xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/eth_p_oui.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt  * hostapd / IEEE 802 OUI Extended EtherType 88-B7
3*a1157835SDaniel Fojt  * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
4*a1157835SDaniel Fojt  *
5*a1157835SDaniel Fojt  * This software may be distributed under the terms of the BSD license.
6*a1157835SDaniel Fojt  * See README for more details.
7*a1157835SDaniel Fojt  */
8*a1157835SDaniel Fojt 
9*a1157835SDaniel Fojt #include "utils/includes.h"
10*a1157835SDaniel Fojt 
11*a1157835SDaniel Fojt #include "utils/common.h"
12*a1157835SDaniel Fojt #include "utils/eloop.h"
13*a1157835SDaniel Fojt #include "l2_packet/l2_packet.h"
14*a1157835SDaniel Fojt #include "hostapd.h"
15*a1157835SDaniel Fojt #include "eth_p_oui.h"
16*a1157835SDaniel Fojt 
17*a1157835SDaniel Fojt /*
18*a1157835SDaniel Fojt  * See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
19*a1157835SDaniel Fojt  * EtherType 88-B7. This file implements this with OUI 00:13:74 and
20*a1157835SDaniel Fojt  * vendor-specific subtype 0x0001.
21*a1157835SDaniel Fojt  */
22*a1157835SDaniel Fojt static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
23*a1157835SDaniel Fojt 
24*a1157835SDaniel Fojt struct eth_p_oui_iface {
25*a1157835SDaniel Fojt 	struct dl_list list;
26*a1157835SDaniel Fojt 	char ifname[IFNAMSIZ + 1];
27*a1157835SDaniel Fojt 	struct l2_packet_data *l2;
28*a1157835SDaniel Fojt 	struct dl_list receiver;
29*a1157835SDaniel Fojt };
30*a1157835SDaniel Fojt 
31*a1157835SDaniel Fojt struct eth_p_oui_ctx {
32*a1157835SDaniel Fojt 	struct dl_list list;
33*a1157835SDaniel Fojt 	struct eth_p_oui_iface *iface;
34*a1157835SDaniel Fojt 	/* all data needed to deliver and unregister */
35*a1157835SDaniel Fojt 	u8 oui_suffix; /* last byte of OUI */
36*a1157835SDaniel Fojt 	void (*rx_callback)(void *ctx, const u8 *src_addr,
37*a1157835SDaniel Fojt 			    const u8 *dst_addr, u8 oui_suffix,
38*a1157835SDaniel Fojt 			    const u8 *buf, size_t len);
39*a1157835SDaniel Fojt 	void *rx_callback_ctx;
40*a1157835SDaniel Fojt };
41*a1157835SDaniel Fojt 
42*a1157835SDaniel Fojt 
eth_p_oui_deliver(struct eth_p_oui_ctx * ctx,const u8 * src_addr,const u8 * dst_addr,const u8 * buf,size_t len)43*a1157835SDaniel Fojt void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
44*a1157835SDaniel Fojt 		       const u8 *dst_addr, const u8 *buf, size_t len)
45*a1157835SDaniel Fojt {
46*a1157835SDaniel Fojt 	ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
47*a1157835SDaniel Fojt 			 ctx->oui_suffix, buf, len);
48*a1157835SDaniel Fojt }
49*a1157835SDaniel Fojt 
50*a1157835SDaniel Fojt 
eth_p_rx(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)51*a1157835SDaniel Fojt static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
52*a1157835SDaniel Fojt {
53*a1157835SDaniel Fojt 	struct eth_p_oui_iface *iface = ctx;
54*a1157835SDaniel Fojt 	struct eth_p_oui_ctx *receiver;
55*a1157835SDaniel Fojt 	const struct l2_ethhdr *ethhdr;
56*a1157835SDaniel Fojt 
57*a1157835SDaniel Fojt 	if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
58*a1157835SDaniel Fojt 		/* too short packet */
59*a1157835SDaniel Fojt 		return;
60*a1157835SDaniel Fojt 	}
61*a1157835SDaniel Fojt 
62*a1157835SDaniel Fojt 	ethhdr = (struct l2_ethhdr *) buf;
63*a1157835SDaniel Fojt 	/* trim eth_hdr from buf and len */
64*a1157835SDaniel Fojt 	buf += sizeof(*ethhdr);
65*a1157835SDaniel Fojt 	len -= sizeof(*ethhdr);
66*a1157835SDaniel Fojt 
67*a1157835SDaniel Fojt 	/* verify OUI and vendor-specific subtype match */
68*a1157835SDaniel Fojt 	if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
69*a1157835SDaniel Fojt 		return;
70*a1157835SDaniel Fojt 	buf += sizeof(global_oui);
71*a1157835SDaniel Fojt 	len -= sizeof(global_oui);
72*a1157835SDaniel Fojt 
73*a1157835SDaniel Fojt 	dl_list_for_each(receiver, &iface->receiver,
74*a1157835SDaniel Fojt 			 struct eth_p_oui_ctx, list) {
75*a1157835SDaniel Fojt 		if (buf[0] != receiver->oui_suffix)
76*a1157835SDaniel Fojt 			continue;
77*a1157835SDaniel Fojt 
78*a1157835SDaniel Fojt 		eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
79*a1157835SDaniel Fojt 				  buf + 1, len - 1);
80*a1157835SDaniel Fojt 	}
81*a1157835SDaniel Fojt }
82*a1157835SDaniel Fojt 
83*a1157835SDaniel Fojt 
84*a1157835SDaniel Fojt struct eth_p_oui_ctx *
eth_p_oui_register(struct hostapd_data * hapd,const char * ifname,u8 oui_suffix,void (* rx_callback)(void * ctx,const u8 * src_addr,const u8 * dst_addr,u8 oui_suffix,const u8 * buf,size_t len),void * rx_callback_ctx)85*a1157835SDaniel Fojt eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
86*a1157835SDaniel Fojt 		   void (*rx_callback)(void *ctx, const u8 *src_addr,
87*a1157835SDaniel Fojt 				       const u8 *dst_addr, u8 oui_suffix,
88*a1157835SDaniel Fojt 				       const u8 *buf, size_t len),
89*a1157835SDaniel Fojt 		   void *rx_callback_ctx)
90*a1157835SDaniel Fojt {
91*a1157835SDaniel Fojt 	struct eth_p_oui_iface *iface;
92*a1157835SDaniel Fojt 	struct eth_p_oui_ctx *receiver;
93*a1157835SDaniel Fojt 	int found = 0;
94*a1157835SDaniel Fojt 	struct hapd_interfaces *interfaces;
95*a1157835SDaniel Fojt 
96*a1157835SDaniel Fojt 	receiver = os_zalloc(sizeof(*receiver));
97*a1157835SDaniel Fojt 	if (!receiver)
98*a1157835SDaniel Fojt 		goto err;
99*a1157835SDaniel Fojt 
100*a1157835SDaniel Fojt 	receiver->oui_suffix = oui_suffix;
101*a1157835SDaniel Fojt 	receiver->rx_callback = rx_callback;
102*a1157835SDaniel Fojt 	receiver->rx_callback_ctx = rx_callback_ctx;
103*a1157835SDaniel Fojt 
104*a1157835SDaniel Fojt 	interfaces = hapd->iface->interfaces;
105*a1157835SDaniel Fojt 
106*a1157835SDaniel Fojt 	dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
107*a1157835SDaniel Fojt 			 list) {
108*a1157835SDaniel Fojt 		if (os_strcmp(iface->ifname, ifname) != 0)
109*a1157835SDaniel Fojt 			continue;
110*a1157835SDaniel Fojt 		found = 1;
111*a1157835SDaniel Fojt 		break;
112*a1157835SDaniel Fojt 	}
113*a1157835SDaniel Fojt 
114*a1157835SDaniel Fojt 	if (!found) {
115*a1157835SDaniel Fojt 		iface = os_zalloc(sizeof(*iface));
116*a1157835SDaniel Fojt 		if (!iface)
117*a1157835SDaniel Fojt 			goto err;
118*a1157835SDaniel Fojt 
119*a1157835SDaniel Fojt 		os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
120*a1157835SDaniel Fojt 		iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
121*a1157835SDaniel Fojt 					   iface, 1);
122*a1157835SDaniel Fojt 		if (!iface->l2) {
123*a1157835SDaniel Fojt 			os_free(iface);
124*a1157835SDaniel Fojt 			goto err;
125*a1157835SDaniel Fojt 		}
126*a1157835SDaniel Fojt 		dl_list_init(&iface->receiver);
127*a1157835SDaniel Fojt 
128*a1157835SDaniel Fojt 		dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
129*a1157835SDaniel Fojt 	}
130*a1157835SDaniel Fojt 
131*a1157835SDaniel Fojt 	dl_list_add_tail(&iface->receiver, &receiver->list);
132*a1157835SDaniel Fojt 	receiver->iface = iface;
133*a1157835SDaniel Fojt 
134*a1157835SDaniel Fojt 	return receiver;
135*a1157835SDaniel Fojt err:
136*a1157835SDaniel Fojt 	os_free(receiver);
137*a1157835SDaniel Fojt 	return NULL;
138*a1157835SDaniel Fojt }
139*a1157835SDaniel Fojt 
140*a1157835SDaniel Fojt 
eth_p_oui_unregister(struct eth_p_oui_ctx * ctx)141*a1157835SDaniel Fojt void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
142*a1157835SDaniel Fojt {
143*a1157835SDaniel Fojt 	struct eth_p_oui_iface *iface;
144*a1157835SDaniel Fojt 
145*a1157835SDaniel Fojt 	if (!ctx)
146*a1157835SDaniel Fojt 		return;
147*a1157835SDaniel Fojt 
148*a1157835SDaniel Fojt 	iface = ctx->iface;
149*a1157835SDaniel Fojt 
150*a1157835SDaniel Fojt 	dl_list_del(&ctx->list);
151*a1157835SDaniel Fojt 	os_free(ctx);
152*a1157835SDaniel Fojt 
153*a1157835SDaniel Fojt 	if (dl_list_empty(&iface->receiver)) {
154*a1157835SDaniel Fojt 		dl_list_del(&iface->list);
155*a1157835SDaniel Fojt 		l2_packet_deinit(iface->l2);
156*a1157835SDaniel Fojt 		os_free(iface);
157*a1157835SDaniel Fojt 	}
158*a1157835SDaniel Fojt }
159*a1157835SDaniel Fojt 
160*a1157835SDaniel Fojt 
eth_p_oui_send(struct eth_p_oui_ctx * ctx,const u8 * src_addr,const u8 * dst_addr,const u8 * buf,size_t len)161*a1157835SDaniel Fojt int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
162*a1157835SDaniel Fojt 		   const u8 *dst_addr, const u8 *buf, size_t len)
163*a1157835SDaniel Fojt {
164*a1157835SDaniel Fojt 	struct eth_p_oui_iface *iface = ctx->iface;
165*a1157835SDaniel Fojt 	u8 *packet, *p;
166*a1157835SDaniel Fojt 	size_t packet_len;
167*a1157835SDaniel Fojt 	int ret;
168*a1157835SDaniel Fojt 	struct l2_ethhdr *ethhdr;
169*a1157835SDaniel Fojt 
170*a1157835SDaniel Fojt 	packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
171*a1157835SDaniel Fojt 	packet = os_zalloc(packet_len);
172*a1157835SDaniel Fojt 	if (!packet)
173*a1157835SDaniel Fojt 		return -1;
174*a1157835SDaniel Fojt 	p = packet;
175*a1157835SDaniel Fojt 
176*a1157835SDaniel Fojt 	ethhdr = (struct l2_ethhdr *) packet;
177*a1157835SDaniel Fojt 	os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
178*a1157835SDaniel Fojt 	os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
179*a1157835SDaniel Fojt 	ethhdr->h_proto = host_to_be16(ETH_P_OUI);
180*a1157835SDaniel Fojt 	p += sizeof(*ethhdr);
181*a1157835SDaniel Fojt 
182*a1157835SDaniel Fojt 	os_memcpy(p, global_oui, sizeof(global_oui));
183*a1157835SDaniel Fojt 	p[sizeof(global_oui)] = ctx->oui_suffix;
184*a1157835SDaniel Fojt 	p += sizeof(global_oui) + 1;
185*a1157835SDaniel Fojt 
186*a1157835SDaniel Fojt 	os_memcpy(p, buf, len);
187*a1157835SDaniel Fojt 
188*a1157835SDaniel Fojt 	ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
189*a1157835SDaniel Fojt 	os_free(packet);
190*a1157835SDaniel Fojt 	return ret;
191*a1157835SDaniel Fojt }
192