11 #include <linux/rtnetlink.h>
15 #define NL_BUFSIZE 8192
18 /* yeah, these callbacks really shouldn't be global */
20 static void *user_data = NULL;
21 static NW_IpChangeCallback on_ip_change = NULL;
22 static NW_LinkChangeCallback on_link_change = NULL;
24 static void netwatch_handle_ifaddrmsg (struct nlmsghdr *nl_msg);
25 static void netwatch_handle_ifinfomsg (struct nlmsghdr *nl_msg);
32 struct sockaddr_nl local;
35 if ((fd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
38 memset (&local, 0, sizeof (local));
39 local.nl_family = AF_NETLINK;
40 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
42 if (bind (fd, (struct sockaddr*) &local, sizeof (local)) < 0)
45 if (fcntl (fd, F_SETFL, O_NONBLOCK))
52 netwatch_queue_inforequest (int fd)
54 char buf[NLMSG_LENGTH (sizeof (struct ifaddrmsg))];
55 struct nlmsghdr *nl_msg;
57 bzero (buf, sizeof(buf));
58 nl_msg = (struct nlmsghdr *) buf;
60 /* For getting interface addresses */
61 nl_msg->nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
62 nl_msg->nlmsg_type = RTM_GETADDR;
63 nl_msg->nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
64 nl_msg->nlmsg_pid = getpid ();
66 return write (fd, nl_msg, nl_msg->nlmsg_len);
71 netwatch_dispatch (int fd)
73 struct nlmsghdr *nl_msg;
78 if ((len = recv (fd, buf, NL_BUFSIZE, 0)) < 0)
80 return (errno == EAGAIN) ? 0 : -1;
83 for (nl_msg = (struct nlmsghdr *) buf;
84 NLMSG_OK (nl_msg, len);
85 nl_msg = NLMSG_NEXT (nl_msg, len))
87 switch (nl_msg->nlmsg_type)
91 netwatch_handle_ifaddrmsg (nl_msg);
95 netwatch_handle_ifinfomsg (nl_msg);
100 fprintf (stderr, "unhandled message (%d)\n",
112 netwatch_register_callbacks (NW_IpChangeCallback ip_cb,
113 NW_LinkChangeCallback link_cb,
116 user_data = userdata;
117 on_ip_change = ip_cb;
118 on_link_change = link_cb;
123 netwatch_handle_ifaddrmsg (struct nlmsghdr *nl_msg)
125 struct ifaddrmsg *if_msg;
126 struct rtattr *attrib;
132 if_msg = (struct ifaddrmsg *) NLMSG_DATA (nl_msg);
134 if (if_msg->ifa_family != AF_INET)
139 len = IFA_PAYLOAD (nl_msg);
140 for (attrib = IFA_RTA (if_msg);
141 RTA_OK (attrib, len);
142 attrib = RTA_NEXT (attrib, len))
144 switch (attrib->rta_type)
147 inet_ntop (AF_INET, RTA_DATA (attrib), address, sizeof (address));
151 label = (char *) RTA_DATA (attrib);
155 /* ignore all other attributes */
160 /* if we got both a label and an IP address */
161 if (on_ip_change && label && address[0] &&
162 (nl_msg->nlmsg_type == RTM_NEWADDR || nl_msg->nlmsg_type == RTM_DELADDR))
164 on_ip_change (if_msg->ifa_index, label, address,
165 nl_msg->nlmsg_type == RTM_NEWADDR, user_data);
173 netwatch_handle_ifinfomsg (struct nlmsghdr *nl_msg)
175 static unsigned long have_state = 0;
176 static unsigned long linkstate = 0;
177 struct ifinfomsg *ifi;
179 ifi = (struct ifinfomsg *) NLMSG_DATA (nl_msg);
181 if (on_link_change && ifi->ifi_index < sizeof (unsigned long) * 8)
183 if (!((1 << ifi->ifi_index) & have_state) ||
184 ((ifi->ifi_flags & IFF_RUNNING) && !((1 << ifi->ifi_index) & linkstate)) ||
185 (!(ifi->ifi_flags & IFF_RUNNING) && ((1 << ifi->ifi_index) & linkstate)))
187 have_state |= (1 << ifi->ifi_index);
188 if (ifi->ifi_flags & IFF_RUNNING)
189 linkstate |= (1 << ifi->ifi_index);
191 linkstate &= ~(1 << ifi->ifi_index);
193 on_link_change (ifi->ifi_index,
194 ifi->ifi_flags & IFF_RUNNING ? 1 : 0,
204 print_ip_change (int link_index,
210 fprintf (stdout, "Link No. %d %s address %s (label %s)\n",
211 link_index, add ? "got" : "lost", ipaddr, label);
215 void print_link_change (int link_index,
219 fprintf (stdout, "Link No. %d is %sconnected\n",
220 link_index, running ? "" : "no longer ");
225 main (int argc, char *argv[])
227 struct pollfd pollfd;
230 netwatch_register_callbacks (print_ip_change, print_link_change, NULL);
232 fd = netwatch_open ();
235 perror ("Error opening netlink socket");
239 netwatch_queue_inforequest (fd);
244 pollfd.events = POLLIN;
247 if (poll (&pollfd, 1, 20000))
248 netwatch_dispatch (fd);