3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/usr.sbin/wpa/ndis_events/ndis_events.c,v 1.8 2011/06/24 07:05:20 kevlo Exp $
36 * This program simulates the behavior of the ndis_events utility
37 * supplied with wpa_supplicant for Windows. The original utility
38 * is designed to translate Windows WMI events. We don't have WMI,
39 * but we need to supply certain event info to wpa_supplicant in
40 * order to make WPA2 work correctly, so we fake up the interface.
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/sysctl.h>
50 #include <net/if_dl.h>
51 #include <net/if_var.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
56 #include <net/route.h>
66 static int verbose
= 0;
68 static int all_events
= 0;
70 #define PROGNAME "ndis_events"
72 #define WPA_SUPPLICANT_PORT 9876
73 #define NDIS_INDICATION_LEN 2048
75 #define EVENT_CONNECT 0
76 #define EVENT_DISCONNECT 1
77 #define EVENT_MEDIA_SPECIFIC 2
79 #define NDIS_STATUS_MEDIA_CONNECT 0x4001000B
80 #define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
81 #define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012
91 static void dbgmsg(const char *, ...) __printflike(1, 2);
92 static int find_ifname(int, char *);
93 static int announce_event(char *, int, struct sockaddr_in
*);
94 static void usage(void);
97 dbgmsg(const char *fmt
, ...)
105 vsyslog(LOG_ERR
, fmt
, ap
);
112 find_ifname(int idx
, char *name
)
116 struct if_msghdr
*ifm
;
117 struct sockaddr_dl
*sdl
;
118 char *buf
, *lim
, *next
;
123 mib
[2] = 0; /* protocol */
124 mib
[3] = 0; /* wildcard address family */
125 mib
[4] = NET_RT_IFLIST
;
126 mib
[5] = 0; /* no flags */
128 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
131 buf
= malloc (needed
);
135 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
144 ifm
= (struct if_msghdr
*)next
;
145 if (ifm
->ifm_type
== RTM_IFINFO
) {
146 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
147 if (ifm
->ifm_index
== idx
) {
148 strncpy(name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
149 name
[sdl
->sdl_nlen
] = '\0';
154 next
+= ifm
->ifm_msglen
;
163 announce_event(char *ifname
, int sock
, struct sockaddr_in
*dst
)
166 char indication
[NDIS_INDICATION_LEN
];
169 char buf
[512], *pos
, *end
;
170 int len
, type
, _type
;
172 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
175 dbgmsg("socket creation failed");
179 bzero((char *)&ifr
, sizeof(ifr
));
180 e
= (struct ndis_evt
*)indication
;
181 e
->ne_len
= NDIS_INDICATION_LEN
- sizeof(struct ndis_evt
);
183 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
184 ifr
.ifr_data
= indication
;
186 if (ioctl(s
, SIOCGPRIVATE_0
, &ifr
) < 0) {
190 dbgmsg("drained all events from %s",
193 dbgmsg("failed to read event info from %s: %d",
199 if (e
->ne_sts
== NDIS_STATUS_MEDIA_CONNECT
) {
200 type
= EVENT_CONNECT
;
202 dbgmsg("Received a connect event for %s", ifname
);
207 } else if (e
->ne_sts
== NDIS_STATUS_MEDIA_DISCONNECT
) {
208 type
= EVENT_DISCONNECT
;
210 dbgmsg("Received a disconnect event for %s", ifname
);
215 } else if (e
->ne_sts
== NDIS_STATUS_MEDIA_SPECIFIC_INDICATION
) {
216 type
= EVENT_MEDIA_SPECIFIC
;
218 dbgmsg("Received a media-specific event for %s",
221 dbgmsg("unknown event %u\n", e
->ne_sts
);
225 end
= buf
+ sizeof(buf
);
227 memcpy(buf
, &_type
, sizeof(_type
));
228 pos
= buf
+ sizeof(_type
);
230 len
= snprintf(pos
+ 1, end
- pos
- 1, "%s", ifname
);
237 *pos
= (unsigned char) len
;
240 if (e
->ne_len
> 255 || 1 + e
->ne_len
> (u_int
)(end
- pos
)) {
241 dbgmsg("Not enough room for send_event data (%d)\n",
246 *pos
++ = (unsigned char) e
->ne_len
;
247 memcpy(pos
, (indication
) + sizeof(struct ndis_evt
), e
->ne_len
);
251 len
= sendto(sock
, buf
, pos
- buf
, 0, (struct sockaddr
*) dst
,
252 sizeof(struct sockaddr_in
));
261 fprintf(stderr
, "Usage: ndis_events [-a] [-d] [-v]\n");
266 main(int argc
, char *argv
[])
269 struct sockaddr_in sin
;
270 char msg
[NDIS_INDICATION_LEN
];
271 struct rt_msghdr
*rtm
;
272 struct if_msghdr
*ifm
;
273 char ifname
[IFNAMSIZ
];
276 while ((ch
= getopt(argc
, argv
, "dva")) != -1) {
293 if (!debug
&& daemon(0, 0))
294 err(1, "failed to daemonize ourselves");
297 openlog(PROGNAME
, LOG_PID
| LOG_CONS
, LOG_DAEMON
);
299 bzero((char *)&sin
, sizeof(sin
));
301 /* Create a datagram socket. */
303 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
305 dbgmsg("socket creation failed");
309 sin
.sin_family
= AF_INET
;
310 sin
.sin_addr
.s_addr
= inet_addr("127.0.0.1");
311 sin
.sin_port
= htons(WPA_SUPPLICANT_PORT
);
313 /* Create a routing socket. */
315 r
= socket (PF_ROUTE
, SOCK_RAW
, 0);
317 dbgmsg("routing socket creation failed");
321 /* Now sit and spin, waiting for events. */
324 dbgmsg("Listening for events");
327 n
= read(r
, msg
, NDIS_INDICATION_LEN
);
329 dbgmsg("read failed");
332 rtm
= (struct rt_msghdr
*)msg
;
333 if (rtm
->rtm_type
!= RTM_IFINFO
)
335 ifm
= (struct if_msghdr
*)msg
;
336 if (find_ifname(ifm
->ifm_index
, ifname
))
338 if (strstr(ifname
, "ndis")) {
339 while(announce_event(ifname
, s
, &sin
) == 0)
343 dbgmsg("Skipping ifinfo message from %s",