Home | History | Annotate | Download | only in dhcpcd-6.8.2
      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