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 #ifdef LIBUDEV_NOINIT 28 # define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 29 # warning This version of udev is too old does not support 30 # warning per device initialization checks. 31 # warning As such, dhcpcd will need to depend on the 32 # warning udev-settle service or similar if starting 33 # warning in master mode. 34 #endif 35 36 #include <libudev.h> 37 #include <string.h> 38 #include <syslog.h> 39 40 #include "../common.h" 41 #include "../dev.h" 42 43 static const char udev_name[] = "udev"; 44 static struct udev *udev; 45 static struct udev_monitor *monitor; 46 47 static struct dev_dhcpcd dhcpcd; 48 49 static int 50 udev_listening(void) 51 { 52 53 return monitor ? 1 : 0; 54 } 55 56 static int 57 udev_initialized(const char *ifname) 58 { 59 struct udev_device *device; 60 int r; 61 62 device = udev_device_new_from_subsystem_sysname(udev, "net", ifname); 63 if (device) { 64 #ifndef LIBUDEV_NOINIT 65 r = udev_device_get_is_initialized(device); 66 #else 67 r = 1; 68 #endif 69 udev_device_unref(device); 70 } else 71 r = 0; 72 return r; 73 } 74 75 static int 76 udev_handle_device(void *ctx) 77 { 78 struct udev_device *device; 79 const char *subsystem, *ifname, *action; 80 81 device = udev_monitor_receive_device(monitor); 82 if (device == NULL) { 83 syslog(LOG_ERR, "libudev: received NULL device"); 84 return -1; 85 } 86 87 subsystem = udev_device_get_subsystem(device); 88 ifname = udev_device_get_sysname(device); 89 action = udev_device_get_action(device); 90 91 /* udev filter documentation says "usually" so double check */ 92 if (strcmp(subsystem, "net") == 0) { 93 syslog(LOG_DEBUG, "%s: libudev: %s", ifname, action); 94 if (strcmp(action, "add") == 0 || strcmp(action, "move") == 0) 95 dhcpcd.handle_interface(ctx, 1, ifname); 96 else if (strcmp(action, "remove") == 0) 97 dhcpcd.handle_interface(ctx, -1, ifname); 98 } 99 100 udev_device_unref(device); 101 return 1; 102 } 103 104 static void 105 udev_stop(void) 106 { 107 108 if (monitor) { 109 udev_monitor_unref(monitor); 110 monitor = NULL; 111 } 112 113 if (udev) { 114 udev_unref(udev); 115 udev = NULL; 116 } 117 } 118 119 static int 120 udev_start(void) 121 { 122 int fd; 123 124 if (udev) { 125 syslog(LOG_ERR, "udev: already started"); 126 return -1; 127 } 128 129 syslog(LOG_DEBUG, "udev: starting"); 130 udev = udev_new(); 131 if (udev == NULL) { 132 syslog(LOG_ERR, "udev_new: %m"); 133 return -1; 134 } 135 monitor = udev_monitor_new_from_netlink(udev, "udev"); 136 if (monitor == NULL) { 137 syslog(LOG_ERR, "udev_monitor_new_from_netlink: %m"); 138 goto bad; 139 } 140 #ifndef LIBUDEV_NOFILTER 141 if (udev_monitor_filter_add_match_subsystem_devtype(monitor, 142 "net", NULL) != 0) 143 { 144 syslog(LOG_ERR, 145 "udev_monitor_filter_add_match_subsystem_devtype: %m"); 146 goto bad; 147 } 148 #endif 149 if (udev_monitor_enable_receiving(monitor) != 0) { 150 syslog(LOG_ERR, "udev_monitor_enable_receiving: %m"); 151 goto bad; 152 } 153 fd = udev_monitor_get_fd(monitor); 154 if (fd == -1) { 155 syslog(LOG_ERR, "udev_monitor_get_fd: %m"); 156 goto bad; 157 } 158 return fd; 159 160 bad: 161 udev_stop(); 162 return -1; 163 } 164 165 int 166 dev_init(struct dev *dev, const struct dev_dhcpcd *dev_dhcpcd) 167 { 168 169 dev->name = udev_name; 170 dev->initialized = udev_initialized; 171 dev->listening = udev_listening; 172 dev->handle_device = udev_handle_device; 173 dev->stop = udev_stop; 174 dev->start = udev_start; 175 176 dhcpcd = *dev_dhcpcd; 177 178 return 0; 179 } 180