device_remove_user(&alias->dep);
alias->dev.hidden = !dev;
if (dev) {
- device_set_ifindex(&alias->dev, dev->ifindex);
+ alias->dev.ifindex = dev->ifindex;
strcpy(alias->dev.ifname, dev->ifname);
device_broadcast_event(&alias->dev, DEV_EVENT_UPDATE_IFNAME);
device_add_user(&alias->dep, dev);
static void alias_device_cb(struct device_user *dep, enum device_event ev)
{
struct alias_device *alias;
- bool new_state = false;
+ bool present = false;
alias = container_of(dep, struct alias_device, dep);
switch (ev) {
case DEV_EVENT_ADD:
- new_state = true;
+ present = true;
case DEV_EVENT_REMOVE:
- device_set_present(&alias->dev, new_state);
- break;
- case DEV_EVENT_LINK_UP:
- new_state = true;
- case DEV_EVENT_LINK_DOWN:
- device_set_link(&alias->dev, new_state);
- break;
- case DEV_EVENT_UPDATE_IFINDEX:
- device_set_ifindex(&alias->dev, dep->dev->ifindex);
+ device_set_present(&alias->dev, present);
break;
default:
device_broadcast_event(&alias->dev, ev);
return 0;
dep->claimed = true;
- D(DEVICE, "Claim %s %s, new active count: %d\n", dev->type->name, dev->ifname, dev->active + 1);
+ D(DEVICE, "Claim %s %s, new refcount: %d\n", dev->type->name, dev->ifname, dev->active + 1);
if (++dev->active != 1)
return 0;
dep->claimed = false;
dev->active--;
- D(DEVICE, "Release %s %s, new active count: %d\n", dev->type->name, dev->ifname, dev->active);
+ D(DEVICE, "Release %s %s, new refcount: %d\n", dev->type->name, dev->ifname, dev->active);
assert(dev->active >= 0);
if (dev->active)
device_refresh_present(dev);
}
-void device_set_link(struct device *dev, bool state)
-{
- if (dev->link_active == state)
- return;
-
- netifd_log_message(L_NOTICE, "%s '%s' link is %s\n", dev->type->name, dev->ifname, state ? "up" : "down" );
-
- dev->link_active = state;
- device_broadcast_event(dev, state ? DEV_EVENT_LINK_UP : DEV_EVENT_LINK_DOWN);
-}
-
-void device_set_ifindex(struct device *dev, int ifindex)
-{
- if (dev->ifindex == ifindex)
- return;
-
- dev->ifindex = ifindex;
- device_broadcast_event(dev, DEV_EVENT_UPDATE_IFINDEX);
-}
-
static int device_refcount(struct device *dev)
{
struct list_head *list;
dep->cb(dep, DEV_EVENT_ADD);
if (dev->active)
dep->cb(dep, DEV_EVENT_UP);
-
- if (dev->link_active)
- dep->cb(dep, DEV_EVENT_LINK_UP);
}
}
return;
blobmsg_add_u8(b, "up", !!dev->active);
- blobmsg_add_u8(b, "carrier", !!dev->link_active);
-
if (dev->type->dump_info)
dev->type->dump_info(dev, b);
else
struct event_socket {
struct uloop_fd uloop;
struct nl_sock *sock;
+ struct nl_cb *cb;
};
static int sock_ioctl = -1;
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);
+ nl_recvmsgs(ev->sock, ev->cb);
}
static struct nl_sock *
ev->uloop.fd = nl_socket_get_fd(ev->sock);
ev->uloop.cb = cb;
- if (uloop_fd_add(&ev->uloop, ULOOP_READ))
- return false;
-
+ uloop_fd_add(&ev->uloop, ULOOP_READ | ULOOP_EDGE_TRIGGER);
return true;
}
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))
+ // Prepare socket for link events
+ ev->cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!ev->cb)
return false;
- // Install the valid custom callback handler
- nl_socket_modify_cb(ev->sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
+ nl_cb_set(ev->cb, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
- // Disable sequence number checking on event sockets
- 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))
- return false;
-
- return true;
+ return create_raw_event_socket(ev, protocol, 0, handler_nl_event);
}
int system_init(void)
static struct event_socket hotplug_event;
sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
- system_fd_set_cloexec(sock_ioctl);
+ fcntl(sock_ioctl, F_SETFD, fcntl(sock_ioctl, F_GETFD) | FD_CLOEXEC);
// Prepare socket for routing / address control
sock_rtnl = create_socket(NETLINK_ROUTE, 0);
system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
}
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP 0x10000
-#endif
-
// Evaluate netlink messages
static int cb_rtnl_event(struct nl_msg *msg, void *arg)
{
struct ifinfomsg *ifi = NLMSG_DATA(nh);
struct nlattr *nla[__IFLA_MAX];
- if (nh->nlmsg_type != RTM_NEWLINK)
+ if (nh->nlmsg_type != RTM_DELLINK && nh->nlmsg_type != RTM_NEWLINK)
goto out;
nlmsg_parse(nh, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
if (!nla[IFLA_IFNAME])
goto out;
- struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
+ struct device *dev = device_get(RTA_DATA(nla[IFLA_IFNAME]), false);
if (!dev)
goto out;
- device_set_ifindex(dev, ifi->ifi_index);
- device_set_link(dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
+ dev->ifindex = ifi->ifi_index;
+ /* TODO: parse link status */
out:
return 0;
if (dev->external)
return;
- device_set_ifindex(dev, system_if_resolve(dev));
+ dev->ifindex = system_if_resolve(dev);
if (!dev->ifindex)
return;
{
system_if_get_settings(dev, &dev->orig_settings);
system_if_apply_settings(dev, &dev->settings);
- device_set_ifindex(dev, system_if_resolve(dev));
+ dev->ifindex = system_if_resolve(dev);
return system_if_flags(dev->ifname, IFF_UP, 0);
}
return ret;
}
-struct if_check_data {
- struct device *dev;
- int pending;
- int ret;
-};
-
-static int cb_if_check_valid(struct nl_msg *msg, void *arg)
-{
- struct nlmsghdr *nh = nlmsg_hdr(msg);
- struct ifinfomsg *ifi = NLMSG_DATA(nh);
- struct if_check_data *chk = (struct if_check_data *)arg;
-
- if (nh->nlmsg_type != RTM_NEWLINK)
- return NL_SKIP;
-
- device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false);
- device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
-
- return NL_OK;
-}
-
-static int cb_if_check_ack(struct nl_msg *msg, void *arg)
-{
- struct if_check_data *chk = (struct if_check_data *)arg;
- chk->pending = 0;
- return NL_STOP;
-}
-
-static int cb_if_check_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
-{
- struct if_check_data *chk = (struct if_check_data *)arg;
-
- device_set_present(chk->dev, false);
- device_set_link(chk->dev, false);
- chk->pending = err->error;
-
- return NL_STOP;
-}
-
int system_if_check(struct device *dev)
{
- struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
- struct nl_msg *msg;
- struct ifinfomsg ifi = {
- .ifi_family = AF_UNSPEC,
- .ifi_index = 0,
- };
- struct if_check_data chk = {
- .dev = dev,
- .pending = 1,
- };
- int ret = 1;
-
- msg = nlmsg_alloc_simple(RTM_GETLINK, 0);
- if (!msg || nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
- nla_put_string(msg, IFLA_IFNAME, dev->ifname))
- goto out;
-
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_if_check_valid, &chk);
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
- nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
-
- nl_send_auto_complete(sock_rtnl, msg);
- while (chk.pending > 0)
- nl_recvmsgs(sock_rtnl, cb);
-
- nlmsg_free(msg);
- ret = chk.pending;
-
-out:
- nl_cb_put(cb);
- return ret;
+ device_set_present(dev, (system_if_resolve(dev) > 0));
+ return 0;
}
struct device *
char buf[64], *s;
void *c;
int dir_fd;
+ uint64_t val = 0;
snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname);
dir_fd = open(buf, O_DIRECTORY);
+ if (read_uint64_file(dir_fd, "carrier", &val))
+ blobmsg_add_u8(b, "link", !!val);
+
memset(&ecmd, 0, sizeof(ecmd));
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, dev->ifname);