2 * Proxy ARP capabilitiy enables an AP to indicate that the non-AP STA will not
3 * receive ARP frames. The Proxy ARP cappability enables the non-AP STA to remain
4 * in power-save for longer period of time.
5 * Original implements in wlc_l2_filter.c for HSPOT2.0. Network Power Save(NPS)
6 * was also defined to support the capability. We abstract core Proxy ARP implement
7 * and moved it from wlc_l2_filter.c to a standalone module to support
10 * Copyright (C) 2012, Broadcom Corporation
11 * All Rights Reserved.
13 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
14 * the contents of this file may not be disclosed to third parties, copied
15 * or duplicated in any form, in whole or in part, without the prior
16 * written permission of Broadcom Corporation.
25 #include <bcmendian.h>
26 #include <proto/802.11.h>
27 #include <proto/802.3.h>
28 #include <proto/vlan.h>
29 #include <proto/bcmip.h>
30 #include <proto/bcmarp.h>
31 #include <proto/bcmipv6.h>
32 #include <proto/bcmudp.h>
33 #include <proto/bcmdhcp.h>
34 #include <proto/bcmproto.h>
35 #include <proxyarp/proxyarp.h>
37 #define ALIGN_ADJ_BUFLEN 2 /* Adjust for ETHER_HDR_LEN pull in linux */
38 #define EAIP_TUPLE_TIMEOUT 600 * 1000
39 #define EAIP_TUPLE_TABLE_SIZE 256
41 /* This marks the start of a packed structure section. */
42 #include <packed_section_start.h>
44 struct aging_link
*prev
;
45 struct aging_link
*next
;
48 BWL_PRE_PACKED_STRUCT
struct eaip_tuple
{
49 struct eaip_tuple
*next
;
51 struct aging_link alink
;
52 uint32 used
; /* time stamp */
54 } BWL_POST_PACKED_STRUCT
;
55 /* This marks the end of a packed structure section. */
56 #include <packed_section_end.h>
58 typedef struct eaip_tuple eaip_tuple_t
;
59 static eaip_tuple_t
*eaip_tbl
[EAIP_TUPLE_TABLE_SIZE
];
60 static struct aging_link
*aq_head
, *aq_tail
; /* aging queue head/tail */
62 static proxyarp_info_t
*pa_info
;
64 static uint8 proxyarp_msglevel
= 0xff;
67 #define ND_OPTION_LEN_ETHER 1
70 aging_queue_enq(struct aging_link
*node
)
84 aging_queue_deq(struct aging_link
*node
)
86 if (node
->prev
== NULL
)
89 node
->prev
->next
= node
->next
;
91 if (node
->next
== NULL
)
94 node
->next
->prev
= node
->prev
;
98 eaip_str(uint8
*ea
, uint8
*ip
, uint8 ip_ver
, uint8
*buf
, uint32 buflen
)
107 bcm_ether_ntoa((struct ether_addr
*)ea
, eastr
);
108 if (ip_ver
== IP_VER_4
)
109 bcm_ip_ntoa((struct ipv4_addr
*)ip
, ipstr
);
111 bcm_format_hex(ipstr
, ip
, 16);
113 snprintf(buf
, buflen
- 1, "%s(%s)", eastr
, ipstr
);
119 eaip_add(proxyarp_info_t
*pah
, uint8
*ea
, uint8
*ip
, uint8 ip_ver
)
126 if (IPV4_ADDR_NULL(ip
) || IPV4_ADDR_BCAST(ip
))
129 idx
= ip
[IPV4_ADDR_LEN
- 1];
130 ip_len
= IPV4_ADDR_LEN
;
133 if (IPV6_ADDR_NULL(ip
))
136 idx
= ip
[IPV6_ADDR_LEN
- 1];
137 ip_len
= IPV6_ADDR_LEN
;
144 if ((node
= MALLOC(pah
->osh
, sizeof(eaip_tuple_t
) + ip_len
)) == NULL
) {
145 PROXYARP_ERR("allocating new eaip for ipv%d error !!\n", ip_ver
);
149 bzero(node
, sizeof(eaip_tuple_t
) + ip_len
);
150 bcopy(ea
, &node
->ea
, ETHER_ADDR_LEN
);
151 node
->used
= OSL_SYSUPTIME();
152 node
->ip
.id
= ip_ver
;
153 node
->ip
.len
= ip_len
;
154 bcopy(ip
, node
->ip
.data
, ip_len
);
155 node
->next
= eaip_tbl
[idx
];
156 eaip_tbl
[idx
] = node
;
160 /* add to aging queue head */
161 aging_queue_enq(&node
->alink
);
167 eaip_del(proxyarp_info_t
*pah
, uint8
*ea
, uint8
*ip
, uint8 ip_ver
)
169 eaip_tuple_t
*prev
, *node
;
176 ip_len
= IPV4_ADDR_LEN
;
180 ip_len
= IPV6_ADDR_LEN
;
187 node
= eaip_tbl
[idx
];
190 if (node
->ip
.id
== ip_ver
&&
191 bcmp(node
->ip
.data
, ip
, ip_len
) == 0 &&
192 bcmp((uint8
*)&node
->ea
, ea
, ETHER_ADDR_LEN
) == 0) {
194 eaip_tbl
[idx
] = node
->next
;
196 prev
->next
= node
->next
;
204 MFREE(pah
->osh
, node
, sizeof(eaip_tuple_t
) + ip_len
);
212 eaip_timeout(eaip_tuple_t
*node
)
214 uint32 now
= OSL_SYSUPTIME();
216 if (now
- node
->used
> EAIP_TUPLE_TIMEOUT
)
222 static eaip_tuple_t
*
223 eaip_find_by_ip(uint8
*ip
, uint8 ip_ver
)
230 node
= eaip_tbl
[ip
[3]];
231 ip_len
= IPV4_ADDR_LEN
;
234 node
= eaip_tbl
[ip
[15]];
235 ip_len
= IPV6_ADDR_LEN
;
244 if (node
->ip
.id
== ip_ver
&& bcmp(node
->ip
.data
, ip
, ip_len
) == 0) {
245 node
->used
= OSL_SYSUPTIME();
247 /* removed from aging queue and re-add to head of aging queue */
248 aging_queue_deq(&node
->alink
);
249 aging_queue_enq(&node
->alink
);
259 proxyarp_update(uint8
*ea
, uint8
*ip
, uint8 ip_ver
)
264 /* basic ether addr check */
265 if (ETHER_ISNULLADDR(ea
) || ETHER_ISBCAST(ea
) || ETHER_ISMULTI(ea
)) {
266 PROXYARP_ERR("Invalid Ether addr\n");
271 node
= eaip_find_by_ip(ip
, ip_ver
);
274 if (bcmp(ea
, (uint8
*)&node
->ea
, ETHER_ADDR_LEN
) != 0) {
275 /* conflct ip address ! */
276 PROXYARP_ERR("Ipaddr Conflict !!!!\n");
281 /* no eaip tuple. we need to add this tuple */
282 if (eaip_add(pa_info
, ea
, ip
, ip_ver
) == BCME_OK
) {
286 PROXYARP_INFO("Create IPv%d %s\n", ip_ver
,
287 eaip_str(ea
, ip
, ip_ver
, eaip_buf
, 128));
296 proxyarp_alloc_reply(osl_t
*osh
, uint32 pktlen
, uint8
*src_ea
, uint8
*dst_ea
,
297 uint16 ea_type
, bool snap
, void **p
)
302 /* adjust pktlen since skb->data is aligned to 2 */
303 pktlen
+= ALIGN_ADJ_BUFLEN
;
305 if ((pkt
= PKTGET(osh
, pktlen
, FALSE
)) == NULL
) {
306 PROXYARP_ERR("%s %d: PKTGET failed\n", __func__
, __LINE__
);
309 /* adjust for pkt->data aligned */
310 PKTPULL(osh
, pkt
, ALIGN_ADJ_BUFLEN
);
311 frame
= PKTDATA(osh
, pkt
);
313 /* Create 14-byte eth header, plus snap header if applicable */
314 bcopy(src_ea
, frame
+ ETHER_SRC_OFFSET
, ETHER_ADDR_LEN
);
315 bcopy(dst_ea
, frame
+ ETHER_DEST_OFFSET
, ETHER_ADDR_LEN
);
317 hton16_ua_store(pktlen
, frame
+ ETHER_TYPE_OFFSET
);
318 bcopy(llc_snap_hdr
, frame
+ ETHER_HDR_LEN
, SNAP_HDR_LEN
);
319 hton16_ua_store(ea_type
, frame
+ ETHER_HDR_LEN
+ SNAP_HDR_LEN
);
321 hton16_ua_store(ea_type
, frame
+ ETHER_TYPE_OFFSET
);
323 *p
= (void *)(frame
+ ETHER_HDR_LEN
+ (snap
? SNAP_HDR_LEN
+ ETHER_TYPE_LEN
: 0));
328 * Moved from wlc_l2_filter.c
331 proxyarp_arpreply(osl_t
*osh
, struct bcmarp
*arp_req
, bool snap
, void **reply
)
333 struct bcmarp
*arp_reply
;
334 eaip_tuple_t
*target
;
336 uint16 pktlen
= ETHER_HDR_LEN
+ ARP_DATA_LEN
+ (snap
? SNAP_HDR_LEN
+ ETHER_TYPE_LEN
: 0);
338 /* no valid entry, return */
340 target
= eaip_find_by_ip(arp_req
->dst_ip
, IP_VER_4
);
343 /* no target exist, return */
344 if (target
== NULL
) {
348 /* src_ea equals to dst_ea, should be dropped */
349 if (bcmp(arp_req
->src_eth
, &target
->ea
, ETHER_ADDR_LEN
) == 0) {
350 PROXYARP_INFO("ARP-Req ask for its own ea, avoid reply to these frame\n");
354 /* Create 42-byte arp-reply data frame */
355 if ((pkt
= proxyarp_alloc_reply(osh
, pktlen
, (uint8
*)&target
->ea
, arp_req
->src_eth
,
356 ETHER_TYPE_ARP
, snap
, (void **)&arp_reply
)) == NULL
) {
360 /* construct 28-byte arp-reply data frame */
361 /* copy first 6 bytes as-is; i.e., htype, ptype, hlen, plen */
362 bcopy(arp_req
, arp_reply
, ARP_OPC_OFFSET
);
363 arp_reply
->oper
= HTON16(ARP_OPC_REPLY
);
364 /* Copy dst eth and ip addresses */
365 bcopy(&target
->ea
, arp_reply
->src_eth
, ETHER_ADDR_LEN
);
366 bcopy(&target
->ip
.data
, arp_reply
->src_ip
, IPV4_ADDR_LEN
);
367 bcopy(arp_req
->src_eth
, arp_reply
->dst_eth
, ETHER_ADDR_LEN
);
368 bcopy(arp_req
->src_ip
, arp_reply
->dst_ip
, IPV4_ADDR_LEN
);
370 *reply
= (void *)pkt
;
375 * moved from wlc_l2_filter.c. The length of the option including
376 * the type and length fields in units of 8 octets
379 parse_nd_options(void *buf
, int buflen
, uint key
)
384 elt
= (bcm_tlv_t
*)buf
;
387 /* find tagged parameter */
388 while (totlen
>= TLV_HDR_LEN
) {
389 int len
= elt
->len
* 8;
391 /* validate remaining totlen */
392 if ((elt
->id
== key
) &&
396 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ len
);
403 * moved from wlc_l2_filter.c
406 calc_checksum(uint8
*src_ipa
, uint8
*dst_ipa
, uint32 ul_len
, uint8 prot
, uint8
*ul_data
)
415 for (i
= 0; i
< (IPV6_ADDR_LEN
/ 2); i
++) {
416 sum
+= *((uint16
*)src_ipa
);
420 for (i
= 0; i
< (IPV6_ADDR_LEN
/ 2); i
++) {
421 sum
+= *((uint16
*)dst_ipa
);
425 *((uint32
*)ph
) = hton32(ul_len
);
426 *((uint32
*)(ph
+4)) = 0;
428 startpos
= (uint16
*)ph
;
429 for (i
= 0; i
< 4; i
++) {
434 startpos
= (uint16
*)ul_data
;
441 *((uint8
*)(&answer
)) = *((uint8
*)startpos
);
445 sum
= (sum
>> 16) + (sum
& 0xffff);
452 * moved from wlc_l2_filter.c
455 proxyarp_nareply(osl_t
*osh
, uint8
*data
, bool snap
, uint8
*src_mac
, uint8 dup_ip
, void **reply
)
459 uint16 pktlen
= ETHER_HDR_LEN
+ NEIGHBOR_ADVERTISE_DATA_LEN
+
460 (snap
? SNAP_HDR_LEN
+ ETHER_TYPE_LEN
: 0);
462 eaip_tuple_t
*target
;
463 uint8 ipv6_mcast_allnode
[16] = {0xff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
464 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1};
466 /* no valid entry, return */
468 target
= eaip_find_by_ip(data
+ NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
, IP_VER_6
);
471 if (target
== NULL
) {
475 if (bcmp(src_mac
, (uint8
*)&target
->ea
, 6) == 0) {
479 /* Create 72 bytes neighbor advertisement data frame */
480 if ((pkt
= proxyarp_alloc_reply(osh
, pktlen
, (uint8
*)&target
->ea
, src_mac
,
481 ETHER_TYPE_IPV6
, snap
, (void **)&na
)) == NULL
) {
485 /* construct 40 bytes ipv6 header */
486 bcopy(data
, na
, IPV6_SRC_IP_OFFSET
);
487 hton16_ua_store((NEIGHBOR_ADVERTISE_DATA_LEN
- NEIGHBOR_ADVERTISE_TYPE_OFFSET
),
488 (na
+ IPV6_PAYLOAD_LEN_OFFSET
));
489 *(na
+ IPV6_HOP_LIMIT_OFFSET
) = 255;
490 bcopy(data
+NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
, na
+IPV6_SRC_IP_OFFSET
, IPV6_ADDR_LEN
);
493 bcopy(ipv6_mcast_allnode
, na
+ IPV6_DEST_IP_OFFSET
, IPV6_ADDR_LEN
);
495 bcopy(data
+IPV6_SRC_IP_OFFSET
, na
+IPV6_DEST_IP_OFFSET
, IPV6_ADDR_LEN
);
497 /* Create 32 bytes icmpv6 NA frame body */
498 bzero((na
+ NEIGHBOR_ADVERTISE_TYPE_OFFSET
),
499 (NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
- NEIGHBOR_ADVERTISE_TYPE_OFFSET
));
500 *(na
+ NEIGHBOR_ADVERTISE_TYPE_OFFSET
) = NEIGHBOR_ADVERTISE_TYPE
;
501 *(na
+ NEIGHBOR_ADVERTISE_FLAGS_OFFSET
) = NEIGHBOR_ADVERTISE_FLAGS_VALUE
;
502 bcopy(data
+NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
, na
+NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
,
504 *(na
+ NEIGHBOR_ADVERTISE_OPTION_OFFSET
) = OPT_TYPE_TGT_LINK_ADDR
;
505 *(na
+ NEIGHBOR_ADVERTISE_OPTION_OFFSET
+ TLV_LEN_OFF
) = ND_OPTION_LEN_ETHER
;
506 bcopy(&target
->ea
, na
+ NEIGHBOR_ADVERTISE_OPTION_OFFSET
+ TLV_BODY_OFF
,
509 /* calculate ICMPv6 check sum */
510 checksum
= calc_checksum(na
+IPV6_SRC_IP_OFFSET
, na
+IPV6_DEST_IP_OFFSET
,
511 NEIGHBOR_ADVERTISE_DATA_LEN
- NEIGHBOR_ADVERTISE_TYPE_OFFSET
,
512 IP_PROT_ICMP6
, na
+ NEIGHBOR_ADVERTISE_TYPE_OFFSET
);
513 *((uint16
*)(na
+ NEIGHBOR_ADVERTISE_CHECKSUM_OFFSET
)) = checksum
;
515 *reply
= (void *)pkt
;
521 uint8 l2_ea
[ETHER_ADDR_LEN
];
522 uint8 req_ea
[ETHER_ADDR_LEN
];
526 proxyarp_dhcpreq_handle(frame_proto_t
*fp
)
528 struct bcmudp_hdr
*udph
;
531 struct ether_header
*eh
;
532 uint16 opt_len
, offset
= DHCP_OPT_OFFSET
;
534 udph
= (struct bcmudp_hdr
*)fp
->l4
;
536 /* check if the packet is a dhcp-reply */
537 if (ntoh16(udph
->dst_port
) != DHCP_PORT_SERVER
)
540 /* we got dhcp-reply. update arp entry */
541 dhcp
= (uint8
*)(fp
->l4
+ UDP_HDR_LEN
);
543 /* only process DHCP reply(offer/ack) packets */
544 if (*(dhcp
+ DHCP_TYPE_OFFSET
) != DHCP_TYPE_REQUEST
)
547 /* First option must be magic cookie */
548 if ((dhcp
[offset
+ 0] != 0x63) || (dhcp
[offset
+ 1] != 0x82) ||
549 (dhcp
[offset
+ 2] != 0x53) || (dhcp
[offset
+ 3] != 0x63))
552 /* shift to real opt start offst */
554 opt_len
= fp
->l4_len
- offset
- UDP_HDR_LEN
;
555 msg_type
= bcm_parse_tlvs(&dhcp
[offset
], opt_len
, DHCP_OPT_MSGTYPE
);
556 if (msg_type
== NULL
|| msg_type
->data
[0] != DHCP_OPT_MSGTYPE_REQ
)
559 eh
= (struct ether_header
*)fp
->l2
;
560 bcopy(&dhcp
[DHCP_TID_OFFSET
], dhcpreq
.tid
, 4);
561 bcopy(eh
->ether_shost
, dhcpreq
.l2_ea
, ETHER_ADDR_LEN
);
562 bcopy(&dhcp
[DHCP_CHADDR_OFFSET
], dhcpreq
.req_ea
, ETHER_ADDR_LEN
);
566 proxyarp_dhcpack_handle(frame_proto_t
*fp
)
568 struct bcmudp_hdr
*udph
;
574 uint16 opt_len
, offset
= DHCP_OPT_OFFSET
;
576 udph
= (struct bcmudp_hdr
*)fp
->l4
;
578 /* check if the packet is a dhcp-reply */
579 if (ntoh16(udph
->dst_port
) != DHCP_PORT_CLIENT
)
582 /* we got dhcp-reply. update arp entry */
583 dhcp
= (uint8
*)(fp
->l4
+ UDP_HDR_LEN
);
585 /* only process DHCP reply(offer/ack) packets */
586 if (*(dhcp
+ DHCP_TYPE_OFFSET
) != DHCP_TYPE_REPLY
)
589 if (IPV4_ADDR_NULL(&dhcp
[16]))
592 /* First option must be magic cookie */
593 if ((dhcp
[offset
+ 0] != 0x63) || (dhcp
[offset
+ 1] != 0x82) ||
594 (dhcp
[offset
+ 2] != 0x53) || (dhcp
[offset
+ 3] != 0x63))
598 opt_len
= fp
->l4_len
- offset
- UDP_HDR_LEN
;
599 msg_type
= bcm_parse_tlvs(&dhcp
[offset
], opt_len
, DHCP_OPT_MSGTYPE
);
600 if (msg_type
== NULL
|| msg_type
->data
[0] != DHCP_OPT_MSGTYPE_ACK
)
605 if (bcmp((dhcp
+ DHCP_TID_OFFSET
), dhcpreq
.tid
, 4) == 0 &&
606 bcmp((dhcp
+ DHCP_CHADDR_OFFSET
), dhcpreq
.req_ea
, ETHER_ADDR_LEN
) == 0) {
607 PROXYARP_INFO("DHCP_ACK: %s\n", eaip_str(dhcpreq
.l2_ea
,
608 &dhcp
[DHCP_YIADDR_OFFSET
], IP_VER_4
, eaip_buf
, 128));
610 proxyarp_update(dhcpreq
.l2_ea
, (dhcp
+ DHCP_YIADDR_OFFSET
), IP_VER_4
);
613 PROXYARP_ERR("DHCP matching error\n");
616 bzero((uint8
*)&dhcpreq
, sizeof(dhcpreq
));
620 proxyarp_arp_handle(osl_t
*osh
, frame_proto_t
*fp
, void **reply
)
623 char srceaip_buf
[128];
624 char dsteaip_buf
[128];
626 struct bcmarp
*arp
= (struct bcmarp
*)fp
->l3
;
627 uint8 op
= ntoh16(arp
->oper
);
629 if (op
> ARP_OPC_REPLY
) {
630 PROXYARP_ERR("%s %d: Invalid ARP operation(%d)\n",
631 __func__
, __LINE__
, op
);
635 /* we proxy ARP request when receiving it */
636 /* update arp info when we receiving arp packet */
638 if (op
== ARP_OPC_REQUEST
)
639 PROXYARP_INFO("ARP_REQ: src %s - dst %s\n",
640 eaip_str(arp
->src_eth
, arp
->src_ip
, IP_VER_4
, srceaip_buf
, 128),
641 eaip_str(arp
->dst_eth
, arp
->dst_ip
, IP_VER_4
, dsteaip_buf
, 128));
645 proxyarp_update((uint8
*)&arp
->src_eth
, (uint8
*)&arp
->src_ip
, IP_VER_4
);
647 if (op
== ARP_OPC_REQUEST
) {
650 if (fp
->l2_t
== FRAME_L2_SNAP_H
|| fp
->l2_t
== FRAME_L2_SNAPVLAN_H
)
653 return proxyarp_arpreply(osh
, arp
, snap
, reply
);
660 proxyarp_icmp6_handle(osl_t
*osh
, frame_proto_t
*fp
, void **reply
)
662 bcm_tlv_t
*link_addr
;
667 uint8 is_null_ip
= 0;
668 uint8
*data
= fp
->l3
;
669 uint16 datalen
= fp
->l3_len
;
670 uint8
*frame
= fp
->l2
;
672 if ((datalen
< NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
+ IPV6_ADDR_LEN
) ||
673 (data
[IPV6_NEXT_HDR_OFFSET
] != IP_PROT_ICMP6
))
676 /* check for ICMPv6 neighbour operation */
677 if (data
[NEIGHBOR_ADVERTISE_TYPE_OFFSET
] == NEIGHBOR_ADVERTISE_TYPE
) {
678 ip_off
= NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
;
679 link_type
= OPT_TYPE_TGT_LINK_ADDR
;
681 else if (data
[NEIGHBOR_ADVERTISE_TYPE_OFFSET
] == NEIGHBOR_SOLICITATION_TYPE
) {
682 link_type
= OPT_TYPE_SRC_LINK_ADDR
;
683 if (IPV6_ADDR_NULL((uint8
)(data
+ NEIGHBOR_ADVERTISE_SRC_IPV6_OFFSET
))) {
684 ip_off
= NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET
;
688 ip_off
= NEIGHBOR_ADVERTISE_SRC_IPV6_OFFSET
;
693 link_addr
= parse_nd_options(data
+ NEIGHBOR_ADVERTISE_OPTION_OFFSET
,
694 datalen
-NEIGHBOR_ADVERTISE_OPTION_OFFSET
, link_type
);
696 if (link_addr
&& link_addr
->len
== ND_OPTION_LEN_ETHER
)
697 ea
= (uint8
*)&link_addr
->data
;
699 ea
= frame
+ ETHER_SRC_OFFSET
;
701 /* update local address */
702 dup_ip
= proxyarp_update(ea
, data
+ ip_off
, IP_VER_6
);
704 /* duplicate address detection, reply with all-node multicast address */
706 PROXYARP_INFO("receive DAD(duplicate address detection) frame, dup_ip = %d\n",
710 if (link_type
== OPT_TYPE_SRC_LINK_ADDR
) {
712 if (fp
->l2_t
== FRAME_L2_SNAP_H
|| fp
->l2_t
== FRAME_L2_SNAPVLAN_H
)
715 return proxyarp_nareply(osh
, data
, snap
, frame
+ ETHER_SRC_OFFSET
, dup_ip
, reply
);
717 else if (link_type
== OPT_TYPE_TGT_LINK_ADDR
) {
720 PROXYARP_ERR("not a src_link or target_link (%x)\n", link_type
);
727 * handle ARP request frame in send path, update database in both send/receive path
730 proxyarp_packets_handle(osl_t
*osh
, void *sdu
, void *fproto
, bool send
, void **reply
)
732 frame_proto_t
*fp
= (frame_proto_t
*)fproto
;
736 /* update ipv4 and reply */
737 if (fp
->l3_t
== FRAME_L3_ARP_H
)
738 return proxyarp_arp_handle(osh
, (frame_proto_t
*)fproto
, reply
);
740 /* update ipv6 and reply */
741 if (fp
->l4_t
== FRAME_L4_ICMP6_H
)
742 return proxyarp_icmp6_handle(osh
, (frame_proto_t
*)fproto
, reply
);
744 /* update ipv4 when AP sending dhcp-ack frame */
745 if (fp
->l4_t
== FRAME_L4_UDP_H
)
746 proxyarp_dhcpack_handle((frame_proto_t
*)fproto
);
750 /* update eaip_tuple timestamp */
751 if (fp
->l3_t
== FRAME_L3_IP_H
|| fp
->l3_t
== FRAME_L3_IP6_H
) {
752 uint8
*ip
= (fp
->l3_t
== FRAME_L3_IP_H
)?
753 fp
->l3
+ IPV4_SRC_IP_OFFSET
: fp
->l3
+ IPV6_SRC_IP_OFFSET
;
756 eaip_find_by_ip(ip
, fp
->l3_t
);
760 /* update ipv4 when AP sending dhcp-req frame */
761 if (fp
->l4_t
== FRAME_L4_UDP_H
)
762 proxyarp_dhcpreq_handle((frame_proto_t
*)fproto
);
768 _proxyarp_watchdog(bool all
, uint8
*del_ea
)
770 /* clean up database */
773 uint8 ea
[ETHER_ADDR_LEN
];
774 uint8 ip
[IPV6_ADDR_LEN
];
779 if (pa_info
== NULL
) {
780 PROXYARP_ERR("Invalid clean-up\n");
786 /* clean all table */
788 for (idx
= 0; idx
< EAIP_TUPLE_TABLE_SIZE
; idx
++) {
791 while (cur
!= NULL
) {
792 bcopy((uint8
*)&cur
->ea
, ea
, ETHER_ADDR_LEN
);
795 if (ip_ver
== IP_VER_4
) {
796 bcopy((uint8
*)&cur
->ip
.data
, ip
, IPV4_ADDR_LEN
);
797 ip
[IPV4_ADDR_LEN
] = 0;
800 bcopy((uint8
*)&cur
->ip
.data
, ip
, IPV6_ADDR_LEN
);
802 PROXYARP_INFO("flush IPv%d - %s\n", ip_ver
,
803 eaip_str(ea
, ip
, ip_ver
, eaip_buf
, 128));
807 eaip_del(pa_info
, ea
, ip
, ip_ver
);
810 aq_head
= aq_tail
= NULL
;
813 struct aging_link
*node
= aq_tail
;
816 cur
= (eaip_tuple_t
*)((void *)node
- OFFSETOF(struct eaip_tuple
, alink
));
818 /* remove specific node if ea exists */
819 if ((del_ea
&& bcmp(del_ea
, (uint8
*)&cur
->ea
, 6) == 0) ||
820 eaip_timeout(cur
) == TRUE
) {
821 bcopy((uint8
*)&cur
->ea
, ea
, ETHER_ADDR_LEN
);
824 if (ip_ver
== IP_VER_4
) {
825 bcopy((uint8
*)&cur
->ip
.data
, ip
, IPV4_ADDR_LEN
);
826 ip
[IPV4_ADDR_LEN
] = 0;
829 bcopy((uint8
*)&cur
->ip
.data
, ip
, IPV6_ADDR_LEN
);
831 aging_queue_deq(node
);
834 PROXYARP_INFO("Aging IPv%d - %s\n", ip_ver
,
835 eaip_str(ea
, ip
, ip_ver
, eaip_buf
, 128));
837 eaip_del(pa_info
, ea
, ip
, ip_ver
);
840 /* no eaip to aging. Stop */
854 return pa_info
->enabled
? TRUE
: FALSE
;
858 proxyarp_set(bool enabled
)
860 pa_info
->enabled
= enabled
;
864 proxyarp_init(proxyarp_info_t
*spa_info
)
866 if (spa_info
== NULL
) {
867 PROXYARP_ERR("Init Error: handle is null\n");
871 bzero(&eaip_tbl
, sizeof(eaip_tbl
));
872 aq_head
= aq_tail
= NULL
;
874 pa_info
->enabled
= FALSE
;
880 proxyarp_deinit(void)
882 _proxyarp_watchdog(TRUE
, NULL
);
883 aq_head
= aq_tail
= NULL
;
884 bzero(&eaip_tbl
, sizeof(eaip_tbl
));