X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=system-linux.c;h=7cec649fdae76f5dff94d1695d65454401956281;hp=714729f9dc5110c00639e7b224c4b590ff668d2b;hb=ae3c6891596950ac7c2d5c45a078ab51efc53d99;hpb=c439b52400978dd3799c66e1f632ee68d2c7c9eb diff --git a/system-linux.c b/system-linux.c index 714729f..7cec649 100644 --- a/system-linux.c +++ b/system-linux.c @@ -58,6 +58,7 @@ struct event_socket { struct uloop_fd uloop; struct nl_sock *sock; + int bufsize; }; static int sock_ioctl = -1; @@ -72,7 +73,38 @@ static void handler_nl_event(struct uloop_fd *u, unsigned int events) { struct event_socket *ev = container_of(u, struct event_socket, uloop); - nl_recvmsgs_default(ev->sock); + int err; + socklen_t errlen = sizeof(err); + + if (!u->error) { + nl_recvmsgs_default(ev->sock); + return; + } + + if (getsockopt(u->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen)) + goto abort; + + switch(err) { + case ENOBUFS: + // Increase rx buffer size on netlink socket + ev->bufsize *= 2; + if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0)) + goto abort; + + // Request full dump since some info got dropped + struct rtgenmsg msg = { .rtgen_family = AF_UNSPEC }; + nl_send_simple(ev->sock, RTM_GETLINK, NLM_F_DUMP, &msg, sizeof(msg)); + break; + + default: + goto abort; + } + u->error = false; + return; + +abort: + uloop_fd_delete(&ev->uloop); + return; } static struct nl_sock * @@ -95,7 +127,7 @@ create_socket(int protocol, int groups) static bool create_raw_event_socket(struct event_socket *ev, int protocol, int groups, - uloop_fd_handler cb) + uloop_fd_handler cb, int flags) { ev->sock = create_socket(protocol, groups); if (!ev->sock) @@ -103,7 +135,7 @@ create_raw_event_socket(struct event_socket *ev, int protocol, int groups, ev->uloop.fd = nl_socket_get_fd(ev->sock); ev->uloop.cb = cb; - if (uloop_fd_add(&ev->uloop, ULOOP_READ)) + if (uloop_fd_add(&ev->uloop, ULOOP_READ|flags)) return false; return true; @@ -113,7 +145,7 @@ static bool create_event_socket(struct event_socket *ev, int protocol, int (*cb)(struct nl_msg *msg, void *arg)) { - if (!create_raw_event_socket(ev, protocol, 0, handler_nl_event)) + if (!create_raw_event_socket(ev, protocol, 0, handler_nl_event, ULOOP_ERROR_CB)) return false; // Install the valid custom callback handler @@ -123,7 +155,8 @@ create_event_socket(struct event_socket *ev, int protocol, nl_socket_disable_seq_check(ev->sock); // Increase rx buffer size to 65K on event sockets - if (nl_socket_set_buffer_size(ev->sock, 65535, 0)) + ev->bufsize = 65535; + if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0)) return false; return true; @@ -146,7 +179,7 @@ int system_init(void) return -1; if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1, - handle_hotplug_event)) + handle_hotplug_event, 0)) return -1; // Receive network link events form kernel @@ -163,7 +196,7 @@ static void system_set_sysctl(const char *path, const char *val) if (fd < 0) return; - write(fd, val, strlen(val)); + if (write(fd, val, strlen(val))) {} close(fd); } @@ -467,8 +500,9 @@ static int cb_clear_event(struct nl_msg *msg, void *arg) hdr->nlmsg_type = type; hdr->nlmsg_flags = NLM_F_REQUEST; - if (!nl_send_auto_complete(sock_rtnl, clr->msg)) - nl_wait_for_ack(sock_rtnl); + nl_socket_disable_auto_ack(sock_rtnl); + nl_send_auto_complete(sock_rtnl, clr->msg); + nl_socket_enable_auto_ack(sock_rtnl); return NL_SKIP; } @@ -764,23 +798,26 @@ system_if_get_settings(struct device *dev, struct device_settings *s) } void -system_if_apply_settings(struct device *dev, struct device_settings *s) +system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned int apply_mask) { struct ifreq ifr; + if (!apply_mask) + return; + memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name)); - if (s->flags & DEV_OPT_MTU) { + if (s->flags & DEV_OPT_MTU & apply_mask) { ifr.ifr_mtu = s->mtu; if (ioctl(sock_ioctl, SIOCSIFMTU, &ifr) < 0) s->flags &= ~DEV_OPT_MTU; } - if (s->flags & DEV_OPT_TXQUEUELEN) { + if (s->flags & DEV_OPT_TXQUEUELEN & apply_mask) { ifr.ifr_qlen = s->txqueuelen; if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0) s->flags &= ~DEV_OPT_TXQUEUELEN; } - if ((s->flags & DEV_OPT_MACADDR) && !dev->external) { + if ((s->flags & DEV_OPT_MACADDR & apply_mask) && !dev->external) { ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr)); if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0) @@ -791,7 +828,7 @@ system_if_apply_settings(struct device *dev, struct device_settings *s) int system_if_up(struct device *dev) { system_if_get_settings(dev, &dev->orig_settings); - system_if_apply_settings(dev, &dev->settings); + system_if_apply_settings(dev, &dev->settings, dev->settings.flags); device_set_ifindex(dev, system_if_resolve(dev)); return system_if_flags(dev->ifname, IFF_UP, 0); } @@ -800,7 +837,7 @@ int system_if_down(struct device *dev) { int ret = system_if_flags(dev->ifname, 0, IFF_UP); dev->orig_settings.flags &= dev->settings.flags; - system_if_apply_settings(dev, &dev->orig_settings); + system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags); return ret; } @@ -1142,6 +1179,7 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) struct rtmsg rtm = { .rtm_family = (alen == 4) ? AF_INET : AF_INET6, .rtm_dst_len = route->mask, + .rtm_src_len = route->sourcemask, .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC, .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC, .rtm_scope = scope, @@ -1167,6 +1205,9 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) if (route->mask) nla_put(msg, RTA_DST, alen, &route->addr); + if (route->sourcemask) + nla_put(msg, RTA_SRC, alen, &route->source); + if (route->metric > 0) nla_put_u32(msg, RTA_PRIORITY, route->metric); @@ -1205,7 +1246,7 @@ int system_flush_routes(void) if (fd < 0) continue; - write(fd, "-1", 2); + if (write(fd, "-1", 2)) {} close(fd); } return 0;