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