1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* 2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon 3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name> 4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without 6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions 7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met: 8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright 9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer. 10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright 11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer in the 12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * documentation and/or other materials provided with the distribution. 13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE. 25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */ 26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef LIBUDEV_NOINIT 28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# warning This version of udev is too old does not support 30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# warning per device initialization checks. 31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# warning As such, dhcpcd will need to depend on the 32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# warning udev-settle service or similar if starting 33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# warning in master mode. 34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <libudev.h> 37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h> 38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <syslog.h> 39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "../common.h" 41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "../dev.h" 42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char udev_name[] = "udev"; 44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct udev *udev; 45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct udev_monitor *monitor; 46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct dev_dhcpcd dhcpcd; 48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanudev_listening(void) 51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return monitor ? 1 : 0; 54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanudev_initialized(const char *ifname) 58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udev_device *device; 60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int r; 61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan device = udev_device_new_from_subsystem_sysname(udev, "net", ifname); 63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (device) { 64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef LIBUDEV_NOINIT 65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = udev_device_get_is_initialized(device); 66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else 67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = 1; 68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev_device_unref(device); 70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = 0; 72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return r; 73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanudev_handle_device(void *ctx) 77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udev_device *device; 79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char *subsystem, *ifname, *action; 80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan device = udev_monitor_receive_device(monitor); 82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (device == NULL) { 83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "libudev: received NULL device"); 84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan subsystem = udev_device_get_subsystem(device); 88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifname = udev_device_get_sysname(device); 89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan action = udev_device_get_action(device); 90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* udev filter documentation says "usually" so double check */ 92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (strcmp(subsystem, "net") == 0) { 93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_DEBUG, "%s: libudev: %s", ifname, action); 94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (strcmp(action, "add") == 0 || strcmp(action, "move") == 0) 95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd.handle_interface(ctx, 1, ifname); 96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (strcmp(action, "remove") == 0) 97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd.handle_interface(ctx, -1, ifname); 98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev_device_unref(device); 101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 1; 102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanudev_stop(void) 106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (monitor) { 109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev_monitor_unref(monitor); 110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan monitor = NULL; 111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udev) { 114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev_unref(udev); 115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev = NULL; 116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanudev_start(void) 121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udev) { 125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "udev: already started"); 126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_DEBUG, "udev: starting"); 130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev = udev_new(); 131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udev == NULL) { 132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "udev_new: %m"); 133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan monitor = udev_monitor_new_from_netlink(udev, "udev"); 136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (monitor == NULL) { 137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "udev_monitor_new_from_netlink: %m"); 138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto bad; 139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef LIBUDEV_NOFILTER 141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udev_monitor_filter_add_match_subsystem_devtype(monitor, 142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "net", NULL) != 0) 143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, 145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "udev_monitor_filter_add_match_subsystem_devtype: %m"); 146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto bad; 147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udev_monitor_enable_receiving(monitor) != 0) { 150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "udev_monitor_enable_receiving: %m"); 151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto bad; 152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fd = udev_monitor_get_fd(monitor); 154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (fd == -1) { 155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan syslog(LOG_ERR, "udev_monitor_get_fd: %m"); 156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto bad; 157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return fd; 159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanbad: 161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udev_stop(); 162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandev_init(struct dev *dev, const struct dev_dhcpcd *dev_dhcpcd) 167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->name = udev_name; 170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->initialized = udev_initialized; 171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->listening = udev_listening; 172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->handle_device = udev_handle_device; 173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->stop = udev_stop; 174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dev->start = udev_start; 175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd = *dev_dhcpcd; 177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 180