xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dhd_wet.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /**
2  * @file
3  * @brief
4  * Wireless EThernet (WET) Bridge.
5  *
6  * WET STA and WET client are inter-exchangable in this file and refer to
7  * addressable entities whose traffic are sent and received through this
8  * bridge, including the hosting device.
9  *
10  * Supported protocol families: IP v4.
11  *
12  * Tx: replace frames' source MAC address with wireless interface's;
13  * update the IP-MAC address mapping table entry.
14  *
15  * Rx: replace frames' the destination MAC address with what found in
16  * the IP-MAC address mapping table.
17  *
18  * All data structures defined in this file are optimized for IP v4. To
19  * support other protocol families, write protocol specific handlers.
20  * Doing so may require data structures changes to expand various address
21  * storages to fit the protocol specific needs, for example, IPX needs 10
22  * octets for its network address. Also one may need to define the data
23  * structures in a more generic way so that they work with all supported
24  * protocol families, for example, the wet_sta strcture may be defined
25  * as follow:
26  *
27  *	struct wet_sta {
28  *		uint8 nal;		network address length
29  *		uint8 na[NETA_MAX_LEN];	network address
30  *		uint8 mac[ETHER_ADDR_LEN];
31  *		...
32  *	};
33  *
34  * Copyright (C) 2020, Broadcom.
35  *
36  *      Unless you and Broadcom execute a separate written software license
37  * agreement governing use of this software, this software is licensed to you
38  * under the terms of the GNU General Public License version 2 (the "GPL"),
39  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
40  * following added to such license:
41  *
42  *      As a special exception, the copyright holders of this software give you
43  * permission to link this software with independent modules, and to copy and
44  * distribute the resulting executable under terms of your choice, provided that
45  * you also meet, for each linked independent module, the terms and conditions of
46  * the license of that module.  An independent module is a module which is not
47  * derived from this software.  The special exception does not apply to any
48  * modifications of the software.
49  *
50  *
51  * <<Broadcom-WL-IPTag/Open:>>
52  *
53  * $Id$
54  */
55 
56 /**
57  * @file
58  * @brief
59  * XXX Twiki: [WirelessEthernet]
60  */
61 #include <typedefs.h>
62 #include <bcmdefs.h>
63 #include <osl.h>
64 #include <bcmutils.h>
65 #include <siutils.h>
66 #include <wlioctl.h>
67 #include <802.11.h>
68 #include <ethernet.h>
69 #include <vlan.h>
70 #include <802.3.h>
71 #include <bcmip.h>
72 #include <bcmarp.h>
73 #include <bcmudp.h>
74 #include <bcmdhcp.h>
75 #include <bcmendian.h>
76 #include <dhd_dbg.h>
77 #include <d11.h>
78 
79 #include <dhd_wet.h>
80 
81 /* IP/MAC address mapping entry */
82 typedef struct wet_sta wet_sta_t;
83 struct wet_sta {
84 	/* client */
85 	uint8 ip[IPV4_ADDR_LEN];	/* client IP addr */
86 	struct ether_addr mac;	/* client MAC addr */
87 	uint8 flags[DHCP_FLAGS_LEN];	/* orig. dhcp flags */
88 	/* internal */
89 	wet_sta_t *next;	/* free STA link */
90 	wet_sta_t *next_ip;	/* hash link by IP */
91 	wet_sta_t *next_mac;	/* hash link by MAC */
92 };
93 #define WET_NUMSTAS		(1 << 8)	/* max. # clients, must be multiple of 2 */
94 #define WET_STA_HASH_SIZE	(WET_NUMSTAS/2)	/* must be <= WET_NUMSTAS */
95 #define WET_STA_HASH_IP(ip)	((ip)[3]&(WET_STA_HASH_SIZE-1))	/* hash by IP */
96 #define WET_STA_HASH_MAC(ea)	(((ea)[3]^(ea)[4]^(ea)[5])&(WET_STA_HASH_SIZE-1)) /* hash by MAC */
97 #define WET_STA_HASH_UNK	-1 /* Unknown hash */
98 #define IP_ISMULTI(ip)           (((ip) & 0xf0000000) == 0xe0000000) /* Check for multicast by IP */
99 
100 /* WET private info structure */
101 struct dhd_wet_info {
102 	/* pointer to dhdpublic info struct */
103 	dhd_pub_t *pub;
104 	/* Host addresses */
105 	uint8 ip[IPV4_ADDR_LEN];
106 	struct ether_addr mac;
107 	/* STA storage, one entry per eth. client */
108 	wet_sta_t sta[WET_NUMSTAS];
109 	/* Free sta list */
110 	wet_sta_t *stafree;
111 	/* Used sta hash by IP */
112 	wet_sta_t *stahash_ip[WET_STA_HASH_SIZE];
113 	/* Used sta hash by MAC */
114 	wet_sta_t *stahash_mac[WET_STA_HASH_SIZE];
115 };
116 
117 /* forward declarations */
118 static int wet_eth_proc(dhd_wet_info_t *weth, void *sdu,
119 	uint8 *frame, int length, int send);
120 static int wet_vtag_proc(dhd_wet_info_t *weth, void *sdu,
121 	uint8 * eh, uint8 *vtag, int length, int send);
122 static int wet_ip_proc(dhd_wet_info_t *weth, void *sdu,
123 	uint8 * eh, uint8 *iph, int length, int send);
124 static int wet_arp_proc(dhd_wet_info_t *weth, void *sdu,
125 	uint8 *eh, uint8 *arph, int length, int send);
126 static int wet_udp_proc(dhd_wet_info_t *weth,
127 	uint8 *eh, uint8 *iph, uint8 *udph, int length, int send);
128 static int wet_dhcpc_proc(dhd_wet_info_t *weth,
129 	uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send);
130 static int wet_dhcps_proc(dhd_wet_info_t *weth,
131 	uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send);
132 static int wet_sta_alloc(dhd_wet_info_t *weth, wet_sta_t **saddr);
133 static int wet_sta_update_all(dhd_wet_info_t *weth,
134 	uint8 *iaddr, struct ether_addr *eaddr, wet_sta_t **saddr);
135 static int wet_sta_update_mac(dhd_wet_info_t *weth,
136 	struct ether_addr *eaddr, wet_sta_t **saddr);
137 static int wet_sta_remove_mac_entry(dhd_wet_info_t *weth, struct ether_addr *eaddr);
138 static int wet_sta_find_ip(dhd_wet_info_t *weth,
139 	uint8 *iaddr, wet_sta_t **saddr);
140 static int wet_sta_find_mac(dhd_wet_info_t *weth,
141 	struct ether_addr *eaddr, wet_sta_t **saddr);
142 static void csum_fixup_16(uint8 *chksum,
143 	uint8 *optr, int olen, uint8 *nptr, int nlen);
144 
145 /*
146  * Protocol handler. 'ph' points to protocol specific header,
147  * for example, it points to IP header if it is IP packet.
148  */
149 typedef int (*prot_proc_t)(dhd_wet_info_t *weth, void *sdu, uint8 *eh,
150 	uint8 *ph, int length, int send);
151 /* Protocol handlers hash table - hash by ether type */
152 typedef struct prot_hdlr prot_hdlr_t;
153 struct prot_hdlr {
154 	uint16 type;		/* ether type */
155 	prot_proc_t prot_proc;
156 	prot_hdlr_t *next;	/* next proto handler that has the same hash */
157 };
158 #define WET_PROT_HASH_SIZE	(1 << 3)
159 #define WET_PROT_HASH(t)	((t)[1]&(WET_PROT_HASH_SIZE-1))
160 static prot_hdlr_t ept_tbl[] = {
161 	/* 0 */ {HTON16(ETHER_TYPE_8021Q), wet_vtag_proc, NULL}, /* 0x8100 */
162 };
163 static prot_hdlr_t prot_hash[WET_PROT_HASH_SIZE] = {
164 	/* 0 */ {HTON16(ETHER_TYPE_IP), wet_ip_proc, &ept_tbl[0]}, /* 0x0800 */
165 	/* 1 */ {0, NULL, NULL},	/* unused   */
166 	/* 2 */ {0, NULL, NULL},	/* unused   */
167 	/* 3 */ {0, NULL, NULL},	/* unused   */
168 	/* 4 */ {0, NULL, NULL},	/* unused   */
169 	/* 5 */ {0, NULL, NULL},	/* unused   */
170 	/* 6 */ {HTON16(ETHER_TYPE_ARP), wet_arp_proc, NULL},	/* 0x0806 */
171 	/* 7 */ {0, NULL, NULL},	/* unused   */
172 };
173 
174 /*
175  * IPv4 handler. 'ph' points to protocol specific header,
176  * for example, it points to UDP header if it is UDP packet.
177  */
178 typedef int (*ipv4_proc_t)(dhd_wet_info_t *weth, uint8 *eh,
179 	uint8 *iph, uint8 *ph, int length, int send);
180 /* IPv4 handlers hash table - hash by protocol type */
181 typedef struct ipv4_hdlr ipv4_hdlr_t;
182 struct ipv4_hdlr {
183 	uint8 type;	/* protocol type */
184 	ipv4_proc_t ipv4_proc;
185 	ipv4_hdlr_t *next;	/* next proto handler that has the same hash */
186 };
187 #define WET_IPV4_HASH_SIZE	(1 << 1)
188 #define WET_IPV4_HASH(p)	((p)&(WET_IPV4_HASH_SIZE-1))
189 static ipv4_hdlr_t ipv4_hash[WET_IPV4_HASH_SIZE] = {
190 	/* 0 */ {0, NULL, NULL},	/* unused   */
191 	/* 1 */ {IP_PROT_UDP, wet_udp_proc, NULL},	/* 0x11 */
192 };
193 
194 /*
195  * UDP handler. 'ph' points to protocol specific header,
196  * for example, it points to DHCP header if it is DHCP packet.
197  */
198 typedef int (*udp_proc_t)(dhd_wet_info_t *weth, uint8 *eh,
199 	uint8 *iph, uint8 *udph, uint8 *ph, int length, int send);
200 /* UDP handlers hash table - hash by port number */
201 typedef struct udp_hdlr udp_hdlr_t;
202 struct udp_hdlr {
203 	uint16 port;	/* udp dest. port */
204 	udp_proc_t udp_proc;
205 	udp_hdlr_t *next;	/* next proto handler that has the same hash */
206 };
207 #define WET_UDP_HASH_SIZE	(1 << 3)
208 #define WET_UDP_HASH(p)	((p)[1]&(WET_UDP_HASH_SIZE-1))
209 static udp_hdlr_t udp_hash[WET_UDP_HASH_SIZE] = {
210 	/* 0 */ {0, NULL, NULL},	/* unused   */
211 	/* 1 */ {0, NULL, NULL},	/* unused   */
212 	/* 2 */ {0, NULL, NULL},	/* unused   */
213 	/* 3 */ {HTON16(DHCP_PORT_SERVER), wet_dhcpc_proc, NULL}, /* 0x43 */
214 	/* 4 */ {HTON16(DHCP_PORT_CLIENT), wet_dhcps_proc, NULL}, /* 0x44 */
215 	/* 5 */ {0, NULL, NULL},	/* unused   */
216 	/* 6 */ {0, NULL, NULL},	/* unused   */
217 	/* 7 */ {0, NULL, NULL},	/* unused   */
218 };
219 
220 #define WETHWADDR(weth)	((weth)->pub->mac.octet)
221 #define WETOSH(weth)	((weth)->pub->osh)
222 
223 /* special values */
224 /* 802.3 llc/snap header */
225 static uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
226 static uint8 ipv4_bcast[IPV4_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff}; /* IP v4 broadcast address */
227 static uint8 ipv4_null[IPV4_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00}; /* IP v4 NULL address */
228 
229 dhd_wet_info_t *
dhd_get_wet_info(dhd_pub_t * pub)230 dhd_get_wet_info(dhd_pub_t *pub)
231 {
232 	dhd_wet_info_t *p;
233 	int i;
234 	p = (dhd_wet_info_t *)MALLOCZ(pub->osh, sizeof(dhd_wet_info_t));
235 	if (p == NULL) {
236 		return 0;
237 	}
238 	for (i = 0; i < WET_NUMSTAS - 1; i ++)
239 		p->sta[i].next = &p->sta[i + 1];
240 	p->stafree = &p->sta[0];
241 	p->pub = pub;
242 	return p;
243 }
244 
245 void
dhd_free_wet_info(dhd_pub_t * pub,void * wet)246 dhd_free_wet_info(dhd_pub_t *pub, void *wet)
247 {
248 	if (wet) {
249 		MFREE(pub->osh, wet, sizeof(dhd_wet_info_t));
250 	}
251 }
252 
dhd_set_wet_host_ipv4(dhd_pub_t * pub,void * parms,uint32 len)253 void dhd_set_wet_host_ipv4(dhd_pub_t *pub, void *parms, uint32 len)
254 {
255 	dhd_wet_info_t *p;
256 	p = (dhd_wet_info_t *)pub->wet_info;
257 	bcopy(parms, p->ip, len);
258 }
259 
dhd_set_wet_host_mac(dhd_pub_t * pub,void * parms,uint32 len)260 void dhd_set_wet_host_mac(dhd_pub_t *pub, void *parms, uint32 len)
261 {
262 	dhd_wet_info_t *p;
263 	p = (dhd_wet_info_t *)pub->wet_info;
264 	bcopy(parms, &p->mac, len);
265 }
266 /* process Ethernet frame */
267 /*
268 * Return:
269 *	= 0 if frame is done ok
270 *	< 0 if unable to handle the frame
271 *	> 0 if no further process
272 */
273 static int
BCMFASTPATH(wet_eth_proc)274 BCMFASTPATH(wet_eth_proc)(dhd_wet_info_t *weth, void *sdu, uint8 *frame, int length, int send)
275 {
276 	uint8 *pt = frame + ETHER_TYPE_OFFSET;
277 	uint16 type;
278 	uint8 *ph;
279 	prot_hdlr_t *phdlr;
280 	/* intercept Ethernet II frame (type > 1500) */
281 	if (length >= ETHER_HDR_LEN && (pt[0] > (ETHER_MAX_DATA >> 8) ||
282 	    (pt[0] == (ETHER_MAX_DATA >> 8) && pt[1] > (ETHER_MAX_DATA & 0xff))))
283 		;
284 	/* intercept 802.3 LLC/SNAP frame (type <= 1500) */
285 	else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN) {
286 		uint8 *llc = frame + ETHER_HDR_LEN;
287 		if (bcmp(llc_snap_hdr, llc, SNAP_HDR_LEN))
288 			return 0;
289 		pt = llc + SNAP_HDR_LEN;
290 	}
291 	/* frame too short bail out */
292 	else {
293 		DHD_ERROR(("wet_eth_proc: %s short eth frame, ignored\n",
294 			send ? "send" : "recv"));
295 		return -1;
296 	}
297 	ph = pt + ETHER_TYPE_LEN;
298 	length -= ph - frame;
299 
300 	/* Call protocol specific handler to process frame. */
301 	type = *(uint16 *)pt;
302 
303 	for (phdlr = &prot_hash[WET_PROT_HASH(pt)];
304 	     phdlr != NULL; phdlr = phdlr->next) {
305 		if (phdlr->type != type || !phdlr->prot_proc)
306 			continue;
307 		return (phdlr->prot_proc)(weth, sdu, frame, ph, length, send);
308 	}
309 
310 	if (!bcmp(WETHWADDR(weth), frame + ETHER_SRC_OFFSET, ETHER_ADDR_LEN)) {
311 		return 0;
312 	}
313 	else {
314 		DHD_INFO(("%s: %s unknown type (0x%X), ignored %s\n",
315 			__FUNCTION__, send ? "send" : "recv", type,
316 			(type == 0xDD86) ? "IPv6":""));
317 		/* ignore unsupported protocol from different mac addr than us */
318 		return BCME_UNSUPPORTED;
319 	}
320 }
321 
322 /* process 8021p/Q tagged frame */
323 /*
324 * Return:
325 *	= 0 if frame is done ok
326 *	< 0 if unable to handle the frame
327 *	> 0 if no further process
328 */
329 static int
BCMFASTPATH(wet_vtag_proc)330 BCMFASTPATH(wet_vtag_proc)(dhd_wet_info_t *weth, void *sdu,
331 	uint8 * eh, uint8 *vtag, int length, int send)
332 {
333 	uint16 type;
334 	uint8 *pt;
335 	prot_hdlr_t *phdlr;
336 
337 	/* check minimum length */
338 	if (length < ETHERVLAN_HDR_LEN) {
339 		DHD_ERROR(("wet_vtag_proc: %s short VLAN frame, ignored\n",
340 			send ? "send" : "recv"));
341 		return -1;
342 	}
343 
344 	/*
345 	 * FIXME: check recursiveness to prevent stack from overflow
346 	 * in case someone sent frames 8100xxxxxxxx8100xxxxxxxx...
347 	 */
348 
349 	/* Call protocol specific handler to process frame. */
350 	type = *(uint16 *)(pt = vtag + VLAN_TAG_LEN);
351 
352 	for (phdlr = &prot_hash[WET_PROT_HASH(pt)];
353 	     phdlr != NULL; phdlr = phdlr->next) {
354 		if (phdlr->type != type || !phdlr->prot_proc)
355 			continue;
356 		return (phdlr->prot_proc)(weth, sdu, eh,
357 			pt + ETHER_TYPE_LEN, length, send);
358 	}
359 
360 	return 0;
361 }
362 
363 /* process IP frame */
364 /*
365 * Return:
366 *	= 0 if frame is done ok
367 *	< 0 if unable to handle the frame
368 *       > 0 if no further process
369 */
370 static int
BCMFASTPATH(wet_ip_proc)371 BCMFASTPATH(wet_ip_proc)(dhd_wet_info_t *weth, void *sdu,
372 		uint8 *eh, uint8 *iph, int length, int send)
373 {
374 	uint8 type;
375 	int ihl;
376 	wet_sta_t *sta;
377 	ipv4_hdlr_t *iphdlr;
378 	uint8 *iaddr;
379 	struct ether_addr *ea = NULL;
380 	int ret, ea_off = 0;
381 	char eabuf[ETHER_ADDR_STR_LEN];
382 	BCM_REFERENCE(eabuf);
383 
384 	/* IPv4 only */
385 	if (length < 1 || (IP_VER(iph) != IP_VER_4)) {
386 		DHD_INFO(("wet_ip_proc: %s non IPv4 frame, ignored\n",
387 			send ? "send" : "recv"));
388 		return -1;
389 	}
390 
391 	ihl = IPV4_HLEN(iph);
392 
393 	/* minimum length */
394 	if (length < ihl) {
395 		DHD_ERROR(("wet_ip_proc: %s short IPv4 frame, ignored\n",
396 		send ? "send" : "recv"));
397 		return -1;
398 	}
399 
400 	/* protocol specific handling */
401 	type = IPV4_PROT(iph);
402 	for (iphdlr = &ipv4_hash[WET_IPV4_HASH(type)];
403 			iphdlr; iphdlr = iphdlr->next) {
404 		if (iphdlr->type != type || !iphdlr->ipv4_proc)
405 			continue;
406 		if ((ret = (iphdlr->ipv4_proc)(weth, eh,
407 			iph, iph + ihl, length - ihl, send)))
408 			return ret;
409 	}
410 
411 	/* generic IP packet handling
412 	 * Replace source MAC in Ethernet header with wireless's and
413 	 * keep track of IP MAC mapping when sending frame.
414 	 */
415 	if (send) {
416 		uint32 iaddr_dest, iaddr_src;
417 		bool wet_table_upd = TRUE;
418 		iaddr = iph + IPV4_SRC_IP_OFFSET;
419 		iaddr_dest = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
420 		iaddr_src = ntoh32(*(uint32 *)(iaddr));
421 
422 		/* Do not process and update knowledge base on receipt of a local IP
423 		 * multicast frame
424 		 */
425 		if (IP_ISMULTI(iaddr_dest) && !iaddr_src) {
426 			DHD_INFO(("recv multicast frame from %s.Don't update hash table\n",
427 				bcm_ether_ntoa((struct ether_addr*)
428 				(eh + ETHER_SRC_OFFSET), eabuf)));
429 			wet_table_upd = FALSE;
430 		}
431 		if (wet_table_upd && wet_sta_update_all(weth, iaddr,
432 				(struct ether_addr*)(eh + ETHER_SRC_OFFSET), &sta) < 0) {
433 			DHD_INFO(("wet_ip_proc: unable to update STA %u.%u.%u.%u %s\n",
434 				iaddr[0], iaddr[1], iaddr[2], iaddr[3],
435 				bcm_ether_ntoa(
436 				(struct ether_addr*)(eh + ETHER_SRC_OFFSET), eabuf)));
437 			return -1;
438 		}
439 		ea = (struct ether_addr *)WETHWADDR(weth);
440 		ea_off = ETHER_SRC_OFFSET;
441 		eacopy(ea, eh + ea_off);
442 	}
443 	/*
444 	 * Replace dest MAC in Ethernet header using the found one
445 	 * when receiving frame.
446 	 */
447 	/* no action for received bcast/mcast ethernet frame */
448 	else if (!ETHER_ISMULTI(eh)) {
449 		iaddr = iph + IPV4_DEST_IP_OFFSET;
450 		if (wet_sta_find_ip(weth, iaddr, &sta) < 0) {
451 			DHD_ERROR(("wet_ip_proc: unable to find STA %u.%u.%u.%u\n",
452 				iaddr[0], iaddr[1], iaddr[2], iaddr[3]));
453 			return -1;
454 		}
455 		ea = &sta->mac;
456 		ea_off = ETHER_DEST_OFFSET;
457 		eacopy(ea, eh + ea_off);
458 	}
459 
460 	return 0;
461 }
462 
463 /* process ARP frame - ARP proxy */
464 /*
465  * Return:
466  *	= 0 if frame is done ok
467  *	< 0 if unable to handle the frame
468  *       > 0 if no further process
469  */
470 static int
BCMFASTPATH(wet_arp_proc)471 BCMFASTPATH(wet_arp_proc)(dhd_wet_info_t *weth, void *sdu,
472 		uint8 *eh, uint8 *arph, int length, int send)
473 {
474 	wet_sta_t *sta;
475 	uint8 *iaddr;
476 	char eabuf[ETHER_ADDR_STR_LEN];
477 	BCM_REFERENCE(eabuf);
478 
479 	/*
480 	 * FIXME: validate ARP header:
481 	 *  h/w Ethernet 2, proto IP x800, h/w addr size 6, proto addr size 4.
482 	 */
483 
484 	/*
485 	 * Replace source MAC in Ethernet header as well as source MAC in
486 	 * ARP protocol header when processing frame sent.
487 	 */
488 	if (send) {
489 		iaddr = arph + ARP_SRC_IP_OFFSET;
490 		if (wet_sta_update_all(weth, iaddr,
491 				(struct ether_addr*)(eh + ETHER_SRC_OFFSET), &sta) < 0) {
492 			DHD_INFO(("wet_arp_proc: unable to update STA %u.%u.%u.%u %s\n",
493 					iaddr[0], iaddr[1], iaddr[2], iaddr[3],
494 					bcm_ether_ntoa(
495 					(struct ether_addr*)(eh + ETHER_SRC_OFFSET), eabuf)));
496 			return -1;
497 		}
498 		bcopy(WETHWADDR(weth), eh + ETHER_SRC_OFFSET, ETHER_ADDR_LEN);
499 		bcopy(WETHWADDR(weth), arph+ARP_SRC_ETH_OFFSET, ETHER_ADDR_LEN);
500 	}
501 	/*
502 	 * Replace dest MAC in Ethernet header as well as dest MAC in
503 	 * ARP protocol header when processing frame recv'd. Process ARP
504 	 * replies and Unicast ARP requests.
505 	 */
506 	else if ((*(uint16 *)(arph + ARP_OPC_OFFSET) == HTON16(ARP_OPC_REPLY)) ||
507 		((*(uint16 *)(arph + ARP_OPC_OFFSET) == HTON16(ARP_OPC_REQUEST)) &&
508 		(!ETHER_ISMULTI(eh)))) {
509 		iaddr = arph + ARP_TGT_IP_OFFSET;
510 		if (wet_sta_find_ip(weth, iaddr, &sta) < 0) {
511 			DHD_INFO(("wet_arp_proc: unable to find STA %u.%u.%u.%u\n",
512 				iaddr[0], iaddr[1], iaddr[2], iaddr[3]));
513 			return -1;
514 		}
515 		bcopy(&sta->mac, arph + ARP_TGT_ETH_OFFSET, ETHER_ADDR_LEN);
516 		bcopy(&sta->mac, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
517 	}
518 
519 	return 0;
520 }
521 
522 /* process UDP frame */
523 /*
524  * Return:
525  *	= 0 if frame is done ok
526  *	< 0 if unable to handle the frame
527  *       > 0 if no further process
528  */
529 static int
BCMFASTPATH(wet_udp_proc)530 BCMFASTPATH(wet_udp_proc)(dhd_wet_info_t *weth,
531 		uint8 *eh, uint8 *iph, uint8 *udph, int length, int send)
532 {
533 	udp_hdlr_t *udphdlr;
534 	uint16 port;
535 
536 	/* check frame length, at least UDP_HDR_LEN */
537 	if ((length -= UDP_HDR_LEN) < 0) {
538 		DHD_ERROR(("wet_udp_proc: %s short UDP frame, ignored\n",
539 			send ? "send" : "recv"));
540 		return -1;
541 	}
542 
543 	/*
544 	 * Unfortunately we must spend some time here to deal with
545 	 * some higher layer protocol special processings.
546 	 * See individual handlers for protocol specific details.
547 	 */
548 	port = *(uint16 *)(udph + UDP_DEST_PORT_OFFSET);
549 	for (udphdlr = &udp_hash[WET_UDP_HASH((uint8 *)&port)];
550 			udphdlr; udphdlr = udphdlr->next) {
551 		if (udphdlr->port != port || !udphdlr->udp_proc)
552 			continue;
553 		return (udphdlr->udp_proc)(weth, eh, iph, udph,
554 				udph + UDP_HDR_LEN, length, send);
555 	}
556 
557 	return 0;
558 }
559 
560 /*
561  * DHCP is a 'complex' protocol for WET, mainly because it
562  * uses its protocol body to convey IP/MAC info. It is impossible
563  * to forward frames correctly back and forth without looking
564  * into the DHCP's body and interpreting it. See RFC2131 sect.
565  * 4.1 'Constructing and sending DHCP messages' for details
566  * of using/parsing various fields in the body.
567  *
568  * DHCP pass through:
569  *
570  *       Must alter DHCP flag to broadcast so that the server
571  *       can reply with the broadcast address before we can
572  *	 provide DHCP relay functionality. Otherwise the DHCP
573  *       server will send DHCP replies using the DHCP client's
574  *       MAC address. Such replies will not be delivered simply
575  *       because:
576  *
577  *         1. The AP's bridge will not forward the replies back to
578  *         this device through the wireless link because it does not
579  *         know such node exists on this link. The bridge's forwarding
580  *         table on the AP will have this device's MAC address only.
581  *         It does not know anything else behind this device.
582  *
583  *         2. The AP's wireless driver won't allow such frames out
584  *         either even if they made their way out the AP's bridge
585  *         through the bridge's DLF broadcasting because there is
586  *         no such STA associated with the AP.
587  *
588  *         3. This device's MAC won't allow such frames pass
589  *         through in non-promiscuous mode even when they made
590  *         their way out of the AP's wireless interface somehow.
591  *
592  * DHCP relay:
593  *
594  *       Once the WET is configured with the host MAC address it can
595  *       relay the host request as if it were sent from WET itself.
596  *
597  *       Once the WET is configured with the host IP address it can
598  *       pretend to be the host and act as a relay agent.
599  *
600  * process DHCP client frame (client to server, or server to relay agent)
601  * Return:
602  *	= 0 if frame is done ok
603  *	< 0 if unable to handle the frame
604  *      > 0 if no further process
605  */
606 static int
BCMFASTPATH(wet_dhcpc_proc)607 BCMFASTPATH(wet_dhcpc_proc)(dhd_wet_info_t *weth,
608 		uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send)
609 {
610 	wet_sta_t *sta;
611 	uint16 flags;
612 	char eabuf[ETHER_ADDR_STR_LEN];
613 	uint16 port;
614 	uint8 *ipv4;
615 	const struct ether_addr *ether;
616 	BCM_REFERENCE(eabuf);
617 
618 	/*
619 	 * FIXME: validate DHCP body:
620 	 * htype Ethernet 1, hlen Ethernet 6, frame length at least 242.
621 	 */
622 
623 	/* only interested in requests when sending to server */
624 	if (send && *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REQUEST)
625 		return 0;
626 	/* only interested in replies when receiving from server as a relay agent */
627 	if (!send && *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
628 		return 0;
629 
630 	/* send request */
631 	if (send) {
632 		/* find existing or alloc new IP/MAC mapping entry */
633 		if (wet_sta_update_mac(weth,
634 				(struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) {
635 			DHD_INFO(("wet_dhcpc_proc: unable to update STA %s\n",
636 				bcm_ether_ntoa(
637 				(struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf)));
638 			return -1;
639 		}
640 		bcopy(dhcp + DHCP_FLAGS_OFFSET, &flags, DHCP_FLAGS_LEN);
641 		/* We can always relay the host's request when we know its MAC addr. */
642 		if (!ETHER_ISNULLADDR(weth->mac.octet) &&
643 				!bcmp(dhcp + DHCP_CHADDR_OFFSET, &weth->mac, ETHER_ADDR_LEN)) {
644 			/* replace chaddr with host's MAC */
645 			csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
646 					dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN,
647 					WETHWADDR(weth), ETHER_ADDR_LEN);
648 			bcopy(WETHWADDR(weth), dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN);
649 			/* force reply to be unicast */
650 			flags &= ~HTON16(DHCP_FLAG_BCAST);
651 		}
652 		/* We can relay other clients' requests when we know the host's IP addr. */
653 		else if (!IPV4_ADDR_NULL(weth->ip)) {
654 			/* we can only handle the first hop otherwise drop it */
655 			if (!IPV4_ADDR_NULL(dhcp + DHCP_GIADDR_OFFSET)) {
656 				DHD_INFO(("wet_dhcpc_proc: not first hop, ignored\n"));
657 				return -1;
658 			}
659 			/* replace giaddr with host's IP */
660 			csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
661 					dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN,
662 					weth->ip, IPV4_ADDR_LEN);
663 			bcopy(weth->ip, dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN);
664 			/* force reply to be unicast */
665 			flags &= ~HTON16(DHCP_FLAG_BCAST);
666 		}
667 		/*
668 		 * Request comes in when we don't know the host's MAC and/or IP
669 		 * addresses hence we can't relay the request. We must notify the
670 		 * server of our addressing limitation by turning on the broadcast
671 		 * bit at this point as what the function comments point out.
672 		 */
673 		else
674 			flags |= HTON16(DHCP_FLAG_BCAST);
675 		/* update flags */
676 		bcopy(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN);
677 		if (flags != *(uint16 *)sta->flags) {
678 			csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
679 					dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN,
680 					(uint8 *)&flags, DHCP_FLAGS_LEN);
681 			bcopy((uint8 *)&flags, dhcp + DHCP_FLAGS_OFFSET,
682 					DHCP_FLAGS_LEN);
683 		}
684 		/* replace the Ethernet source MAC with ours */
685 		bcopy(WETHWADDR(weth), eh + ETHER_SRC_OFFSET, ETHER_ADDR_LEN);
686 	}
687 	/* relay recv'd reply to its destiny */
688 	else if (!IPV4_ADDR_NULL(weth->ip) &&
689 			!bcmp(dhcp + DHCP_GIADDR_OFFSET, weth->ip, IPV4_ADDR_LEN)) {
690 		/* find IP/MAC mapping entry */
691 		if (wet_sta_find_mac(weth,
692 		(struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) {
693 			DHD_INFO(("wet_dhcpc_proc: unable to find STA %s\n",
694 				bcm_ether_ntoa(
695 				(struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf)));
696 			return -1;
697 		}
698 		/*
699 		 * XXX the following code works for the first hop only
700 		 */
701 		/* restore the DHCP giaddr with its original */
702 		csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
703 				dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN,
704 				ipv4_null, IPV4_ADDR_LEN);
705 		bcopy(ipv4_null, dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN);
706 		/* restore the original client's dhcp flags */
707 		if (bcmp(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN)) {
708 			csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
709 					dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN,
710 					sta->flags, DHCP_FLAGS_LEN);
711 			bcopy(sta->flags, dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN);
712 		}
713 		/* replace the dest UDP port with DHCP client port */
714 		port = HTON16(DHCP_PORT_CLIENT);
715 		csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
716 				udph + UDP_DEST_PORT_OFFSET, UDP_PORT_LEN,
717 				(uint8 *)&port, UDP_PORT_LEN);
718 		bcopy((uint8 *)&port, udph + UDP_DEST_PORT_OFFSET, UDP_PORT_LEN);
719 		/* replace the dest MAC & IP addr with the client's */
720 		if (*(uint16 *)sta->flags & HTON16(DHCP_FLAG_BCAST)) {
721 			ipv4 = ipv4_bcast;
722 			ether = &ether_bcast;
723 		}
724 		else {
725 			ipv4 = dhcp + DHCP_YIADDR_OFFSET;
726 			ether = &sta->mac;
727 		}
728 		csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
729 				iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN,
730 				ipv4, IPV4_ADDR_LEN);
731 		csum_fixup_16(iph + IPV4_CHKSUM_OFFSET,
732 				iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN,
733 				ipv4, IPV4_ADDR_LEN);
734 		bcopy(ipv4, iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN);
735 		bcopy(ether, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
736 	}
737 	/* it should not recv non-relay reply at all, but just in case */
738 	else {
739 		DHD_INFO(("wet_dhcpc_proc: ignore recv'd frame from %s\n",
740 		bcm_ether_ntoa((struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf)));
741 		return -1;
742 	}
743 
744 	/* no further processing! */
745 	return 1;
746 }
747 
748 /* process DHCP server frame (server to client) */
749 /*
750  * Return:
751  *	= 0 if frame is done ok
752  *	< 0 if unable to handle the frame
753  *      > 0 if no further process
754  */
755 static int
BCMFASTPATH(wet_dhcps_proc)756 BCMFASTPATH(wet_dhcps_proc)(dhd_wet_info_t *weth,
757 	uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send)
758 {
759 	wet_sta_t *sta;
760 	char eabuf[ETHER_ADDR_STR_LEN];
761 	BCM_REFERENCE(eabuf);
762 
763 	/*
764 	 * FIXME: validate DHCP body:
765 	 *  htype Ethernet 1, hlen Ethernet 6, frame length at least 242.
766 	 */
767 
768 	/* only interested in replies when receiving from server */
769 	if (send || *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
770 		return 0;
771 
772 	/* find IP/MAC mapping entry */
773 	if (wet_sta_find_mac(weth, (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) {
774 		DHD_INFO(("wet_dhcps_proc: unable to find STA %s\n",
775 		bcm_ether_ntoa((struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf)));
776 		return -1;
777 	}
778 	/* relay the reply to the host when we know the host's MAC addr */
779 	if (!ETHER_ISNULLADDR(weth->mac.octet) &&
780 			!bcmp(dhcp + DHCP_CHADDR_OFFSET, WETHWADDR(weth), ETHER_ADDR_LEN)) {
781 		csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
782 				dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN,
783 				weth->mac.octet, ETHER_ADDR_LEN);
784 		bcopy(&weth->mac, dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN);
785 	}
786 	/* restore the original client's dhcp flags if necessary */
787 	if (bcmp(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN)) {
788 		csum_fixup_16(udph + UDP_CHKSUM_OFFSET,
789 				dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN,
790 				sta->flags, DHCP_FLAGS_LEN);
791 		bcopy(sta->flags, dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN);
792 	}
793 	/* replace the dest MAC with that of client's */
794 	if (*(uint16 *)sta->flags & HTON16(DHCP_FLAG_BCAST))
795 		bcopy((const uint8 *)&ether_bcast, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
796 	else
797 		bcopy(&sta->mac, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
798 
799 	/* no further processing! */
800 	return 1;
801 }
802 
803 /* alloc IP/MAC mapping entry
804  * Returns 0 if succeeded; < 0 otherwise.
805  */
806 static int
wet_sta_alloc(dhd_wet_info_t * weth,wet_sta_t ** saddr)807 wet_sta_alloc(dhd_wet_info_t *weth, wet_sta_t **saddr)
808 {
809 	wet_sta_t *sta;
810 
811 	/* allocate a new one */
812 	if (!weth->stafree) {
813 		DHD_INFO(("wet_sta_alloc: no room for another STA\n"));
814 		return -1;
815 	}
816 	sta = weth->stafree;
817 	weth->stafree = sta->next;
818 
819 	/* init them just in case */
820 	sta->next = NULL;
821 	sta->next_ip = NULL;
822 	sta->next_mac = NULL;
823 
824 	*saddr = sta;
825 	return 0;
826 }
827 
828 /* update IP/MAC mapping entry and hash
829  * Returns 0 if succeeded; < 0 otherwise.
830  */
831 static int
BCMFASTPATH(wet_sta_update_all)832 BCMFASTPATH(wet_sta_update_all)(dhd_wet_info_t *weth, uint8 *iaddr, struct ether_addr *eaddr,
833 		wet_sta_t **saddr)
834 {
835 	wet_sta_t *sta;
836 	int i;
837 	char eabuf[ETHER_ADDR_STR_LEN];
838 	BCM_REFERENCE(eabuf);
839 
840 	/* find the existing one and remove it from the old IP hash link */
841 	if (!wet_sta_find_mac(weth, eaddr, &sta)) {
842 		i = WET_STA_HASH_IP(sta->ip);
843 		if (bcmp(sta->ip, iaddr, IPV4_ADDR_LEN)) {
844 			wet_sta_t *sta2, **next;
845 			for (next = &weth->stahash_ip[i], sta2 = *next;
846 			sta2; sta2 = sta2->next_ip) {
847 				if (sta2 == sta)
848 					break;
849 				next = &sta2->next_ip;
850 			}
851 			if (sta2) {
852 				*next = sta2->next_ip;
853 				sta2->next_ip = NULL;
854 			}
855 			i = WET_STA_HASH_UNK;
856 		}
857 	}
858 	/* allocate a new one and hash it by MAC */
859 	else if (!wet_sta_alloc(weth, &sta)) {
860 		i = WET_STA_HASH_MAC(eaddr->octet);
861 		bcopy(eaddr, &sta->mac, ETHER_ADDR_LEN);
862 		sta->next_mac = weth->stahash_mac[i];
863 		weth->stahash_mac[i] = sta;
864 		i = WET_STA_HASH_UNK;
865 	}
866 	/* bail out if we can't find nor create any */
867 	else {
868 		DHD_INFO(("wet_sta_update_all: unable to alloc STA %u.%u.%u.%u %s\n",
869 		iaddr[0], iaddr[1], iaddr[2], iaddr[3],
870 		bcm_ether_ntoa(eaddr, eabuf)));
871 		return -1;
872 	}
873 
874 	/* update IP and hash by new IP */
875 	if (i == WET_STA_HASH_UNK) {
876 		i = WET_STA_HASH_IP(iaddr);
877 		bcopy(iaddr, sta->ip, IPV4_ADDR_LEN);
878 		sta->next_ip = weth->stahash_ip[i];
879 		weth->stahash_ip[i] = sta;
880 
881 		/* start here and look for other entries with same IP address */
882 		{
883 			wet_sta_t *sta2, *prev;
884 			prev = sta;
885 			for (sta2 = sta->next_ip;	sta2; sta2 = sta2->next_ip) {
886 				/* does this entry have the same IP address? */
887 				if (!bcmp(sta->ip, sta2->ip, IPV4_ADDR_LEN)) {
888 					/* sta2 currently points to the entry we need to remove */
889 					/* fix next pointers */
890 					prev->next_ip = sta2->next_ip;
891 					sta2->next_ip = NULL;
892 					/* now we need to find this guy in the MAC list and
893 					   remove it from that list too.
894 					   */
895 					wet_sta_remove_mac_entry(weth, &sta2->mac);
896 					/* entry should be completely out of the table now,
897 					   add it to the free list
898 					   */
899 					memset(sta2, 0, sizeof(wet_sta_t));
900 					sta2->next = weth->stafree;
901 					weth->stafree = sta2;
902 
903 					sta2 = prev;
904 				}
905 				prev = sta2;
906 			}
907 		}
908 	}
909 
910 	*saddr = sta;
911 	return 0;
912 }
913 
914 /* update IP/MAC mapping entry and hash */
915 static int
BCMFASTPATH(wet_sta_update_mac)916 BCMFASTPATH(wet_sta_update_mac)(dhd_wet_info_t *weth, struct ether_addr *eaddr, wet_sta_t **saddr)
917 {
918 	wet_sta_t *sta;
919 	int i;
920 	char eabuf[ETHER_ADDR_STR_LEN];
921 	BCM_REFERENCE(eabuf);
922 
923 	/* find the existing one */
924 	if (!wet_sta_find_mac(weth, eaddr, &sta))
925 		;
926 	/* allocate a new one and hash it */
927 	else if (!wet_sta_alloc(weth, &sta)) {
928 		i = WET_STA_HASH_MAC(eaddr->octet);
929 		bcopy(eaddr, &sta->mac, ETHER_ADDR_LEN);
930 		sta->next_mac = weth->stahash_mac[i];
931 		weth->stahash_mac[i] = sta;
932 	}
933 	/* bail out if we can't find nor create any */
934 	else {
935 		DHD_INFO(("wet_sta_update_mac: unable to alloc STA %s\n",
936 		bcm_ether_ntoa(eaddr, eabuf)));
937 		return -1;
938 	}
939 
940 	*saddr = sta;
941 	return 0;
942 }
943 
944 /*  Remove MAC entry from hash list
945  *  NOTE:  This only removes the entry matching "eaddr" from the MAC
946  *  list.  The caller needs to remove from the IP list and
947  *  put back onto the free list to completely remove the entry
948  *  from the WET table.
949  */
950 static int
BCMFASTPATH(wet_sta_remove_mac_entry)951 BCMFASTPATH(wet_sta_remove_mac_entry)(dhd_wet_info_t *weth, struct ether_addr *eaddr)
952 {
953 	wet_sta_t *sta, *prev;
954 	int i = WET_STA_HASH_MAC(eaddr->octet);
955 	char eabuf[ETHER_ADDR_STR_LEN];
956 	int found = 0;
957 	BCM_REFERENCE(eabuf);
958 
959 	/* find the existing one */
960 	for (sta = prev = weth->stahash_mac[i]; sta; sta = sta->next_mac) {
961 		if (!bcmp(&sta->mac, eaddr, ETHER_ADDR_LEN)) {
962 			found = 1;
963 			break;
964 		}
965 		prev = sta;
966 	}
967 
968 	/* bail out if we can't find */
969 	if (!found) {
970 		DHD_INFO(("wet_sta_remove_mac_entry: unable to find STA %s entry\n",
971 		bcm_ether_ntoa(eaddr, eabuf)));
972 		return -1;
973 	}
974 
975 	/* fix the list */
976 	if (prev == sta)
977 		weth->stahash_mac[i] = sta->next_mac; /* removing first entry in this bucket */
978 	else
979 		prev->next_mac = sta->next_mac;
980 
981 	return 0;
982 }
983 
984 /* find IP/MAC mapping entry by IP address
985  * Returns 0 if succeeded; < 0 otherwise.
986  */
987 static int
BCMFASTPATH(wet_sta_find_ip)988 BCMFASTPATH(wet_sta_find_ip)(dhd_wet_info_t *weth, uint8 *iaddr, wet_sta_t **saddr)
989 {
990 	int i = WET_STA_HASH_IP(iaddr);
991 	wet_sta_t *sta;
992 
993 	/* find the existing one by IP */
994 	for (sta = weth->stahash_ip[i]; sta; sta = sta->next_ip) {
995 		if (bcmp(sta->ip, iaddr, IPV4_ADDR_LEN))
996 			continue;
997 		*saddr = sta;
998 		return 0;
999 	}
1000 
1001 	/* sta has not been learned */
1002 	DHD_INFO(("wet_sta_find_ip: unable to find STA %u.%u.%u.%u\n",
1003 		iaddr[0], iaddr[1], iaddr[2], iaddr[3]));
1004 	return -1;
1005 }
1006 
1007 /* find IP/MAC mapping entry by MAC address
1008  * Returns 0 if succeeded; < 0 otherwise.
1009  */
1010 static int
BCMFASTPATH(wet_sta_find_mac)1011 BCMFASTPATH(wet_sta_find_mac)(dhd_wet_info_t *weth, struct ether_addr *eaddr, wet_sta_t **saddr)
1012 {
1013 	int i = WET_STA_HASH_MAC(eaddr->octet);
1014 	wet_sta_t *sta;
1015 	char eabuf[ETHER_ADDR_STR_LEN];
1016 	BCM_REFERENCE(eabuf);
1017 
1018 	/* find the existing one by MAC */
1019 	for (sta = weth->stahash_mac[i]; sta; sta = sta->next_mac) {
1020 		if (bcmp(&sta->mac, eaddr, ETHER_ADDR_LEN))
1021 			continue;
1022 		*saddr = sta;
1023 		return 0;
1024 	}
1025 
1026 	/* sta has not been learnt */
1027 	DHD_INFO(("wet_sta_find_mac: unable to find STA %s\n",
1028 		bcm_ether_ntoa(eaddr, eabuf)));
1029 	return -1;
1030 }
1031 
1032 /* Adjust 16 bit checksum - taken from RFC 3022.
1033  *
1034  *   The algorithm below is applicable only for even offsets (i.e., optr
1035  *   below must be at an even offset from start of header) and even lengths
1036  *   (i.e., olen and nlen below must be even).
1037  */
1038 static void
BCMFASTPATH(csum_fixup_16)1039 BCMFASTPATH(csum_fixup_16)(uint8 *chksum, uint8 *optr, int olen, uint8 *nptr, int nlen)
1040 {
1041 	long x, old, new;
1042 
1043 	ASSERT(!((uintptr_t)optr&1) && !(olen&1));
1044 	ASSERT(!((uintptr_t)nptr&1) && !(nlen&1));
1045 
1046 	x = (chksum[0]<< 8)+chksum[1];
1047 	if (!x)
1048 		return;
1049 	x = ~x & 0xFFFF;
1050 	while (olen)
1051 	{
1052 		old = (optr[0]<< 8)+optr[1]; optr += 2;
1053 		x -= old & 0xffff;
1054 		if (x <= 0) { x--; x &= 0xffff; }
1055 		olen -= 2;
1056 	}
1057 	while (nlen)
1058 	{
1059 		new = (nptr[0]<< 8)+nptr[1]; nptr += 2;
1060 		x += new & 0xffff;
1061 		if (x & 0x10000) { x++; x &= 0xffff; }
1062 		nlen -= 2;
1063 	}
1064 	x = ~x & 0xFFFF;
1065 	chksum[0] = (uint8)(x >> 8); chksum[1] = (uint8)x;
1066 }
1067 
1068 /* Process frames in transmit direction by replacing source MAC with
1069  * wireless's and keep track of IP MAC address mapping table.
1070  * Return:
1071  *	= 0 if frame is done ok;
1072  *	< 0 if unable to handle the frame;
1073  *
1074  * To avoid other interfaces to see our changes specially
1075  * changes to broadcast frame which definitely will be seen by
1076  * other bridged interfaces we must copy the frame to our own
1077  * buffer, modify it, and then sent it.
1078  * Return the new sdu in 'new'.
1079  */
1080 int
BCMFASTPATH(dhd_wet_send_proc)1081 BCMFASTPATH(dhd_wet_send_proc)(void *wet, void *sdu, void **new)
1082 {
1083 	dhd_wet_info_t *weth = (dhd_wet_info_t *)wet;
1084 	uint8 *frame = PKTDATA(WETOSH(weth), sdu);
1085 	int length = PKTLEN(WETOSH(weth), sdu);
1086 	void *pkt = sdu;
1087 
1088 	/*
1089 	 * FIXME: need to tell if buffer is shared and only
1090 	 * do copy on shared buffer.
1091 	 */
1092 	/*
1093 	 * copy broadcast/multicast frame to our own packet
1094 	 * otherwise we will screw up others because we alter
1095 	 * the frame content.
1096 	 */
1097 	if (length < ETHER_HDR_LEN) {
1098 		DHD_ERROR(("dhd_wet_send_proc: unable to process short frame\n"));
1099 		return -1;
1100 	}
1101 	if (ETHER_ISMULTI(frame)) {
1102 		length = pkttotlen(WETOSH(weth), sdu);
1103 		if (!(pkt = PKTGET(WETOSH(weth), length, TRUE))) {
1104 			DHD_ERROR(("dhd_wet_send_proc: unable to alloc, dropped\n"));
1105 			return -1;
1106 		}
1107 		frame = PKTDATA(WETOSH(weth), pkt);
1108 		pktcopy(WETOSH(weth), sdu, 0, length, frame);
1109 		/* Transfer priority */
1110 		PKTSETPRIO(pkt, PKTPRIO(sdu));
1111 		PKTFREE(WETOSH(weth), sdu, TRUE);
1112 		PKTSETLEN(WETOSH(weth), pkt, length);
1113 	}
1114 	*new = pkt;
1115 
1116 	/* process frame */
1117 	return wet_eth_proc(weth, sdu, frame, length, 1) < 0 ? -1 : 0;
1118 }
1119 
1120 /*
1121  * Process frames in receive direction by replacing destination MAC with
1122  * the one found in IP MAC address mapping table.
1123  * Return:
1124  *	= 0 if frame is done ok;
1125  *	< 0 if unable to handle the frame;
1126  */
1127 int
BCMFASTPATH(dhd_wet_recv_proc)1128 BCMFASTPATH(dhd_wet_recv_proc)(void *wet, void *sdu)
1129 {
1130 	dhd_wet_info_t *weth = (dhd_wet_info_t *)wet;
1131 	/* process frame */
1132 	return wet_eth_proc(weth, sdu, PKTDATA(WETOSH(weth), sdu),
1133 			PKTLEN(WETOSH(weth), sdu), 0) < 0 ? -1 : 0;
1134 }
1135 
1136 /* Delete WET Database */
1137 void
dhd_wet_sta_delete_list(dhd_pub_t * dhd_pub)1138 dhd_wet_sta_delete_list(dhd_pub_t *dhd_pub)
1139 {
1140 	wet_sta_t *sta;
1141 	int i, j;
1142 	dhd_wet_info_t *weth = dhd_pub->wet_info;
1143 
1144 	for (i = 0; i < WET_STA_HASH_SIZE; i ++) {
1145 		for (sta = weth->stahash_mac[i]; sta; sta = sta->next_mac) {
1146 			wet_sta_t *sta2, **next;
1147 			j = WET_STA_HASH_IP(sta->ip);
1148 			for (next = &weth->stahash_ip[j], sta2 = *next;
1149 					sta2; sta2 = sta2->next_ip) {
1150 				if (sta2 == sta)
1151 					break;
1152 				next = &sta2->next_ip;
1153 			}
1154 			if (sta2) {
1155 				*next = sta2->next_ip;
1156 				sta2->next_ip = NULL;
1157 			}
1158 			j = WET_STA_HASH_UNK;
1159 
1160 			wet_sta_remove_mac_entry(weth, &sta->mac);
1161 			memset(sta, 0, sizeof(wet_sta_t));
1162 		}
1163 	}
1164 }
1165 void
dhd_wet_dump(dhd_pub_t * dhdp,struct bcmstrbuf * b)1166 dhd_wet_dump(dhd_pub_t *dhdp, struct bcmstrbuf *b)
1167 {
1168 	char eabuf[ETHER_ADDR_STR_LEN];
1169 	wet_sta_t *sta;
1170 	int i;
1171 	dhd_wet_info_t *weth = dhdp->wet_info;
1172 
1173 	bcm_bprintf(b, "Host MAC: %s\n", bcm_ether_ntoa(&weth->mac, eabuf));
1174 	bcm_bprintf(b, "Host IP: %u.%u.%u.%u\n",
1175 			weth->ip[0], weth->ip[1], weth->ip[2], weth->ip[3]);
1176 	bcm_bprintf(b, "Entry\tEnetAddr\t\tInetAddr\n");
1177 	for (i = 0; i < WET_NUMSTAS; i ++) {
1178 		/* FIXME: it leaves the last sta entry unfiltered, who cares! */
1179 		if (weth->sta[i].next)
1180 			continue;
1181 		/* format the entry dump */
1182 		sta = &weth->sta[i];
1183 		bcm_bprintf(b, "%u\t%s\t%u.%u.%u.%u\n",
1184 				i, bcm_ether_ntoa(&sta->mac, eabuf),
1185 				sta->ip[0], sta->ip[1], sta->ip[2], sta->ip[3]);
1186 	}
1187 }
1188