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