1/* 2 * WPA Supplicant - Layer2 packet handling with FreeBSD 3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> 4 * Copyright (c) 2005, Sam Leffler <sam@errno.com> 5 * 6 * This software may be distributed under the terms of the BSD license. 7 * See README for more details. 8 */ 9 10#include "includes.h" 11#if defined(__APPLE__) || defined(__GLIBC__) 12#include <net/bpf.h> 13#endif /* __APPLE__ */ 14#include <pcap.h> 15 16#include <sys/ioctl.h> 17#ifdef __sun__ 18#include <libdlpi.h> 19#else /* __sun__ */ 20#include <sys/sysctl.h> 21#endif /* __sun__ */ 22 23#include <net/if.h> 24#include <net/if_dl.h> 25#include <net/route.h> 26#include <netinet/in.h> 27 28#include "common.h" 29#include "eloop.h" 30#include "l2_packet.h" 31 32 33static const u8 pae_group_addr[ETH_ALEN] = 34{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; 35 36struct l2_packet_data { 37 pcap_t *pcap; 38 char ifname[100]; 39 u8 own_addr[ETH_ALEN]; 40 void (*rx_callback)(void *ctx, const u8 *src_addr, 41 const u8 *buf, size_t len); 42 void *rx_callback_ctx; 43 int l2_hdr; /* whether to include layer 2 (Ethernet) header data 44 * buffers */ 45}; 46 47 48int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) 49{ 50 os_memcpy(addr, l2->own_addr, ETH_ALEN); 51 return 0; 52} 53 54 55int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, 56 const u8 *buf, size_t len) 57{ 58 if (!l2->l2_hdr) { 59 int ret; 60 struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len); 61 if (eth == NULL) 62 return -1; 63 os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); 64 os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); 65 eth->h_proto = htons(proto); 66 os_memcpy(eth + 1, buf, len); 67 ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth)); 68 os_free(eth); 69 return ret; 70 } else 71 return pcap_inject(l2->pcap, buf, len); 72} 73 74 75static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) 76{ 77 struct l2_packet_data *l2 = eloop_ctx; 78 pcap_t *pcap = sock_ctx; 79 struct pcap_pkthdr hdr; 80 const u_char *packet; 81 struct l2_ethhdr *ethhdr; 82 unsigned char *buf; 83 size_t len; 84 85 packet = pcap_next(pcap, &hdr); 86 87 if (packet == NULL || hdr.caplen < sizeof(*ethhdr)) 88 return; 89 90 ethhdr = (struct l2_ethhdr *) packet; 91 if (l2->l2_hdr) { 92 buf = (unsigned char *) ethhdr; 93 len = hdr.caplen; 94 } else { 95 buf = (unsigned char *) (ethhdr + 1); 96 len = hdr.caplen - sizeof(*ethhdr); 97 } 98 l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); 99} 100 101 102static int l2_packet_init_libpcap(struct l2_packet_data *l2, 103 unsigned short protocol) 104{ 105 bpf_u_int32 pcap_maskp, pcap_netp; 106 char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; 107 struct bpf_program pcap_fp; 108 109 pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); 110 l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err); 111 if (l2->pcap == NULL) { 112 fprintf(stderr, "pcap_open_live: %s\n", pcap_err); 113 fprintf(stderr, "ifname='%s'\n", l2->ifname); 114 return -1; 115 } 116 if (pcap_datalink(l2->pcap) != DLT_EN10MB && 117 pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) { 118 fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n", 119 pcap_geterr(l2->pcap)); 120 return -1; 121 } 122 os_snprintf(pcap_filter, sizeof(pcap_filter), 123 "not ether src " MACSTR " and " 124 "( ether dst " MACSTR " or ether dst " MACSTR " ) and " 125 "ether proto 0x%x", 126 MAC2STR(l2->own_addr), /* do not receive own packets */ 127 MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), 128 protocol); 129 if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { 130 fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); 131 return -1; 132 } 133 134 if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { 135 fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); 136 return -1; 137 } 138 139 pcap_freecode(&pcap_fp); 140#ifndef __sun__ 141 /* 142 * When libpcap uses BPF we must enable "immediate mode" to 143 * receive frames right away; otherwise the system may 144 * buffer them for us. 145 */ 146 { 147 unsigned int on = 1; 148 if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) { 149 fprintf(stderr, "%s: cannot enable immediate mode on " 150 "interface %s: %s\n", 151 __func__, l2->ifname, strerror(errno)); 152 /* XXX should we fail? */ 153 } 154 } 155#endif /* __sun__ */ 156 157 eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap), 158 l2_packet_receive, l2, l2->pcap); 159 160 return 0; 161} 162 163 164static int eth_get(const char *device, u8 ea[ETH_ALEN]) 165{ 166#ifdef __sun__ 167 dlpi_handle_t dh; 168 u32 physaddrlen = DLPI_PHYSADDR_MAX; 169 u8 physaddr[DLPI_PHYSADDR_MAX]; 170 int retval; 171 172 retval = dlpi_open(device, &dh, 0); 173 if (retval != DLPI_SUCCESS) { 174 wpa_printf(MSG_ERROR, "dlpi_open error: %s", 175 dlpi_strerror(retval)); 176 return -1; 177 } 178 179 retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, 180 &physaddrlen); 181 if (retval != DLPI_SUCCESS) { 182 wpa_printf(MSG_ERROR, "dlpi_get_physaddr error: %s", 183 dlpi_strerror(retval)); 184 dlpi_close(dh); 185 return -1; 186 } 187 os_memcpy(ea, physaddr, ETH_ALEN); 188 dlpi_close(dh); 189#else /* __sun__ */ 190 struct if_msghdr *ifm; 191 struct sockaddr_dl *sdl; 192 u_char *p, *buf; 193 size_t len; 194 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; 195 196 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 197 return -1; 198 if ((buf = os_malloc(len)) == NULL) 199 return -1; 200 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 201 os_free(buf); 202 return -1; 203 } 204 for (p = buf; p < buf + len; p += ifm->ifm_msglen) { 205 ifm = (struct if_msghdr *)p; 206 sdl = (struct sockaddr_dl *)(ifm + 1); 207 if (ifm->ifm_type != RTM_IFINFO || 208 (ifm->ifm_addrs & RTA_IFP) == 0) 209 continue; 210 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || 211 os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0) 212 continue; 213 os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen); 214 break; 215 } 216 os_free(buf); 217 218 if (p >= buf + len) { 219 errno = ESRCH; 220 return -1; 221 } 222#endif /* __sun__ */ 223 return 0; 224} 225 226 227struct l2_packet_data * l2_packet_init( 228 const char *ifname, const u8 *own_addr, unsigned short protocol, 229 void (*rx_callback)(void *ctx, const u8 *src_addr, 230 const u8 *buf, size_t len), 231 void *rx_callback_ctx, int l2_hdr) 232{ 233 struct l2_packet_data *l2; 234 235 l2 = os_zalloc(sizeof(struct l2_packet_data)); 236 if (l2 == NULL) 237 return NULL; 238 os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); 239 l2->rx_callback = rx_callback; 240 l2->rx_callback_ctx = rx_callback_ctx; 241 l2->l2_hdr = l2_hdr; 242 243 if (eth_get(l2->ifname, l2->own_addr) < 0) { 244 fprintf(stderr, "Failed to get link-level address for " 245 "interface '%s'.\n", l2->ifname); 246 os_free(l2); 247 return NULL; 248 } 249 250 if (l2_packet_init_libpcap(l2, protocol)) { 251 os_free(l2); 252 return NULL; 253 } 254 255 return l2; 256} 257 258 259void l2_packet_deinit(struct l2_packet_data *l2) 260{ 261 if (l2 != NULL) { 262 if (l2->pcap) { 263 eloop_unregister_read_sock( 264 pcap_get_selectable_fd(l2->pcap)); 265 pcap_close(l2->pcap); 266 } 267 os_free(l2); 268 } 269} 270 271 272int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) 273{ 274 pcap_if_t *devs, *dev; 275 struct pcap_addr *addr; 276 struct sockaddr_in *saddr; 277 int found = 0; 278 char err[PCAP_ERRBUF_SIZE + 1]; 279 280 if (pcap_findalldevs(&devs, err) < 0) { 281 wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); 282 return -1; 283 } 284 285 for (dev = devs; dev && !found; dev = dev->next) { 286 if (os_strcmp(dev->name, l2->ifname) != 0) 287 continue; 288 289 addr = dev->addresses; 290 while (addr) { 291 saddr = (struct sockaddr_in *) addr->addr; 292 if (saddr && saddr->sin_family == AF_INET) { 293 os_strlcpy(buf, inet_ntoa(saddr->sin_addr), 294 len); 295 found = 1; 296 break; 297 } 298 addr = addr->next; 299 } 300 } 301 302 pcap_freealldevs(devs); 303 304 return found ? 0 : -1; 305} 306 307 308void l2_packet_notify_auth_start(struct l2_packet_data *l2) 309{ 310} 311