1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon
3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved
5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without
7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions
8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met:
9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright
10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer.
11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright
12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer in the
13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    documentation and/or other materials provided with the distribution.
14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE.
26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/socket.h>
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/stat.h>
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/uio.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/un.h>
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h>
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h>
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdio.h>
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <time.h>
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h>
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h"
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h"
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "control.h"
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h"
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef SUN_LEN
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define SUN_LEN(su) \
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan            (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue_purge(struct dhcpcd_ctx *ctx, char *data)
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int found;
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_list *fp;
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_data *fpd;
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If no other fd queue has the same data, free it */
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	found = 0;
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(fp, &ctx->control_fds, next) {
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_FOREACH(fpd, &fp->queue, next) {
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (fpd->data == data) {
64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				found = 1;
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!found)
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(data);
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue_free(struct fd_list *fd)
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_data *fdp;
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((fdp = TAILQ_FIRST(&fd->queue))) {
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&fd->queue, fdp, next);
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (fdp->freeit)
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			control_queue_purge(fd->ctx, fdp->data);
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(fdp);
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&fd->free_queue, fdp, next);
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(fdp);
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_delete(struct fd_list *fd)
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_event_delete(fd->ctx->eloop, fd->fd, 0);
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(fd->fd);
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	control_queue_free(fd);
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(fd);
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle_data(void *arg)
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_list *fd = arg;
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[1024], *e, *p, *argvp[255], **ap, *a;
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes;
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int argc;
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bytes == -1 || bytes == 0) {
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Control was closed or there was an error.
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * Remove it from our list. */
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		control_delete(fd);
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	buffer[bytes] = '\0';
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = buffer;
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = buffer + bytes;
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Each command is \n terminated
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * Each argument is NULL separated */
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (p < e) {
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		argc = 0;
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ap = argvp;
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (p < e) {
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			argc++;
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = ENOBUFS;
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return;
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			a = *ap++ = p;
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = strlen(p);
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += len + 1;
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (len && a[len - 1] == '\n') {
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				a[len - 1] = '\0';
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*ap = NULL;
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(fd->ctx, LOG_ERR,
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcpcd_handleargs: %m", __func__);
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (errno != EINTR && errno != EAGAIN) {
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				control_delete(fd);
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return;
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_un run;
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	socklen_t len;
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_list *l;
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd, flags;
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = sizeof(run);
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return;
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return;
174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	l = malloc(sizeof(*l));
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (l) {
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l->ctx = ctx;
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l->fd = fd;
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l->flags = fd_flags;
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&l->queue);
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&l->free_queue);
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_add(ctx->eloop, l->fd,
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    control_handle_data, l, NULL, NULL);
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle(void *arg)
191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcpcd_ctx *ctx = arg;
193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	control_handle1(ctx, ctx->control_fd, 0);
195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle_unpriv(void *arg)
199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcpcd_ctx *ctx = arg;
201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanmake_sock(struct sockaddr_un *sa, const char *ifname, int unpriv)
207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC
211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fd = socket(AF_UNIX,
212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int flags;
216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(sa, 0, sizeof(*sa));
233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sa->sun_family = AF_UNIX;
234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (unpriv)
235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifname ? "-" : "", ifname ? ifname : "");
239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return fd;
241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_un sa;
250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	socklen_t len;
252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1)
254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = (socklen_t)SUN_LEN(&sa);
256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unlink(sa.sun_path);
257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    chmod(sa.sun_path, fmode) == -1 ||
259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (ctx->control_group &&
260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    listen(fd, sizeof(ctx->control_fds)) == -1)
262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		unlink(sa.sun_path);
265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fmode & S_UNPRIV) != S_UNPRIV)
269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		strlcpy(ctx->control_sock, sa.sun_path,
270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    sizeof(ctx->control_sock));
271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return fd;
272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_start(struct dhcpcd_ctx *ctx, const char *ifname)
276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1)
280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->control_fd = fd;
283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_event_add(ctx->eloop, fd, control_handle, ctx, NULL, NULL);
284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){
286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We must be in master mode, so create an unpriviledged socket
287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * to allow normal users to learn the status of dhcpcd. */
288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->control_unpriv_fd = fd;
289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_add(ctx->eloop, fd, control_handle_unpriv,
290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ctx, NULL, NULL);
291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->control_fd;
293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_stop(struct dhcpcd_ctx *ctx)
297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int retval = 0;
299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_list *l;
300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->options & DHCPCD_FORKED)
302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto freeit;
303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->control_fd == -1)
305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_event_delete(ctx->eloop, ctx->control_fd, 0);
307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(ctx->control_fd);
308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->control_fd = -1;
309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (unlink(ctx->control_sock) == -1)
310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		retval = -1;
311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->control_unpriv_fd != -1) {
313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd, 0);
314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->control_unpriv_fd);
315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->control_unpriv_fd = -1;
316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (unlink(UNPRIVSOCKET) == -1)
317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			retval = -1;
318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanfreeit:
321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((l = TAILQ_FIRST(&ctx->control_fds))) {
322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->control_fds, l, next);
323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(ctx->eloop, l->fd, 0);
324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(l->fd);
325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		control_queue_free(l);
326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(l);
327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return retval;
330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_open(struct dhcpcd_ctx *ctx, const char *ifname)
334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_un sa;
336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	socklen_t len;
337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ctx->control_fd = make_sock(&sa, ifname, 0)) == -1)
339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = (socklen_t)SUN_LEN(&sa);
341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (connect(ctx->control_fd, (struct sockaddr *)&sa, len) == -1) {
342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->control_fd);
343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->control_fd = -1;
344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[1024];
353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int i;
354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len, l;
355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (argc > 255) {
357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = 0;
361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; i < argc; i++) {
362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = strlen(argv[i]) + 1;
363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (len + l > sizeof(buffer)) {
364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ENOBUFS;
365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(buffer + len, argv[i], l);
368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len += l;
369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return write(ctx->control_fd, buffer, len);
371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_writeone(void *arg)
375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_list *fd;
377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct iovec iov[2];
378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_data *data;
379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fd = arg;
381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	data = TAILQ_FIRST(&fd->queue);
382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov[0].iov_base = &data->data_len;
383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov[0].iov_len = sizeof(size_t);
384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov[1].iov_base = data->data;
385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov[1].iov_len = data->data_len;
386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (writev(fd->fd, iov, 2) == -1) {
387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(fd->ctx, LOG_ERR,
388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: writev fd %d: %m", __func__, fd->fd);
389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (errno != EINTR && errno != EAGAIN)
390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			control_delete(fd);
391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_REMOVE(&fd->queue, data, next);
395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (data->freeit)
396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		control_queue_purge(fd->ctx, data->data);
397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	data->data = NULL; /* safety */
398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	data->data_len = 0;
399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (TAILQ_FIRST(&fd->queue) == NULL)
402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(fd->ctx->eloop, fd->fd, 1);
403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit)
407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct fd_data *d;
409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t n;
410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	d = TAILQ_FIRST(&fd->free_queue);
412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (d) {
413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&fd->free_queue, d, next);
414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = 0;
416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_FOREACH(d, &fd->queue, next) {
417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (++n == CONTROL_QUEUE_MAX) {
418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = ENOBUFS;
419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return -1;
420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		d = malloc(sizeof(*d));
423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (d == NULL)
424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	d->data = data;
427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	d->data_len = data_len;
428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	d->freeit = fit;
429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INSERT_TAIL(&fd->queue, d, next);
430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_event_add(fd->ctx->eloop, fd->fd,
431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NULL, NULL, control_writeone, fd);
432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_close(struct dhcpcd_ctx *ctx)
437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->control_fd != -1) {
440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->control_fd);
441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->control_fd = -1;
442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
444