1 #include <sys/socket.h>
4 #include <linux/rtnetlink.h>
5 #include <linux/sockios.h>
6 #include <linux/if_vlan.h>
11 #include <netlink/msg.h>
12 #include <netlink/attr.h>
13 #include <libubox/uloop.h>
19 static int sock_ioctl
= -1;
20 static struct nl_sock
*sock_rtnl
= NULL
;
21 static struct nl_sock
*sock_rtnl_event
= NULL
;
23 static void handler_rtnl_event(struct uloop_fd
*u
, unsigned int events
);
24 static int cb_rtnl_event(struct nl_msg
*msg
, void *arg
);
25 static struct uloop_fd rtnl_event
= {.cb
= handler_rtnl_event
};
26 static struct nl_cb
*nl_cb_rtnl_event
;
30 sock_ioctl
= socket(AF_LOCAL
, SOCK_DGRAM
, 0);
31 fcntl(sock_ioctl
, F_SETFD
, fcntl(sock_ioctl
, F_GETFD
) | FD_CLOEXEC
);
33 // Prepare socket for routing / address control
34 if ((sock_rtnl
= nl_socket_alloc())) {
35 if (nl_connect(sock_rtnl
, NETLINK_ROUTE
)) {
36 nl_socket_free(sock_rtnl
);
41 // Prepare socket for link events
42 if ((nl_cb_rtnl_event
= nl_cb_alloc(NL_CB_DEFAULT
)))
43 nl_cb_set(nl_cb_rtnl_event
, NL_CB_VALID
, NL_CB_CUSTOM
,
46 if (nl_cb_rtnl_event
&& (sock_rtnl_event
= nl_socket_alloc())) {
47 if (nl_connect(sock_rtnl_event
, NETLINK_ROUTE
)) {
48 nl_socket_free(sock_rtnl_event
);
49 sock_rtnl_event
= NULL
;
51 // Receive network link events form kernel
52 nl_socket_add_membership(sock_rtnl_event
, RTNLGRP_LINK
);
54 // Synthesize initial link messages
55 struct nl_msg
*m
= nlmsg_alloc_simple(RTM_GETLINK
, NLM_F_DUMP
);
56 if (m
&& nlmsg_reserve(m
, sizeof(struct ifinfomsg
), 0)) {
57 nl_send_auto_complete(sock_rtnl_event
, m
);
62 rtnl_event
.fd
= nl_socket_get_fd(sock_rtnl_event
);
64 rtnl_event
.fd
= sock_rtnl_event
->s_fd
; // libnl-tiny hack...
66 uloop_fd_add(&rtnl_event
, ULOOP_READ
| ULOOP_EDGE_TRIGGER
);
69 return -(sock_ioctl
< 0 || !sock_rtnl
);
72 // If socket is ready for reading parse netlink events
73 static void handler_rtnl_event(struct uloop_fd
*u
, unsigned int events
)
75 nl_recvmsgs(sock_rtnl_event
, nl_cb_rtnl_event
);
78 // Evaluate netlink messages
79 static int cb_rtnl_event(struct nl_msg
*msg
, void *arg
)
81 struct nlmsghdr
*nh
= nlmsg_hdr(msg
);
82 struct ifinfomsg
*ifi
= NLMSG_DATA(nh
);
83 struct nlattr
*nla
[__IFLA_MAX
];
85 if (nh
->nlmsg_type
!= RTM_DELLINK
&& nh
->nlmsg_type
!= RTM_NEWLINK
)
88 nlmsg_parse(nh
, sizeof(*ifi
), nla
, __IFLA_MAX
- 1, NULL
);
89 if (!nla
[IFLA_IFNAME
])
92 struct device
*dev
= device_get(RTA_DATA(nla
[IFLA_IFNAME
]), false);
96 dev
->ifindex
= ifi
->ifi_index
;
97 device_set_present(dev
, (nh
->nlmsg_type
== RTM_NEWLINK
));
103 static int system_rtnl_call(struct nl_msg
*msg
)
105 int s
= -(nl_send_auto_complete(sock_rtnl
, msg
)
106 || nl_wait_for_ack(sock_rtnl
));
111 int system_bridge_addbr(struct device
*bridge
)
113 return ioctl(sock_ioctl
, SIOCBRADDBR
, bridge
->ifname
);
116 int system_bridge_delbr(struct device
*bridge
)
118 return ioctl(sock_ioctl
, SIOCBRDELBR
, bridge
->ifname
);
121 static int system_bridge_if(struct device
*bridge
, struct device
*dev
, int cmd
)
124 ifr
.ifr_ifindex
= dev
->ifindex
;
125 strncpy(ifr
.ifr_name
, bridge
->ifname
, sizeof(ifr
.ifr_name
));
126 return ioctl(sock_ioctl
, cmd
, &ifr
);
129 int system_bridge_addif(struct device
*bridge
, struct device
*dev
)
131 return system_bridge_if(bridge
, dev
, SIOCBRADDIF
);
134 int system_bridge_delif(struct device
*bridge
, struct device
*dev
)
136 return system_bridge_if(bridge
, dev
, SIOCBRDELIF
);
139 static int system_vlan(struct device
*dev
, int id
)
141 struct vlan_ioctl_args ifr
= {
142 .cmd
= (id
== 0) ? DEL_VLAN_CMD
: ADD_VLAN_CMD
,
145 strncpy(ifr
.device1
, dev
->ifname
, sizeof(ifr
.device1
));
146 return ioctl(sock_ioctl
, SIOCSIFVLAN
, &ifr
);
149 int system_vlan_add(struct device
*dev
, int id
)
151 return system_vlan(dev
, id
);
154 int system_vlan_del(struct device
*dev
)
156 return system_vlan(dev
, 0);
159 static int system_if_flags(struct device
*dev
, unsigned add
, unsigned rem
)
162 strncpy(ifr
.ifr_name
, dev
->ifname
, sizeof(ifr
.ifr_name
));
163 ioctl(sock_ioctl
, SIOCGIFFLAGS
, &ifr
);
164 ifr
.ifr_flags
|= add
;
165 ifr
.ifr_flags
&= ~rem
;
166 return ioctl(sock_ioctl
, SIOCSIFFLAGS
, &ifr
);
169 static int system_if_resolve(struct device
*dev
)
172 strncpy(ifr
.ifr_name
, dev
->ifname
, sizeof(ifr
.ifr_name
));
173 if (!ioctl(sock_ioctl
, SIOCGIFINDEX
, &ifr
))
174 return ifr
.ifr_ifindex
;
179 int system_if_up(struct device
*dev
)
181 dev
->ifindex
= system_if_resolve(dev
);
182 return system_if_flags(dev
, IFF_UP
, 0);
185 int system_if_down(struct device
*dev
)
187 return system_if_flags(dev
, 0, IFF_UP
);
190 int system_if_check(struct device
*dev
)
192 return -!(system_if_resolve(dev
));
195 static int system_addr(struct device
*dev
, struct device_addr
*addr
, int cmd
)
197 int alen
= ((addr
->flags
& DEVADDR_FAMILY
) == DEVADDR_INET4
) ? 4 : 16;
198 struct ifaddrmsg ifa
= {
199 .ifa_family
= (alen
== 4) ? AF_INET
: AF_INET6
,
200 .ifa_prefixlen
= addr
->mask
,
201 .ifa_index
= dev
->ifindex
,
204 struct nl_msg
*msg
= nlmsg_alloc_simple(cmd
, 0);
208 nlmsg_append(msg
, &ifa
, sizeof(ifa
), 0);
209 nla_put(msg
, IFA_LOCAL
, alen
, &addr
->addr
);
210 return system_rtnl_call(msg
);
213 int system_add_address(struct device
*dev
, struct device_addr
*addr
)
215 return system_addr(dev
, addr
, RTM_NEWADDR
);
218 int system_del_address(struct device
*dev
, struct device_addr
*addr
)
220 return system_addr(dev
, addr
, RTM_DELADDR
);
223 static int system_rt(struct device
*dev
, struct device_route
*route
, int cmd
)
225 int alen
= ((route
->flags
& DEVADDR_FAMILY
) == DEVADDR_INET4
) ? 4 : 16;
229 have_gw
= !!route
->nexthop
.in
.s_addr
;
231 have_gw
= route
->nexthop
.in6
.s6_addr32
[0] ||
232 route
->nexthop
.in6
.s6_addr32
[1] ||
233 route
->nexthop
.in6
.s6_addr32
[2] ||
234 route
->nexthop
.in6
.s6_addr32
[3];
236 unsigned char scope
= (cmd
== RTM_DELROUTE
) ? RT_SCOPE_NOWHERE
:
237 (have_gw
) ? RT_SCOPE_UNIVERSE
: RT_SCOPE_LINK
;
240 .rtm_family
= (alen
== 4) ? AF_INET
: AF_INET6
,
241 .rtm_dst_len
= route
->mask
,
242 .rtm_table
= RT_TABLE_MAIN
,
243 .rtm_protocol
= RTPROT_BOOT
,
245 .rtm_type
= (cmd
== RTM_DELROUTE
) ? 0: RTN_UNICAST
,
248 struct nl_msg
*msg
= nlmsg_alloc_simple(cmd
, 0);
252 nlmsg_append(msg
, &rtm
, sizeof(rtm
), 0);
255 nla_put(msg
, RTA_DST
, alen
, &route
->addr
);
258 nla_put(msg
, RTA_GATEWAY
, alen
, &route
->nexthop
);
260 if (route
->flags
& DEVADDR_DEVICE
)
261 nla_put_u32(msg
, RTA_OIF
, dev
->ifindex
);
263 return system_rtnl_call(msg
);
266 int system_add_route(struct device
*dev
, struct device_route
*route
)
268 return system_rt(dev
, route
, RTM_NEWROUTE
);
271 int system_del_route(struct device
*dev
, struct device_route
*route
)
273 return system_rt(dev
, route
, RTM_DELROUTE
);