1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2015 Roy Marples <roy (at) 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 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 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 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 78 dev_stop(struct dhcpcd_ctx *ctx) 79 { 80 81 dev_stop1(ctx,!(ctx->options & DHCPCD_FORKED)); 82 } 83 84 static int 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 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 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 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