IE chosen channel on Lb interface decoded incorrectly
[jelmer/wireshark.git] / iface_monitor.c
1 /* iface_monitor.c
2  * interface monitor by Pontus Fuchs <pontus.fuchs@gmail.com>
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 #include "config.h"
23
24 #ifdef HAVE_LIBPCAP
25
26 #include "iface_monitor.h"
27
28 #if defined(HAVE_LIBNL)
29
30 /*
31  * Linux with libnl.
32  */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <errno.h>
37
38 #include <netlink/msg.h>
39 #include <netlink/attr.h>
40 #include <netlink/route/link.h>
41
42 #ifndef IFF_UP
43 /*
44  * Apparently, some versions of libnl drag in headers that define IFF_UP
45  * and others don't.  Include <net/if.h> iff IFF_UP isn't already defined,
46  * so that if <linux/if.h> has been included by some or all of the
47  * netlink headers, we don't include <net/if.h> and get a bunch of
48  * complaints about various structures being redefined.
49  */
50 #include <net/if.h>
51 #endif
52
53 /* libnl 1.x compatibility code */
54 #ifdef HAVE_LIBNL1
55 #define nl_sock nl_handle
56 #define nl_socket_disable_seq_check nl_disable_sequence_check
57
58 static inline struct nl_handle *nl_socket_alloc(void)
59 {
60     return nl_handle_alloc();
61 }
62
63 static inline void nl_socket_free(struct nl_sock *h)
64 {
65     nl_handle_destroy(h);
66 }
67 #endif /* HAVE_LIBNL1 */
68
69 static struct nl_sock *iface_mon_sock;
70
71 static void
72 iface_mon_handler2(struct nl_object *obj, void *arg)
73 {
74     struct rtnl_link *filter;
75     struct rtnl_link *link_obj;
76     int flags, up;
77     char *ifname;
78     iface_mon_cb cb = (iface_mon_cb)arg;
79
80     filter = rtnl_link_alloc();
81     if (!filter) {
82         fprintf(stderr, "error allocating filter\n");
83         return;
84     }
85
86     if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
87         rtnl_link_put(filter);
88         return;
89     }
90
91     link_obj = (struct rtnl_link *) obj;
92     flags = rtnl_link_get_flags (link_obj);
93     ifname = rtnl_link_get_name(link_obj);
94
95     /*
96      * You can't bind a PF_PACKET socket to an interface that's not
97      * up, so an interface going down is an "interface should be
98      * removed" indication.
99      *
100      * XXX - what indication, if any, do we get if the interface
101      * *completely goes away*?
102      *
103      * XXX - can we get events if an interface's link-layer or
104      * network addresses change?
105      */
106     up = (flags & IFF_UP) ? 1 : 0;
107
108     cb(ifname, up);
109
110     rtnl_link_put(filter);
111
112     return;
113 }
114
115 static int
116 iface_mon_handler(struct nl_msg *msg, void *arg)
117 {
118     nl_msg_parse (msg, &iface_mon_handler2, arg);
119     return 0;
120 }
121
122 void
123 iface_mon_event(void)
124 {
125     nl_recvmsgs_default(iface_mon_sock);
126 }
127
128 int
129 iface_mon_get_sock(void)
130 {
131     return nl_socket_get_fd(iface_mon_sock);
132 }
133
134 int
135 iface_mon_start(iface_mon_cb cb)
136 {
137     int err;
138
139     iface_mon_sock = nl_socket_alloc();
140     if (!iface_mon_sock) {
141         fprintf(stderr, "Failed to allocate netlink socket.\n");
142         return -ENOMEM;
143     }
144
145     nl_socket_disable_seq_check(iface_mon_sock);
146
147     nl_socket_modify_cb(iface_mon_sock, NL_CB_VALID, NL_CB_CUSTOM, iface_mon_handler, cb);
148
149     if (nl_connect(iface_mon_sock, NETLINK_ROUTE)) {
150         fprintf(stderr, "Failed to connect to generic netlink.\n");
151         err = -ENOLINK;
152         goto out_handle_destroy;
153     }
154
155     nl_socket_add_membership(iface_mon_sock, RTNLGRP_LINK);
156
157     return 0;
158
159 out_handle_destroy:
160     nl_socket_free(iface_mon_sock);
161     return err;
162 }
163
164 void
165 iface_mon_stop(void)
166 {
167     if(iface_mon_sock)
168         nl_socket_free(iface_mon_sock);
169     iface_mon_sock = NULL;
170 }
171
172 #elif defined(__APPLE__)
173
174 /*
175  * OS X.
176  */
177
178 #include <stddef.h>
179 #include <stdio.h>
180 #include <errno.h>
181 #include <unistd.h>
182
183 #include <sys/socket.h>
184 #include <sys/ioctl.h>
185 #include <sys/types.h>
186 #include <net/if.h>
187 #include <sys/kern_event.h>
188
189 #include <glib.h>
190
191 static int s;
192 static iface_mon_cb callback;
193
194 int
195 iface_mon_start(iface_mon_cb cb)
196 {
197     int ret;
198     struct kev_request key;
199
200     /* Create a socket of type PF_SYSTEM to listen for events. */
201     s = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
202     if (s == -1)
203         return -errno;
204
205     /*
206      * Ask for DLIL messages.
207      *
208      * XXX - also ask for KEV_INET_SUBCLASS and KEV_INET6_SUBCLASS,
209      * to detect new or changed network addresses, so those can be
210      * updated as well?  Can we specify multiple filters on a socket,
211      * or must we specify KEV_ANY_SUBCLASS and filter the events after
212      * receiving them?
213      */
214     key.vendor_code = KEV_VENDOR_APPLE;
215     key.kev_class = KEV_NETWORK_CLASS;
216     key.kev_subclass = KEV_DL_SUBCLASS;
217     if (ioctl(s, SIOCSKEVFILT, &key) == -1) {
218         ret = -errno;
219         close(s);
220         return ret;
221     }
222
223     callback = cb;
224     return 0;
225 }
226
227 void
228 iface_mon_stop(void)
229 {
230     close(s);
231 }
232
233 int
234 iface_mon_get_sock(void)
235 {
236     return s;
237 }
238
239 /*
240  * Size of buffer for kernel network event.
241  */
242 #define NET_EVENT_DATA_SIZE     (KEV_MSG_HEADER_SIZE + sizeof (struct net_event_data))
243
244 void
245 iface_mon_event(void)
246 {
247     char msg[NET_EVENT_DATA_SIZE];
248     ssize_t received;
249     struct kern_event_msg *kem;
250     struct net_event_data *evd;
251     size_t evd_len;
252     char ifr_name[IFNAMSIZ];
253
254     received = recv(s, msg, sizeof msg, 0);
255     if (received < 0) {
256         /* Error - ignore. */
257         return;
258     }
259     if ((size_t)received < sizeof msg) {
260         /* Short read - ignore. */
261         return;
262     }
263     kem = (struct kern_event_msg *)msg;
264     evd_len = kem->total_size - KEV_MSG_HEADER_SIZE;
265     if (evd_len != sizeof (struct net_event_data)) {
266         /* Length of the message is bogus. */
267         return;
268     }
269     evd = (struct net_event_data *)&kem->event_data[0];
270     g_snprintf(ifr_name, IFNAMSIZ, "%s%u", evd->if_name, evd->if_unit);
271
272     /*
273      * Check type of event.
274      *
275      * Note: if we also ask for KEV_INET_SUBCLASS, we will get
276      * events with keys
277      *
278      *    KEV_INET_NEW_ADDR
279      *    KEV_INET_CHANGED_ADDR
280      *    KEV_INET_CHANGED_ADDR
281      *    KEV_INET_SIFDSTADDR
282      *    KEV_INET_SIFBRDADDR
283      *    KEV_INET_SIFNETMASK
284      *
285      * reflecting network address changes, with the data being a
286      * struct kev_in_data rather than struct net_event_data, and
287      * if we also ask for KEV_INET6_SUBCLASS, we will get events
288      * with keys
289      *
290      *    KEV_INET6_NEW_LL_ADDR
291      *    KEV_INET6_NEW_USER_ADDR
292      *    KEV_INET6_NEW_RTADV_ADDR
293      *    KEV_INET6_ADDR_DELETED
294      *
295      * with the data being a struct kev_in6_data.
296      */
297     switch (kem->event_code) {
298
299     case KEV_DL_IF_ATTACHED:
300         /*
301          * A new interface has arrived.
302          *
303          * XXX - what we really want is "a new BPFable interface
304          * has arrived", but that's not available.  While we're
305          * asking for additional help from BPF, it'd also be
306          * nice if we could ask it for a list of all interfaces
307          * that have had bpfattach()/bpf_attach() done on them,
308          * so we don't have to try to open the device in order
309          * to see whether we should show it as something on
310          * which we can capture.
311          */
312         callback(ifr_name, 1);
313         break;
314
315     case KEV_DL_IF_DETACHED:
316         /*
317          * An existing interface has been removed.
318          *
319          * XXX - use KEV_DL_IF_DETACHING instead, as that's
320          * called shortly after bpfdetach() is called, and
321          * bpfdetach() makes an interface no longer BPFable,
322          * and that's what we *really* care about.
323          */
324         callback(ifr_name, 0);
325         break;
326
327     default:
328         /*
329          * Is there any reason to care about:
330          *
331          *    KEV_DL_LINK_ON
332          *    KEV_DL_LINK_OFF
333          *    KEV_DL_SIFFLAGS
334          *    KEV_DL_LINK_ADDRESS_CHANGED
335          *    KEV_DL_IFCAP_CHANGED
336          *
337          * or any of the other events?  On Snow Leopard and, I think,
338          * earlier releases, you can't attach a BPF device to an
339          * interface that's not up, so KEV_DL_SIFFLAGS might be
340          * worth listening to so that we only say "here's a new
341          * interface" when it goes up; on Lion (and possibly Mountain
342          * Lion), an interface doesn't have to be up in order to
343          * have a BPF device attached to it.
344          */
345         break;
346     }
347 }
348
349 #else /* don't have something we support */
350
351 int
352 iface_mon_start(iface_mon_cb cb _U_)
353 {
354     return -1;
355 }
356
357 void
358 iface_mon_stop(void)
359 {
360 }
361
362 int
363 iface_mon_get_sock(void)
364 {
365     return -1;
366 }
367
368 void
369 iface_mon_event(void)
370 {
371 }
372
373 #endif /* HAVE_LIBNL */
374
375 #endif /* HAVE_LIBPCAP */