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