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
link_init(struct l2_packet_data * l2)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
l2_packet_get_own_addr(struct l2_packet_data * l2,uint8_t * addr)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
l2_packet_send(struct l2_packet_data * l2,uint8_t * buf,size_t buflen)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
l2_packet_receive(int fd,void * eloop_ctx,void * sock_ctx)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 *
l2_packet_init(const char * ifname,unsigned short protocol,void (* rx_callback)(void *,unsigned char *,unsigned char *,size_t),void * rx_callback_ctx)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
l2_packet_deinit(struct l2_packet_data * l2)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