1*a399b765Szf162725 /* 2*a399b765Szf162725 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3*a399b765Szf162725 * Use is subject to license terms. 4*a399b765Szf162725 */ 5*a399b765Szf162725 6*a399b765Szf162725 /* 7*a399b765Szf162725 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 8*a399b765Szf162725 * Sun elects to license this software under the BSD license. 9*a399b765Szf162725 * See README for more details. 10*a399b765Szf162725 */ 11*a399b765Szf162725 12*a399b765Szf162725 #pragma ident "%Z%%M% %I% %E% SMI" 13*a399b765Szf162725 14*a399b765Szf162725 #include <stdio.h> 15*a399b765Szf162725 #include <stdlib.h> 16*a399b765Szf162725 #include <string.h> 17*a399b765Szf162725 #include <unistd.h> 18*a399b765Szf162725 #include <libdlpi.h> 19*a399b765Szf162725 #include <sys/ethernet.h> 20*a399b765Szf162725 #include <netinet/in.h> 21*a399b765Szf162725 22*a399b765Szf162725 #include "wpa_impl.h" 23*a399b765Szf162725 #include "eloop.h" 24*a399b765Szf162725 #include "l2_packet.h" 25*a399b765Szf162725 26*a399b765Szf162725 static int 27*a399b765Szf162725 link_init(struct l2_packet_data *l2) 28*a399b765Szf162725 { 29*a399b765Szf162725 int retval; 30*a399b765Szf162725 uint8_t paddr[DLPI_PHYSADDR_MAX]; 31*a399b765Szf162725 size_t paddrlen = sizeof (paddr); 32*a399b765Szf162725 33*a399b765Szf162725 retval = dlpi_bind(l2->dh, DLPI_ANY_SAP, NULL); 34*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 35*a399b765Szf162725 wpa_printf(MSG_ERROR, "cannot bind on %s: %s", 36*a399b765Szf162725 l2->ifname, dlpi_strerror(retval)); 37*a399b765Szf162725 return (-1); 38*a399b765Szf162725 } 39*a399b765Szf162725 40*a399b765Szf162725 retval = dlpi_promiscon(l2->dh, DL_PROMISC_SAP); 41*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 42*a399b765Szf162725 wpa_printf(MSG_ERROR, "cannot enable promiscous" 43*a399b765Szf162725 " mode (SAP) on %s: %s", 44*a399b765Szf162725 l2->ifname, dlpi_strerror(retval)); 45*a399b765Szf162725 return (-1); 46*a399b765Szf162725 } 47*a399b765Szf162725 48*a399b765Szf162725 retval = dlpi_get_physaddr(l2->dh, DL_CURR_PHYS_ADDR, paddr, &paddrlen); 49*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 50*a399b765Szf162725 wpa_printf(MSG_ERROR, "cannot get physical address for %s: %s", 51*a399b765Szf162725 l2->ifname, dlpi_strerror(retval)); 52*a399b765Szf162725 return (-1); 53*a399b765Szf162725 } 54*a399b765Szf162725 if (paddrlen != sizeof (l2->own_addr)) { 55*a399b765Szf162725 wpa_printf(MSG_ERROR, "physical address for %s is not %d bytes", 56*a399b765Szf162725 l2->ifname, sizeof (l2->own_addr)); 57*a399b765Szf162725 return (-1); 58*a399b765Szf162725 } 59*a399b765Szf162725 (void) memcpy(l2->own_addr, paddr, sizeof (l2->own_addr)); 60*a399b765Szf162725 61*a399b765Szf162725 return (0); 62*a399b765Szf162725 } 63*a399b765Szf162725 64*a399b765Szf162725 /* 65*a399b765Szf162725 * layer2 packet handling. 66*a399b765Szf162725 */ 67*a399b765Szf162725 int 68*a399b765Szf162725 l2_packet_get_own_addr(struct l2_packet_data *l2, uint8_t *addr) 69*a399b765Szf162725 { 70*a399b765Szf162725 (void) memcpy(addr, l2->own_addr, sizeof (l2->own_addr)); 71*a399b765Szf162725 return (0); 72*a399b765Szf162725 } 73*a399b765Szf162725 74*a399b765Szf162725 int 75*a399b765Szf162725 l2_packet_send(struct l2_packet_data *l2, uint8_t *buf, size_t buflen) 76*a399b765Szf162725 { 77*a399b765Szf162725 int retval; 78*a399b765Szf162725 79*a399b765Szf162725 retval = dlpi_send(l2->dh, NULL, 0, buf, buflen, NULL); 80*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 81*a399b765Szf162725 wpa_printf(MSG_ERROR, "l2_packet_send: cannot send " 82*a399b765Szf162725 "message on %s: %s", l2->ifname, dlpi_strerror(retval)); 83*a399b765Szf162725 return (-1); 84*a399b765Szf162725 } 85*a399b765Szf162725 return (0); 86*a399b765Szf162725 } 87*a399b765Szf162725 88*a399b765Szf162725 /* ARGSUSED */ 89*a399b765Szf162725 static void 90*a399b765Szf162725 l2_packet_receive(int fd, void *eloop_ctx, void *sock_ctx) 91*a399b765Szf162725 { 92*a399b765Szf162725 struct l2_packet_data *l2 = eloop_ctx; 93*a399b765Szf162725 uint64_t buf[IEEE80211_MTU_MAX / sizeof (uint64_t)]; 94*a399b765Szf162725 size_t buflen = sizeof (buf); 95*a399b765Szf162725 struct l2_ethhdr *ethhdr; 96*a399b765Szf162725 int retval; 97*a399b765Szf162725 98*a399b765Szf162725 retval = dlpi_recv(l2->dh, NULL, NULL, buf, &buflen, 0, NULL); 99*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 100*a399b765Szf162725 wpa_printf(MSG_ERROR, "l2_packet_receive: cannot receive " 101*a399b765Szf162725 "message on %s: %s", l2->ifname, dlpi_strerror(retval)); 102*a399b765Szf162725 return; 103*a399b765Szf162725 } 104*a399b765Szf162725 105*a399b765Szf162725 ethhdr = (struct l2_ethhdr *)buf; 106*a399b765Szf162725 if (buflen < sizeof (*ethhdr) || 107*a399b765Szf162725 (ntohs(ethhdr->h_proto) != ETHERTYPE_EAPOL && 108*a399b765Szf162725 ntohs(ethhdr->h_proto) != ETHERTYPE_RSN_PREAUTH)) 109*a399b765Szf162725 return; 110*a399b765Szf162725 111*a399b765Szf162725 l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, 112*a399b765Szf162725 (unsigned char *)(ethhdr + 1), buflen - sizeof (*ethhdr)); 113*a399b765Szf162725 } 114*a399b765Szf162725 115*a399b765Szf162725 /* ARGSUSED */ 116*a399b765Szf162725 struct l2_packet_data * 117*a399b765Szf162725 l2_packet_init(const char *ifname, unsigned short protocol, 118*a399b765Szf162725 void (*rx_callback)(void *, unsigned char *, unsigned char *, size_t), 119*a399b765Szf162725 void *rx_callback_ctx) 120*a399b765Szf162725 { 121*a399b765Szf162725 int retval; 122*a399b765Szf162725 struct l2_packet_data *l2; 123*a399b765Szf162725 124*a399b765Szf162725 l2 = calloc(1, sizeof (struct l2_packet_data)); 125*a399b765Szf162725 if (l2 == NULL) 126*a399b765Szf162725 return (NULL); 127*a399b765Szf162725 128*a399b765Szf162725 (void) strlcpy(l2->ifname, ifname, sizeof (l2->ifname)); 129*a399b765Szf162725 l2->rx_callback = rx_callback; 130*a399b765Szf162725 l2->rx_callback_ctx = rx_callback_ctx; 131*a399b765Szf162725 132*a399b765Szf162725 retval = dlpi_open(l2->ifname, &l2->dh, DLPI_RAW); 133*a399b765Szf162725 if (retval != DLPI_SUCCESS) { 134*a399b765Szf162725 wpa_printf(MSG_ERROR, "unable to open DLPI link %s: %s", 135*a399b765Szf162725 l2->ifname, dlpi_strerror(retval)); 136*a399b765Szf162725 free(l2); 137*a399b765Szf162725 return (NULL); 138*a399b765Szf162725 } 139*a399b765Szf162725 140*a399b765Szf162725 /* NOTE: link_init() sets l2->own_addr */ 141*a399b765Szf162725 if (link_init(l2) < 0) { 142*a399b765Szf162725 dlpi_close(l2->dh); 143*a399b765Szf162725 free(l2); 144*a399b765Szf162725 return (NULL); 145*a399b765Szf162725 } 146*a399b765Szf162725 147*a399b765Szf162725 (void) eloop_register_read_sock(dlpi_fd(l2->dh), l2_packet_receive, l2, 148*a399b765Szf162725 NULL); 149*a399b765Szf162725 150*a399b765Szf162725 return (l2); 151*a399b765Szf162725 } 152*a399b765Szf162725 153*a399b765Szf162725 void 154*a399b765Szf162725 l2_packet_deinit(struct l2_packet_data *l2) 155*a399b765Szf162725 { 156*a399b765Szf162725 if (l2 == NULL) 157*a399b765Szf162725 return; 158*a399b765Szf162725 159*a399b765Szf162725 eloop_unregister_read_sock(dlpi_fd(l2->dh)); 160*a399b765Szf162725 dlpi_close(l2->dh); 161*a399b765Szf162725 free(l2); 162*a399b765Szf162725 } 163