blob: 6c6b11105797b377877d588ccf04a8b22b5482d7 [file] [log] [blame]
Samuel Tand7ed8512015-08-13 16:11:35 -07001/*
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
39int
40dev_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
48int
49dev_listening(struct dhcpcd_ctx *ctx)
50{
51
52 if (ctx->dev == NULL)
53 return 0;
54 return ctx->dev->listening();
55}
56
57static void
58dev_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
77void
78dev_stop(struct dhcpcd_ctx *ctx)
79{
80
81 dev_stop1(ctx,!(ctx->options & DHCPCD_FORKED));
82}
83
84static int
85dev_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
120static int
121dev_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
154static void
155dev_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
165int
166dev_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}