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