1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon
3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without
6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions
7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met:
8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright
9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer.
10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright
11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer in the
12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    documentation and/or other materials provided with the distribution.
13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE.
25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <dirent.h>
28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <dlfcn.h>
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdio.h>
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define _INDEV
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dev.h"
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h"
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h"
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev == NULL)
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 1;
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->dev->initialized(ifname);
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_listening(struct dhcpcd_ctx *ctx)
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev == NULL)
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->dev->listening();
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_stop1(struct dhcpcd_ctx *ctx, int stop)
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev) {
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (stop)
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_DEBUG,
64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "dev: unloaded %s", ctx->dev->name);
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(ctx->eloop, ctx->dev_fd, 0);
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->dev->stop();
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(ctx->dev);
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->dev = NULL;
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->dev_fd = -1;
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev_handle) {
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dlclose(ctx->dev_handle);
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->dev_handle = NULL;
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_stop(struct dhcpcd_ctx *ctx)
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dev_stop1(ctx,!(ctx->options & DHCPCD_FORKED));
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_start2(struct dhcpcd_ctx *ctx, const char *name)
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char file[PATH_MAX];
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	void *h;
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	void (*fptr)(struct dev *, const struct dev_dhcpcd *);
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dev_dhcpcd dev_dhcpcd;
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(file, sizeof(file), DEVDIR "/%s", name);
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	h = dlopen(file, RTLD_LAZY);
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (h == NULL) {
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "dlopen: %s", dlerror());
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fptr = (void (*)(struct dev *, const struct dev_dhcpcd *))
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    dlsym(h, "dev_init");
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fptr == NULL) {
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "dlsym: %s", dlerror());
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dlclose(h);
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->dev = calloc(1, sizeof(*ctx->dev));
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dev_dhcpcd.handle_interface = &dhcpcd_handleinterface;
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fptr(ctx->dev, &dev_dhcpcd);
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev->start  == NULL || (r = ctx->dev->start()) == -1) {
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(ctx->dev);
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->dev = NULL;
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dlclose(h);
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ctx, LOG_INFO, "dev: loaded %s", ctx->dev->name);
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->dev_handle = h;
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_start1(struct dhcpcd_ctx *ctx)
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	DIR *dp;
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dirent *d;
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev) {
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "dev: already started %s", ctx->dev->name);
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev_load)
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return dev_start2(ctx, ctx->dev_load);
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dp = opendir(DEVDIR);
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dp == NULL) {
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_DEBUG, "dev: %s: %m", DEVDIR);
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = 0;
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((d = readdir(dp))) {
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (d->d_name[0] == '.')
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = dev_start2(ctx, d->d_name);
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r != -1)
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	closedir(dp);
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_handle_data(void *arg)
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcpcd_ctx *ctx;
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx = arg;
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev->handle_device(arg) == -1) {
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* XXX: an error occured. should we restart dev? */
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_start(struct dhcpcd_ctx *ctx)
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev_fd != -1) {
170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "%s: already started on fd %d", __func__,
171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ctx->dev_fd);
172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return ctx->dev_fd;
173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->dev_fd = dev_start1(ctx);
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->dev_fd != -1) {
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (eloop_event_add(ctx->eloop,
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ctx->dev_fd, dev_handle_data, ctx, NULL, NULL) == -1)
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_ERR,
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: eloop_event_add: %m", __func__);
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dev_stop1(ctx, 1);
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->dev_fd;
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
189