6 #include <sys/socket.h>
8 #include <linux/netlink.h>
9 #include <linux/rtnetlink.h>
12 #include <list/list.h>
13 #include <talloc/talloc.h>
14 #include <waiter/waiter.h>
15 #include <pb-config/pb-config.h>
16 #include <system/system.h>
21 #define PIDFILE_BASE (LOCAL_STATE_DIR "/petitboot/")
23 #define for_each_nlmsg(buf, nlmsg, len) \
24 for (nlmsg = (struct nlmsghdr *)buf; \
25 NLMSG_OK(nlmsg, len) && nlmsg->nlmsg_type != NLMSG_DONE; \
26 nlmsg = NLMSG_NEXT(nlmsg, len))
28 #define for_each_rta(buf, rta, attrlen) \
29 for (rta = (struct rtattr *)(buf); RTA_OK(rta, attrlen); \
30 rta = RTA_NEXT(rta, attrlen))
36 uint8_t hwaddr[HWADDR_SIZE];
40 IFSTATE_UP_WAITING_LINK,
45 struct list_item list;
49 struct list interfaces;
50 struct waiter *waiter;
56 static const struct network_config *find_config_by_hwaddr(
59 const struct config *config;
62 config = config_get();
66 for (i = 0; i < config->n_network_configs; i++) {
67 struct network_config *netconf = config->network_configs[i];
69 if (!memcmp(netconf->hwaddr, hwaddr, HWADDR_SIZE))
76 static struct interface *find_interface_by_ifindex(struct network *network,
79 struct interface *interface;
81 list_for_each_entry(&network->interfaces, interface, list)
82 if (interface->ifindex == ifindex)
88 static int network_init_netlink(struct network *network)
90 struct sockaddr_nl addr;
93 memset(&addr, 0, sizeof(addr));
94 addr.nl_family = AF_NETLINK;
95 addr.nl_groups = RTMGRP_LINK;
97 network->netlink_sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
98 if (network->netlink_sd < 0) {
99 perror("socket(AF_NETLINK)");
103 rc = bind(network->netlink_sd, (struct sockaddr *)&addr, sizeof(addr));
105 perror("bind(sockaddr_nl)");
106 close(network->netlink_sd);
113 static int network_send_link_query(struct network *network)
117 struct nlmsghdr nlmsg;
118 struct rtgenmsg rtmsg;
121 memset(&msg, 0, sizeof(msg));
123 msg.nlmsg.nlmsg_len = sizeof(msg);
124 msg.nlmsg.nlmsg_type = RTM_GETLINK;
125 msg.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
126 msg.nlmsg.nlmsg_seq = 0;
127 msg.nlmsg.nlmsg_pid = 0;
128 msg.rtmsg.rtgen_family = AF_UNSPEC;
130 rc = send(network->netlink_sd, &msg, sizeof(msg), MSG_NOSIGNAL);
131 if (rc != sizeof(msg))
137 static int interface_change(struct network *network,
138 struct interface *interface,
142 const char *statestr = up ? "up" : "down";
143 const char *argv[] = {
152 rc = pb_run_cmd(argv, 1, network->dry_run);
154 pb_log("failed to bring interface %s %s\n", interface->name,
161 static int interface_up(struct network *network,
162 struct interface *interface)
164 return interface_change(network, interface, true);
167 static int interface_down(struct network *network,
168 struct interface *interface)
170 return interface_change(network, interface, false);
173 static void configure_interface_dhcp(struct network *network,
174 struct interface *interface)
177 const char *argv[] = {
178 pb_system_apps.udhcpc,
182 "-i", interface->name,
185 snprintf(pidfile, sizeof(pidfile), "%s/udhcpc-%s.pid",
186 PIDFILE_BASE, interface->name);
188 pb_run_cmd(argv, 0, network->dry_run);
192 static void configure_interface_static(struct network *network,
193 struct interface *interface,
194 const struct network_config *config)
196 const char *addr_argv[] = {
200 config->static_config.address,
205 const char *route_argv[] = {
211 config->static_config.gateway,
217 rc = pb_run_cmd(addr_argv, 1, network->dry_run);
219 pb_log("failed to add address %s to interface %s\n",
220 config->static_config.address,
225 /* we need the interface up before we can route through it */
226 rc = interface_up(network, interface);
230 if (config->static_config.gateway)
231 rc = pb_run_cmd(route_argv, 1, network->dry_run);
234 pb_log("failed to add default route %s on interface %s\n",
235 config->static_config.gateway,
242 static void configure_interface(struct network *network,
243 struct interface *interface, bool up, bool link)
245 const struct network_config *config = NULL;
247 if (interface->state == IFSTATE_IGNORED)
250 /* old interface? check that we're still up and running */
251 if (interface->state == IFSTATE_CONFIGURED) {
253 interface->state = IFSTATE_NEW;
255 interface->state = IFSTATE_UP_WAITING_LINK;
260 /* always up the lookback, no other handling required */
261 if (!strcmp(interface->name, "lo")) {
262 if (interface->state == IFSTATE_NEW)
263 interface_up(network, interface);
264 interface->state = IFSTATE_CONFIGURED;
268 config = find_config_by_hwaddr(interface->hwaddr);
269 if (config && config->ignore) {
270 pb_log("network: ignoring interface %s\n", interface->name);
271 interface->state = IFSTATE_IGNORED;
275 /* if we're in manual config mode, we need an interface configuration */
276 if (network->manual_config && !config) {
277 interface->state = IFSTATE_IGNORED;
278 pb_log("network: skipping %s: manual config mode, "
279 "but no config for this interface\n",
284 /* new interface? bring up to the point so we can detect a link */
285 if (interface->state == IFSTATE_NEW) {
287 interface_up(network, interface);
288 pb_log("network: bringing up interface %s\n",
293 interface->state = IFSTATE_UP_WAITING_LINK;
297 /* no link? wait for a notification */
298 if (interface->state == IFSTATE_UP_WAITING_LINK && !link)
301 pb_log("network: configuring interface %s\n", interface->name);
303 if (!config || config->method == CONFIG_METHOD_DHCP) {
304 configure_interface_dhcp(network, interface);
306 } else if (config->method == CONFIG_METHOD_STATIC) {
307 configure_interface_static(network, interface, config);
311 static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg)
313 bool have_ifaddr, have_ifname;
314 struct interface *interface;
315 struct ifinfomsg *info;
318 char ifname[IFNAMSIZ+1];
322 /* we're only interested in NEWLINK messages */
323 type = nlmsg->nlmsg_type;
324 if (!(type == RTM_NEWLINK || type == RTM_DELLINK))
327 info = NLMSG_DATA(nlmsg);
329 have_ifaddr = have_ifname = false;
331 attrlen = nlmsg->nlmsg_len - sizeof(*info);
333 /* extract the interface name and hardware address attributes */
334 for_each_rta(info + 1, attr, attrlen) {
335 void *data = RTA_DATA(attr);
337 switch (attr->rta_type) {
339 memcpy(ifaddr, data, sizeof(ifaddr));
344 strncpy(ifname, data, IFNAMSIZ);
350 if (!have_ifaddr || !have_ifname)
353 if (type == RTM_DELLINK) {
354 interface = find_interface_by_ifindex(network, info->ifi_index);
357 pb_log("network: interface %s removed\n", interface->name);
358 list_remove(&interface->list);
359 talloc_free(interface);
364 interface = find_interface_by_ifindex(network, info->ifi_index);
366 interface = talloc_zero(network, struct interface);
367 interface->ifindex = info->ifi_index;
368 interface->state = IFSTATE_NEW;
369 memcpy(interface->hwaddr, ifaddr, sizeof(interface->hwaddr));
370 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
373 configure_interface(network, interface,
374 info->ifi_flags & IFF_UP,
375 info->ifi_flags & IFF_LOWER_UP);
380 static int network_netlink_process(void *arg)
382 struct network *network = arg;
383 struct nlmsghdr *nlmsg;
388 rc = recv(network->netlink_sd, buf, sizeof(buf), 0);
390 perror("netlink recv");
396 for_each_nlmsg(buf, nlmsg, len)
397 network_handle_nlmsg(network, nlmsg);
402 struct network *network_init(void *ctx, struct waitset *waitset, bool dry_run)
404 struct network *network;
407 network = talloc(ctx, struct network);
408 list_init(&network->interfaces);
409 network->manual_config = false;
410 network->dry_run = dry_run;
412 rc = network_init_netlink(network);
416 network->waiter = waiter_register_io(waitset, network->netlink_sd,
417 WAIT_IN, network_netlink_process, network);
419 if (!network->waiter)
422 rc = network_send_link_query(network);
429 network_shutdown(network);
434 int network_shutdown(struct network *network)
436 struct interface *interface;
439 waiter_remove(network->waiter);
441 list_for_each_entry(&network->interfaces, interface, list)
442 interface_down(network, interface);
444 close(network->netlink_sd);
445 talloc_free(network);