l2_packet_winpcap.c

Go to the documentation of this file.
00001 
00036 #include "includes.h"
00037 #include <pcap.h>
00038 
00039 #include "common.h"
00040 #include "eloop.h"
00041 #include "l2_packet.h"
00042 
00043 
00044 static const u8 pae_group_addr[ETH_ALEN] =
00045 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
00046 
00047 /*
00048  * Number of pcap_dispatch() iterations to do without extra wait after each
00049  * received EAPOL packet or authentication notification. This is used to reduce
00050  * latency for EAPOL receive.
00051  */
00052 static const size_t no_wait_count = 750;
00053 
00054 struct l2_packet_data {
00055         pcap_t *pcap;
00056         unsigned int num_fast_poll;
00057         char ifname[100];
00058         u8 own_addr[ETH_ALEN];
00059         void (*rx_callback)(void *ctx, const u8 *src_addr,
00060                             const u8 *buf, size_t len);
00061         void *rx_callback_ctx;
00062         int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
00063                      * rx_callback and l2_packet_send() */
00064         int running;
00065         HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
00066         u8 *rx_buf, *rx_src;
00067         size_t rx_len;
00068         size_t rx_no_wait;
00069 };
00070 
00071 
00072 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
00073 {
00074         os_memcpy(addr, l2->own_addr, ETH_ALEN);
00075         return 0;
00076 }
00077 
00078 
00079 int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
00080                    const u8 *buf, size_t len)
00081 {
00082         int ret;
00083         struct l2_ethhdr *eth;
00084 
00085         if (l2 == NULL)
00086                 return -1;
00087 
00088         if (l2->l2_hdr) {
00089                 ret = pcap_sendpacket(l2->pcap, buf, len);
00090         } else {
00091                 size_t mlen = sizeof(*eth) + len;
00092                 eth = os_malloc(mlen);
00093                 if (eth == NULL)
00094                         return -1;
00095 
00096                 os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
00097                 os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
00098                 eth->h_proto = htons(proto);
00099                 os_memcpy(eth + 1, buf, len);
00100                 ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
00101                 os_free(eth);
00102         }
00103 
00104         return ret;
00105 }
00106 
00107 
00108 /* pcap_dispatch() callback for the RX thread */
00109 static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
00110                                  const u_char *pkt_data)
00111 {
00112         struct l2_packet_data *l2 = (struct l2_packet_data *) user;
00113         struct l2_ethhdr *ethhdr;
00114 
00115         if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
00116                 return;
00117 
00118         ethhdr = (struct l2_ethhdr *) pkt_data;
00119         if (l2->l2_hdr) {
00120                 l2->rx_buf = (u8 *) ethhdr;
00121                 l2->rx_len = hdr->caplen;
00122         } else {
00123                 l2->rx_buf = (u8 *) (ethhdr + 1);
00124                 l2->rx_len = hdr->caplen - sizeof(*ethhdr);
00125         }
00126         l2->rx_src = ethhdr->h_source;
00127         SetEvent(l2->rx_avail);
00128         WaitForSingleObject(l2->rx_done, INFINITE);
00129         ResetEvent(l2->rx_done);
00130         l2->rx_no_wait = no_wait_count;
00131 }
00132 
00133 
00134 /* main RX loop that is running in a separate thread */
00135 static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
00136 {
00137         struct l2_packet_data *l2 = arg;
00138 
00139         while (l2->running) {
00140                 pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
00141                               (u_char *) l2);
00142                 if (l2->rx_no_wait > 0)
00143                         l2->rx_no_wait--;
00144                 if (WaitForSingleObject(l2->rx_notify,
00145                                         l2->rx_no_wait ? 0 : 50) ==
00146                     WAIT_OBJECT_0) {
00147                         l2->rx_no_wait = no_wait_count;
00148                         ResetEvent(l2->rx_notify);
00149                 }
00150         }
00151         SetEvent(l2->rx_thread_done);
00152         ExitThread(0);
00153         return 0;
00154 }
00155 
00156 
00157 /* main thread RX event handler */
00158 static void l2_packet_rx_event(void *eloop_data, void *user_data)
00159 {
00160         struct l2_packet_data *l2 = eloop_data;
00161         l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
00162                         l2->rx_len);
00163         ResetEvent(l2->rx_avail);
00164         SetEvent(l2->rx_done);
00165 }
00166 
00167 
00168 static int l2_packet_init_libpcap(struct l2_packet_data *l2,
00169                                   unsigned short protocol)
00170 {
00171         bpf_u_int32 pcap_maskp, pcap_netp;
00172         char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
00173         struct bpf_program pcap_fp;
00174 
00175         pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
00176         l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
00177         if (l2->pcap == NULL) {
00178                 fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
00179                 fprintf(stderr, "ifname='%s'\n", l2->ifname);
00180                 return -1;
00181         }
00182         os_snprintf(pcap_filter, sizeof(pcap_filter),
00183                     "not ether src " MACSTR " and "
00184                     "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
00185                     "ether proto 0x%x",
00186                     MAC2STR(l2->own_addr), /* do not receive own packets */
00187                     MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
00188                     protocol);
00189         if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
00190                 fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
00191                 return -1;
00192         }
00193 
00194         if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
00195                 fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
00196                 return -1;
00197         }
00198 
00199         pcap_freecode(&pcap_fp);
00200 
00201         return 0;
00202 }
00203 
00204 
00205 struct l2_packet_data * l2_packet_init(
00206         const char *ifname, const u8 *own_addr, unsigned short protocol,
00207         void (*rx_callback)(void *ctx, const u8 *src_addr,
00208                             const u8 *buf, size_t len),
00209         void *rx_callback_ctx, int l2_hdr)
00210 {
00211         struct l2_packet_data *l2;
00212         DWORD thread_id;
00213 
00214         l2 = os_zalloc(sizeof(struct l2_packet_data));
00215         if (l2 == NULL)
00216                 return NULL;
00217         if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
00218                 os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
00219         else
00220                 os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
00221                             ifname);
00222         l2->rx_callback = rx_callback;
00223         l2->rx_callback_ctx = rx_callback_ctx;
00224         l2->l2_hdr = l2_hdr;
00225 
00226         if (own_addr)
00227                 os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
00228 
00229         if (l2_packet_init_libpcap(l2, protocol)) {
00230                 os_free(l2);
00231                 return NULL;
00232         }
00233 
00234         l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
00235         l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
00236         l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
00237         if (l2->rx_avail == NULL || l2->rx_done == NULL ||
00238             l2->rx_notify == NULL) {
00239                 CloseHandle(l2->rx_avail);
00240                 CloseHandle(l2->rx_done);
00241                 CloseHandle(l2->rx_notify);
00242                 pcap_close(l2->pcap);
00243                 os_free(l2);
00244                 return NULL;
00245         }
00246 
00247         eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
00248                              l2_packet_rx_event, l2, NULL);
00249 
00250         l2->running = 1;
00251         l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
00252                                      &thread_id);
00253 
00254         return l2;
00255 }
00256 
00257 
00258 static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
00259 {
00260         struct l2_packet_data *l2 = eloop_ctx;
00261 
00262         if (l2->rx_thread_done &&
00263             WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
00264                 wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
00265                            "exit - kill it\n");
00266                 TerminateThread(l2->rx_thread, 0);
00267         }
00268         CloseHandle(l2->rx_thread_done);
00269         CloseHandle(l2->rx_thread);
00270         if (l2->pcap)
00271                 pcap_close(l2->pcap);
00272         eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
00273         CloseHandle(l2->rx_avail);
00274         CloseHandle(l2->rx_done);
00275         CloseHandle(l2->rx_notify);
00276         os_free(l2);
00277 }
00278 
00279 
00280 void l2_packet_deinit(struct l2_packet_data *l2)
00281 {
00282         if (l2 == NULL)
00283                 return;
00284 
00285         l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
00286 
00287         l2->running = 0;
00288         pcap_breakloop(l2->pcap);
00289 
00290         /*
00291          * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
00292          * event and this event is set in l2_packet_rx_event(). However,
00293          * l2_packet_deinit() may end up being called from l2->rx_callback(),
00294          * so we need to return from here and complete deinitialization in
00295          * a registered timeout to avoid having to forcefully kill the RX
00296          * thread.
00297          */
00298         eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
00299 }
00300 
00301 
00302 int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
00303 {
00304         pcap_if_t *devs, *dev;
00305         struct pcap_addr *addr;
00306         struct sockaddr_in *saddr;
00307         int found = 0;
00308         char err[PCAP_ERRBUF_SIZE + 1];
00309 
00310         if (pcap_findalldevs(&devs, err) < 0) {
00311                 wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
00312                 return -1;
00313         }
00314 
00315         for (dev = devs; dev && !found; dev = dev->next) {
00316                 if (os_strcmp(dev->name, l2->ifname) != 0)
00317                         continue;
00318 
00319                 addr = dev->addresses;
00320                 while (addr) {
00321                         saddr = (struct sockaddr_in *) addr->addr;
00322                         if (saddr && saddr->sin_family == AF_INET) {
00323                                 os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
00324                                            len);
00325                                 found = 1;
00326                                 break;
00327                         }
00328                         addr = addr->next;
00329                 }
00330         }
00331 
00332         pcap_freealldevs(devs);
00333 
00334         return found ? 0 : -1;
00335 }
00336 
00337 
00338 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
00339 {
00340         if (l2)
00341                 SetEvent(l2->rx_notify);
00342 }
00343 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1