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