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