11 #include <linux/rtnetlink.h>
16 #define NL_BUFSIZE 8192
19 /* yeah, these callbacks really shouldn't be global */
21 static void *user_data = NULL;
22 static NW_IpChangeCallback on_ip_change = NULL;
23 static NW_LinkChangeCallback on_link_change = NULL;
25 static void netwatch_handle_ifaddrmsg (struct nlmsghdr *nl_msg);
26 static void netwatch_handle_ifinfomsg (struct nlmsghdr *nl_msg);
33 struct sockaddr_nl local;
36 if ((fd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
39 memset (&local, 0, sizeof (local));
40 local.nl_family = AF_NETLINK;
41 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
43 if (bind (fd, (struct sockaddr*) &local, sizeof (local)) < 0)
46 if (fcntl (fd, F_SETFL, O_NONBLOCK))
53 netwatch_queue_inforequest (int fd)
55 char buf[NLMSG_LENGTH (sizeof (struct ifaddrmsg))];
56 struct nlmsghdr *nl_msg;
58 bzero (buf, sizeof(buf));
59 nl_msg = (struct nlmsghdr *) buf;
61 /* For getting interface addresses */
62 nl_msg->nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
63 nl_msg->nlmsg_type = RTM_GETADDR;
64 nl_msg->nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
65 nl_msg->nlmsg_pid = getpid ();
67 return write (fd, nl_msg, nl_msg->nlmsg_len);
72 netwatch_dispatch (int fd)
74 struct nlmsghdr *nl_msg;
79 if ((len = recv (fd, buf, NL_BUFSIZE, 0)) < 0)
81 return (errno == EAGAIN) ? 0 : -1;
84 for (nl_msg = (struct nlmsghdr *) buf;
85 NLMSG_OK (nl_msg, (unsigned int) len);
86 nl_msg = NLMSG_NEXT (nl_msg, len))
88 switch (nl_msg->nlmsg_type)
92 netwatch_handle_ifaddrmsg (nl_msg);
96 netwatch_handle_ifinfomsg (nl_msg);
101 fprintf (stderr, "unhandled message (%d)\n",
113 netwatch_register_callbacks (NW_IpChangeCallback ip_cb,
114 NW_LinkChangeCallback link_cb,
117 user_data = userdata;
118 on_ip_change = ip_cb;
119 on_link_change = link_cb;
124 netwatch_handle_ifaddrmsg (struct nlmsghdr *nl_msg)
126 struct ifaddrmsg *if_msg;
127 struct rtattr *attrib;
133 if_msg = (struct ifaddrmsg *) NLMSG_DATA (nl_msg);
135 if (if_msg->ifa_family != AF_INET)
140 len = IFA_PAYLOAD (nl_msg);
141 for (attrib = IFA_RTA (if_msg);
142 RTA_OK (attrib, len);
143 attrib = RTA_NEXT (attrib, len))
145 switch (attrib->rta_type)
148 inet_ntop (AF_INET, RTA_DATA (attrib), address, sizeof (address));
152 label = (char *) RTA_DATA (attrib);
156 /* ignore all other attributes */
161 /* if we got both a label and an IP address */
162 if (on_ip_change && label && address[0] &&
163 (nl_msg->nlmsg_type == RTM_NEWADDR || nl_msg->nlmsg_type == RTM_DELADDR))
165 on_ip_change (if_msg->ifa_index, label, address,
166 nl_msg->nlmsg_type == RTM_NEWADDR, user_data);
174 netwatch_handle_ifinfomsg (struct nlmsghdr *nl_msg)
176 static unsigned long have_state = 0;
177 static unsigned long linkstate = 0;
178 struct ifinfomsg *ifi;
180 ifi = (struct ifinfomsg *) NLMSG_DATA (nl_msg);
182 if (on_link_change && ((unsigned int)ifi->ifi_index < sizeof (unsigned long) * 8))
184 if (!((1 << ifi->ifi_index) & have_state) ||
185 ((ifi->ifi_flags & IFF_RUNNING) && !((1 << ifi->ifi_index) & linkstate)) ||
186 (!(ifi->ifi_flags & IFF_RUNNING) && ((1 << ifi->ifi_index) & linkstate)))
188 have_state |= (1 << ifi->ifi_index);
189 if (ifi->ifi_flags & IFF_RUNNING)
190 linkstate |= (1 << ifi->ifi_index);
192 linkstate &= ~(1 << ifi->ifi_index);
194 on_link_change (ifi->ifi_index,
195 ifi->ifi_flags & IFF_RUNNING ? 1 : 0,
205 print_ip_change (int link_index,
209 void *UNUSED(user_data))
211 fprintf (stdout, "Link No. %d %s address %s (label %s)\n",
212 link_index, add ? "got" : "lost", ipaddr, label);
216 void print_link_change (int link_index,
218 void *UNUSED(user_data))
220 fprintf (stdout, "Link No. %d is %sconnected\n",
221 link_index, running ? "" : "no longer ");
226 main (int UNUSED(argc), char **UNUSED(argv))
228 struct pollfd pollfd;
231 netwatch_register_callbacks (print_ip_change, print_link_change, NULL);
233 fd = netwatch_open ();
236 perror ("Error opening netlink socket");
240 netwatch_queue_inforequest (fd);
245 pollfd.events = POLLIN;
248 if (poll (&pollfd, 1, 20000))
249 netwatch_dispatch (fd);