xref: /xnu-11215.61.5/tests/net_bridge.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions /*
2*4f1223e8SApple OSS Distributions  * Copyright (c) 2019-2024 Apple Inc. All rights reserved.
3*4f1223e8SApple OSS Distributions  *
4*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4f1223e8SApple OSS Distributions  *
6*4f1223e8SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4f1223e8SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4f1223e8SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4f1223e8SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4f1223e8SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4f1223e8SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4f1223e8SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4f1223e8SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4f1223e8SApple OSS Distributions  *
15*4f1223e8SApple OSS Distributions  * Please obtain a copy of the License at
16*4f1223e8SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4f1223e8SApple OSS Distributions  *
18*4f1223e8SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4f1223e8SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4f1223e8SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4f1223e8SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4f1223e8SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4f1223e8SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4f1223e8SApple OSS Distributions  * limitations under the License.
25*4f1223e8SApple OSS Distributions  *
26*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4f1223e8SApple OSS Distributions  */
28*4f1223e8SApple OSS Distributions 
29*4f1223e8SApple OSS Distributions /*
30*4f1223e8SApple OSS Distributions  * net_bridge.c
31*4f1223e8SApple OSS Distributions  * - test if_bridge.c functionality
32*4f1223e8SApple OSS Distributions  */
33*4f1223e8SApple OSS Distributions 
34*4f1223e8SApple OSS Distributions #include <darwintest.h>
35*4f1223e8SApple OSS Distributions #include <stdio.h>
36*4f1223e8SApple OSS Distributions #include <unistd.h>
37*4f1223e8SApple OSS Distributions #include <stddef.h>
38*4f1223e8SApple OSS Distributions #include <stdlib.h>
39*4f1223e8SApple OSS Distributions #include <string.h>
40*4f1223e8SApple OSS Distributions #include <sys/socket.h>
41*4f1223e8SApple OSS Distributions #include <arpa/inet.h>
42*4f1223e8SApple OSS Distributions #include <sys/event.h>
43*4f1223e8SApple OSS Distributions #include <net/if.h>
44*4f1223e8SApple OSS Distributions #include <netinet/in.h>
45*4f1223e8SApple OSS Distributions #include <netinet6/in6_var.h>
46*4f1223e8SApple OSS Distributions #include <netinet6/nd6.h>
47*4f1223e8SApple OSS Distributions #include <netinet/in.h>
48*4f1223e8SApple OSS Distributions #include <netinet/ip.h>
49*4f1223e8SApple OSS Distributions #include <netinet/udp.h>
50*4f1223e8SApple OSS Distributions #include <netinet/tcp.h>
51*4f1223e8SApple OSS Distributions #include <netinet/if_ether.h>
52*4f1223e8SApple OSS Distributions #include <netinet/ip6.h>
53*4f1223e8SApple OSS Distributions #include <netinet/icmp6.h>
54*4f1223e8SApple OSS Distributions #include <net/if_arp.h>
55*4f1223e8SApple OSS Distributions #include <net/bpf.h>
56*4f1223e8SApple OSS Distributions #include <net/if_bridgevar.h>
57*4f1223e8SApple OSS Distributions #include <net/if_fake_var.h>
58*4f1223e8SApple OSS Distributions #include <sys/ioctl.h>
59*4f1223e8SApple OSS Distributions #include <sys/types.h>
60*4f1223e8SApple OSS Distributions #include <sys/stat.h>
61*4f1223e8SApple OSS Distributions #include <errno.h>
62*4f1223e8SApple OSS Distributions #include <pthread.h>
63*4f1223e8SApple OSS Distributions #include <stdbool.h>
64*4f1223e8SApple OSS Distributions #include <TargetConditionals.h>
65*4f1223e8SApple OSS Distributions #include <darwintest_utils.h>
66*4f1223e8SApple OSS Distributions 
67*4f1223e8SApple OSS Distributions #include "net_test_lib.h"
68*4f1223e8SApple OSS Distributions #include "inet_transfer.h"
69*4f1223e8SApple OSS Distributions #include "bpflib.h"
70*4f1223e8SApple OSS Distributions #include "in_cksum.h"
71*4f1223e8SApple OSS Distributions 
72*4f1223e8SApple OSS Distributions static bool S_cleaning_up;
73*4f1223e8SApple OSS Distributions 
74*4f1223e8SApple OSS Distributions #define ALL_ADDRS (uint32_t)(-1)
75*4f1223e8SApple OSS Distributions 
76*4f1223e8SApple OSS Distributions typedef struct {
77*4f1223e8SApple OSS Distributions 	char            ifname[IFNAMSIZ];       /* port we do I/O on */
78*4f1223e8SApple OSS Distributions 	ether_addr_t    mac;
79*4f1223e8SApple OSS Distributions 	char            member_ifname[IFNAMSIZ]; /* member of bridge */
80*4f1223e8SApple OSS Distributions 	ether_addr_t    member_mac;
81*4f1223e8SApple OSS Distributions 	int             fd;
82*4f1223e8SApple OSS Distributions 	u_int           unit;
83*4f1223e8SApple OSS Distributions 	u_int           num_addrs;
84*4f1223e8SApple OSS Distributions 	void *          rx_buf;
85*4f1223e8SApple OSS Distributions 	int             rx_buf_size;
86*4f1223e8SApple OSS Distributions 	bool            mac_nat;
87*4f1223e8SApple OSS Distributions 	struct in_addr  ip;
88*4f1223e8SApple OSS Distributions 	struct in6_addr ip6;
89*4f1223e8SApple OSS Distributions 	u_short         if_index;
90*4f1223e8SApple OSS Distributions 
91*4f1223e8SApple OSS Distributions 	u_int           test_count;
92*4f1223e8SApple OSS Distributions 	u_int           test_address_count;
93*4f1223e8SApple OSS Distributions 	uint64_t        test_address_present;
94*4f1223e8SApple OSS Distributions } switch_port, *switch_port_t;
95*4f1223e8SApple OSS Distributions 
96*4f1223e8SApple OSS Distributions typedef struct {
97*4f1223e8SApple OSS Distributions 	u_int           size;
98*4f1223e8SApple OSS Distributions 	u_int           count;
99*4f1223e8SApple OSS Distributions 	bool            mac_nat;
100*4f1223e8SApple OSS Distributions 	switch_port     list[1];
101*4f1223e8SApple OSS Distributions } switch_port_list, * switch_port_list_t;
102*4f1223e8SApple OSS Distributions 
103*4f1223e8SApple OSS Distributions static struct in_addr   bridge_ip_addr;
104*4f1223e8SApple OSS Distributions static struct in6_addr  bridge_ipv6_addr;
105*4f1223e8SApple OSS Distributions static u_short          bridge_if_index;
106*4f1223e8SApple OSS Distributions 
107*4f1223e8SApple OSS Distributions static struct ifbareq *
108*4f1223e8SApple OSS Distributions bridge_rt_table_copy(u_int * ret_count);
109*4f1223e8SApple OSS Distributions 
110*4f1223e8SApple OSS Distributions static void
111*4f1223e8SApple OSS Distributions bridge_rt_table_log(struct ifbareq *rt_table, u_int count);
112*4f1223e8SApple OSS Distributions 
113*4f1223e8SApple OSS Distributions static struct ifbrmne *
114*4f1223e8SApple OSS Distributions bridge_mac_nat_entries_copy(u_int * ret_count);
115*4f1223e8SApple OSS Distributions 
116*4f1223e8SApple OSS Distributions static void
117*4f1223e8SApple OSS Distributions bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count);
118*4f1223e8SApple OSS Distributions 
119*4f1223e8SApple OSS Distributions #define SETUP_FLAGS_MAC_NAT             0x01
120*4f1223e8SApple OSS Distributions #define SETUP_FLAGS_CHECKSUM_OFFLOAD    0x02
121*4f1223e8SApple OSS Distributions #define SETUP_FLAGS_ATTACH_STACK        0x04
122*4f1223e8SApple OSS Distributions #define SETUP_FLAGS_TRAILERS            0x08
123*4f1223e8SApple OSS Distributions #define SETUP_FLAGS_SHARE_MEMBER_MAC    0x10
124*4f1223e8SApple OSS Distributions 
125*4f1223e8SApple OSS Distributions #define s6_addr16 __u6_addr.__u6_addr16
126*4f1223e8SApple OSS Distributions 
127*4f1223e8SApple OSS Distributions /**
128*4f1223e8SApple OSS Distributions ** Packet creation/display
129*4f1223e8SApple OSS Distributions **/
130*4f1223e8SApple OSS Distributions #define BOOTP_SERVER_PORT       67
131*4f1223e8SApple OSS Distributions #define BOOTP_CLIENT_PORT       68
132*4f1223e8SApple OSS Distributions 
133*4f1223e8SApple OSS Distributions #define TEST_SOURCE_PORT        14
134*4f1223e8SApple OSS Distributions #define TEST_DEST_PORT          15
135*4f1223e8SApple OSS Distributions 
136*4f1223e8SApple OSS Distributions #define EA_UNIT_INDEX           4
137*4f1223e8SApple OSS Distributions #define EA_ADDR_INDEX           5
138*4f1223e8SApple OSS Distributions 
139*4f1223e8SApple OSS Distributions static void
set_ethernet_address(ether_addr_t * eaddr,u_int unit,u_int addr_index)140*4f1223e8SApple OSS Distributions set_ethernet_address(ether_addr_t *eaddr, u_int unit, u_int addr_index)
141*4f1223e8SApple OSS Distributions {
142*4f1223e8SApple OSS Distributions 	u_char  *a = eaddr->octet;
143*4f1223e8SApple OSS Distributions 
144*4f1223e8SApple OSS Distributions 	a[0] = 0x02;
145*4f1223e8SApple OSS Distributions 	a[2] = 0x00;
146*4f1223e8SApple OSS Distributions 	a[3] = 0x00;
147*4f1223e8SApple OSS Distributions 	a[1] = 0x00;
148*4f1223e8SApple OSS Distributions 	a[EA_UNIT_INDEX] = (u_char)unit;
149*4f1223e8SApple OSS Distributions 	a[EA_ADDR_INDEX] = (u_char)addr_index;
150*4f1223e8SApple OSS Distributions }
151*4f1223e8SApple OSS Distributions 
152*4f1223e8SApple OSS Distributions #define TEN_NET                 0x0a000000
153*4f1223e8SApple OSS Distributions #define TEN_1_NET               (TEN_NET | 0x010000)
154*4f1223e8SApple OSS Distributions 
155*4f1223e8SApple OSS Distributions static void
get_ipv4_address(u_int unit,u_int addr_index,struct in_addr * ip)156*4f1223e8SApple OSS Distributions get_ipv4_address(u_int unit, u_int addr_index, struct in_addr *ip)
157*4f1223e8SApple OSS Distributions {
158*4f1223e8SApple OSS Distributions 	/* up to 255 units, 255 addresses */
159*4f1223e8SApple OSS Distributions 	ip->s_addr = htonl(TEN_1_NET | (unit << 8) | addr_index);
160*4f1223e8SApple OSS Distributions 	return;
161*4f1223e8SApple OSS Distributions }
162*4f1223e8SApple OSS Distributions 
163*4f1223e8SApple OSS Distributions #define IN6ADDR_ULA_INIT \
164*4f1223e8SApple OSS Distributions 	{{{ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
165*4f1223e8SApple OSS Distributions 	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
166*4f1223e8SApple OSS Distributions 
167*4f1223e8SApple OSS Distributions static struct in6_addr ula_address = IN6ADDR_ULA_INIT;
168*4f1223e8SApple OSS Distributions 
169*4f1223e8SApple OSS Distributions #define ULA_UNIT_INDEX  14
170*4f1223e8SApple OSS Distributions #define ULA_ADDR_INDEX  15
171*4f1223e8SApple OSS Distributions 
172*4f1223e8SApple OSS Distributions static void
get_ipv6_ula_address(u_int unit,u_int addr_index,struct in6_addr * ip)173*4f1223e8SApple OSS Distributions get_ipv6_ula_address(u_int unit, u_int addr_index, struct in6_addr *ip)
174*4f1223e8SApple OSS Distributions {
175*4f1223e8SApple OSS Distributions 	*ip = ula_address;
176*4f1223e8SApple OSS Distributions 	/* up to 255 units, 255 addresses */
177*4f1223e8SApple OSS Distributions 	ip->s6_addr[ULA_UNIT_INDEX] = (uint8_t)unit;
178*4f1223e8SApple OSS Distributions 	ip->s6_addr[ULA_ADDR_INDEX] = (uint8_t)addr_index;
179*4f1223e8SApple OSS Distributions }
180*4f1223e8SApple OSS Distributions 
181*4f1223e8SApple OSS Distributions #define ND6_EUI64_GBIT  0x01
182*4f1223e8SApple OSS Distributions #define ND6_EUI64_UBIT  0x02
183*4f1223e8SApple OSS Distributions 
184*4f1223e8SApple OSS Distributions #define ND6_EUI64_TO_IFID(in6) \
185*4f1223e8SApple OSS Distributions 	do {(in6)->s6_addr[8] ^= ND6_EUI64_UBIT; } while (0)
186*4f1223e8SApple OSS Distributions static void
get_ipv6_ll_address(const ether_addr_t * mac,struct in6_addr * in6)187*4f1223e8SApple OSS Distributions get_ipv6_ll_address(const ether_addr_t *mac, struct in6_addr * in6)
188*4f1223e8SApple OSS Distributions {
189*4f1223e8SApple OSS Distributions 	const u_char *  addr = mac->octet;
190*4f1223e8SApple OSS Distributions 
191*4f1223e8SApple OSS Distributions 	bzero(in6, sizeof(*in6));
192*4f1223e8SApple OSS Distributions 	in6->s6_addr16[0] = htons(0xfe80);
193*4f1223e8SApple OSS Distributions 	in6->s6_addr[8] = addr[0];
194*4f1223e8SApple OSS Distributions 	in6->s6_addr[9] = addr[1];
195*4f1223e8SApple OSS Distributions 	in6->s6_addr[10] = addr[2];
196*4f1223e8SApple OSS Distributions 	in6->s6_addr[11] = 0xff;
197*4f1223e8SApple OSS Distributions 	in6->s6_addr[12] = 0xfe;
198*4f1223e8SApple OSS Distributions 	in6->s6_addr[13] = addr[3];
199*4f1223e8SApple OSS Distributions 	in6->s6_addr[14] = addr[4];
200*4f1223e8SApple OSS Distributions 	in6->s6_addr[15] = addr[5];
201*4f1223e8SApple OSS Distributions 	ND6_EUI64_TO_IFID(in6);
202*4f1223e8SApple OSS Distributions 	return;
203*4f1223e8SApple OSS Distributions }
204*4f1223e8SApple OSS Distributions 
205*4f1223e8SApple OSS Distributions static void
get_ip_address(uint8_t af,u_int unit,u_int addr_index,union ifbrip * ip)206*4f1223e8SApple OSS Distributions get_ip_address(uint8_t af, u_int unit, u_int addr_index, union ifbrip *ip)
207*4f1223e8SApple OSS Distributions {
208*4f1223e8SApple OSS Distributions 	switch (af) {
209*4f1223e8SApple OSS Distributions 	case AF_INET:
210*4f1223e8SApple OSS Distributions 		get_ipv4_address(unit, addr_index, &ip->ifbrip_addr);
211*4f1223e8SApple OSS Distributions 		break;
212*4f1223e8SApple OSS Distributions 	case AF_INET6:
213*4f1223e8SApple OSS Distributions 		get_ipv6_ula_address(unit, addr_index, &ip->ifbrip_addr6);
214*4f1223e8SApple OSS Distributions 		break;
215*4f1223e8SApple OSS Distributions 	default:
216*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
217*4f1223e8SApple OSS Distributions 		break;
218*4f1223e8SApple OSS Distributions 	}
219*4f1223e8SApple OSS Distributions }
220*4f1223e8SApple OSS Distributions 
221*4f1223e8SApple OSS Distributions static bool
ip_addresses_are_equal(uint8_t af,union ifbrip * ip1,union ifbrip * ip2)222*4f1223e8SApple OSS Distributions ip_addresses_are_equal(uint8_t af, union ifbrip * ip1, union ifbrip * ip2)
223*4f1223e8SApple OSS Distributions {
224*4f1223e8SApple OSS Distributions 	bool    equal;
225*4f1223e8SApple OSS Distributions 
226*4f1223e8SApple OSS Distributions 	switch (af) {
227*4f1223e8SApple OSS Distributions 	case AF_INET:
228*4f1223e8SApple OSS Distributions 		equal = (ip1->ifbrip_addr.s_addr == ip2->ifbrip_addr.s_addr);
229*4f1223e8SApple OSS Distributions 		break;
230*4f1223e8SApple OSS Distributions 	case AF_INET6:
231*4f1223e8SApple OSS Distributions 		equal = IN6_ARE_ADDR_EQUAL(&ip1->ifbrip_addr6,
232*4f1223e8SApple OSS Distributions 		    &ip2->ifbrip_addr6);
233*4f1223e8SApple OSS Distributions 		break;
234*4f1223e8SApple OSS Distributions 	default:
235*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
236*4f1223e8SApple OSS Distributions 		equal = false;
237*4f1223e8SApple OSS Distributions 		break;
238*4f1223e8SApple OSS Distributions 	}
239*4f1223e8SApple OSS Distributions 	return equal;
240*4f1223e8SApple OSS Distributions }
241*4f1223e8SApple OSS Distributions 
242*4f1223e8SApple OSS Distributions static ether_addr_t ether_external = {
243*4f1223e8SApple OSS Distributions 	{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 }
244*4f1223e8SApple OSS Distributions };
245*4f1223e8SApple OSS Distributions 
246*4f1223e8SApple OSS Distributions static inline struct in_addr
get_external_ipv4_address(void)247*4f1223e8SApple OSS Distributions get_external_ipv4_address(void)
248*4f1223e8SApple OSS Distributions {
249*4f1223e8SApple OSS Distributions 	struct in_addr  ip;
250*4f1223e8SApple OSS Distributions 
251*4f1223e8SApple OSS Distributions 	/* IP 10.1.255.1 */
252*4f1223e8SApple OSS Distributions 	ip.s_addr = htonl(TEN_1_NET | 0xff01);
253*4f1223e8SApple OSS Distributions 	return ip;
254*4f1223e8SApple OSS Distributions }
255*4f1223e8SApple OSS Distributions 
256*4f1223e8SApple OSS Distributions static inline void
get_external_ip_address(uint8_t af,union ifbrip * ip)257*4f1223e8SApple OSS Distributions get_external_ip_address(uint8_t af, union ifbrip * ip)
258*4f1223e8SApple OSS Distributions {
259*4f1223e8SApple OSS Distributions 	switch (af) {
260*4f1223e8SApple OSS Distributions 	case AF_INET:
261*4f1223e8SApple OSS Distributions 		/* IP 10.1.255.1 */
262*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr = get_external_ipv4_address();
263*4f1223e8SApple OSS Distributions 		break;
264*4f1223e8SApple OSS Distributions 	case AF_INET6:
265*4f1223e8SApple OSS Distributions 		/* fd80::1 */
266*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6 = ula_address;
267*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6.s6_addr[1] = 0x80;
268*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6.s6_addr[15] = 0x01;
269*4f1223e8SApple OSS Distributions 		break;
270*4f1223e8SApple OSS Distributions 	default:
271*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
272*4f1223e8SApple OSS Distributions 		break;
273*4f1223e8SApple OSS Distributions 	}
274*4f1223e8SApple OSS Distributions }
275*4f1223e8SApple OSS Distributions 
276*4f1223e8SApple OSS Distributions static inline void
get_broadcast_ip_address(uint8_t af,union ifbrip * ip)277*4f1223e8SApple OSS Distributions get_broadcast_ip_address(uint8_t af, union ifbrip * ip)
278*4f1223e8SApple OSS Distributions {
279*4f1223e8SApple OSS Distributions 	switch (af) {
280*4f1223e8SApple OSS Distributions 	case AF_INET:
281*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr.s_addr = INADDR_BROADCAST;
282*4f1223e8SApple OSS Distributions 		break;
283*4f1223e8SApple OSS Distributions 	case AF_INET6:
284*4f1223e8SApple OSS Distributions 		/* 0xff0e::0 linklocal scope multicast */
285*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6 = in6addr_any;
286*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6.s6_addr[0] = 0xff;
287*4f1223e8SApple OSS Distributions 		ip->ifbrip_addr6.s6_addr[1] = __IPV6_ADDR_SCOPE_LINKLOCAL;
288*4f1223e8SApple OSS Distributions 		break;
289*4f1223e8SApple OSS Distributions 	default:
290*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
291*4f1223e8SApple OSS Distributions 		break;
292*4f1223e8SApple OSS Distributions 	}
293*4f1223e8SApple OSS Distributions }
294*4f1223e8SApple OSS Distributions 
295*4f1223e8SApple OSS Distributions #define ETHER_NTOA_BUFSIZE      (ETHER_ADDR_LEN * 3)
296*4f1223e8SApple OSS Distributions static const char *
ether_ntoa_buf(const ether_addr_t * n,char * buf,int buf_size)297*4f1223e8SApple OSS Distributions ether_ntoa_buf(const ether_addr_t *n, char * buf, int buf_size)
298*4f1223e8SApple OSS Distributions {
299*4f1223e8SApple OSS Distributions 	char *  str;
300*4f1223e8SApple OSS Distributions 
301*4f1223e8SApple OSS Distributions 	str = ether_ntoa(n);
302*4f1223e8SApple OSS Distributions 	strlcpy(buf, str, buf_size);
303*4f1223e8SApple OSS Distributions 	return buf;
304*4f1223e8SApple OSS Distributions }
305*4f1223e8SApple OSS Distributions 
306*4f1223e8SApple OSS Distributions static const char *
inet_ptrtop(int af,const void * ptr,char * buf,socklen_t buf_size)307*4f1223e8SApple OSS Distributions inet_ptrtop(int af, const void * ptr, char * buf, socklen_t buf_size)
308*4f1223e8SApple OSS Distributions {
309*4f1223e8SApple OSS Distributions 	union {
310*4f1223e8SApple OSS Distributions 		struct in_addr  ip;
311*4f1223e8SApple OSS Distributions 		struct in6_addr ip6;
312*4f1223e8SApple OSS Distributions 	} u;
313*4f1223e8SApple OSS Distributions 
314*4f1223e8SApple OSS Distributions 	switch (af) {
315*4f1223e8SApple OSS Distributions 	case AF_INET:
316*4f1223e8SApple OSS Distributions 		bcopy(ptr, &u.ip, sizeof(u.ip));
317*4f1223e8SApple OSS Distributions 		break;
318*4f1223e8SApple OSS Distributions 	case AF_INET6:
319*4f1223e8SApple OSS Distributions 		bcopy(ptr, &u.ip6, sizeof(u.ip6));
320*4f1223e8SApple OSS Distributions 		break;
321*4f1223e8SApple OSS Distributions 	default:
322*4f1223e8SApple OSS Distributions 		return NULL;
323*4f1223e8SApple OSS Distributions 	}
324*4f1223e8SApple OSS Distributions 	return inet_ntop(af, &u, buf, buf_size);
325*4f1223e8SApple OSS Distributions }
326*4f1223e8SApple OSS Distributions 
327*4f1223e8SApple OSS Distributions static __inline__ char *
arpop_name(u_int16_t op)328*4f1223e8SApple OSS Distributions arpop_name(u_int16_t op)
329*4f1223e8SApple OSS Distributions {
330*4f1223e8SApple OSS Distributions 	switch (op) {
331*4f1223e8SApple OSS Distributions 	case ARPOP_REQUEST:
332*4f1223e8SApple OSS Distributions 		return "ARP REQUEST";
333*4f1223e8SApple OSS Distributions 	case ARPOP_REPLY:
334*4f1223e8SApple OSS Distributions 		return "ARP REPLY";
335*4f1223e8SApple OSS Distributions 	case ARPOP_REVREQUEST:
336*4f1223e8SApple OSS Distributions 		return "REVARP REQUEST";
337*4f1223e8SApple OSS Distributions 	case ARPOP_REVREPLY:
338*4f1223e8SApple OSS Distributions 		return "REVARP REPLY";
339*4f1223e8SApple OSS Distributions 	default:
340*4f1223e8SApple OSS Distributions 		break;
341*4f1223e8SApple OSS Distributions 	}
342*4f1223e8SApple OSS Distributions 	return "<unknown>";
343*4f1223e8SApple OSS Distributions }
344*4f1223e8SApple OSS Distributions 
345*4f1223e8SApple OSS Distributions static void
arp_frame_validate(const struct ether_arp * earp,u_int len,bool dump)346*4f1223e8SApple OSS Distributions arp_frame_validate(const struct ether_arp * earp, u_int len, bool dump)
347*4f1223e8SApple OSS Distributions {
348*4f1223e8SApple OSS Distributions 	const struct arphdr *   arp_p;
349*4f1223e8SApple OSS Distributions 	int                     arphrd;
350*4f1223e8SApple OSS Distributions 	char                    buf_sender_ether[ETHER_NTOA_BUFSIZE];
351*4f1223e8SApple OSS Distributions 	char                    buf_sender_ip[INET_ADDRSTRLEN];
352*4f1223e8SApple OSS Distributions 	char                    buf_target_ether[ETHER_NTOA_BUFSIZE];
353*4f1223e8SApple OSS Distributions 	char                    buf_target_ip[INET_ADDRSTRLEN];
354*4f1223e8SApple OSS Distributions 
355*4f1223e8SApple OSS Distributions 	T_QUIET;
356*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(len, (u_int)sizeof(*earp),
357*4f1223e8SApple OSS Distributions 	    "%s ARP packet size %u need %u",
358*4f1223e8SApple OSS Distributions 	    __func__, len, (u_int)sizeof(*earp));
359*4f1223e8SApple OSS Distributions 	if (!dump) {
360*4f1223e8SApple OSS Distributions 		return;
361*4f1223e8SApple OSS Distributions 	}
362*4f1223e8SApple OSS Distributions 	arp_p = &earp->ea_hdr;
363*4f1223e8SApple OSS Distributions 	arphrd = ntohs(arp_p->ar_hrd);
364*4f1223e8SApple OSS Distributions 	T_LOG("%s type=0x%x proto=0x%x", arpop_name(ntohs(arp_p->ar_op)),
365*4f1223e8SApple OSS Distributions 	    arphrd, ntohs(arp_p->ar_pro));
366*4f1223e8SApple OSS Distributions 	if (arp_p->ar_hln == sizeof(earp->arp_sha)) {
367*4f1223e8SApple OSS Distributions 		ether_ntoa_buf((const ether_addr_t *)earp->arp_sha,
368*4f1223e8SApple OSS Distributions 		    buf_sender_ether,
369*4f1223e8SApple OSS Distributions 		    sizeof(buf_sender_ether));
370*4f1223e8SApple OSS Distributions 		ether_ntoa_buf((const ether_addr_t *)earp->arp_tha,
371*4f1223e8SApple OSS Distributions 		    buf_target_ether,
372*4f1223e8SApple OSS Distributions 		    sizeof(buf_target_ether));
373*4f1223e8SApple OSS Distributions 		T_LOG("Sender H/W\t%s", buf_sender_ether);
374*4f1223e8SApple OSS Distributions 		T_LOG("Target H/W\t%s", buf_target_ether);
375*4f1223e8SApple OSS Distributions 	}
376*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET, earp->arp_spa,
377*4f1223e8SApple OSS Distributions 	    buf_sender_ip, sizeof(buf_sender_ip));
378*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET, earp->arp_tpa,
379*4f1223e8SApple OSS Distributions 	    buf_target_ip, sizeof(buf_target_ip));
380*4f1223e8SApple OSS Distributions 	T_LOG("Sender IP\t%s", buf_sender_ip);
381*4f1223e8SApple OSS Distributions 	T_LOG("Target IP\t%s", buf_target_ip);
382*4f1223e8SApple OSS Distributions 	return;
383*4f1223e8SApple OSS Distributions }
384*4f1223e8SApple OSS Distributions 
385*4f1223e8SApple OSS Distributions static void
ip_frame_validate(const void * buf,u_int buf_len,bool dump)386*4f1223e8SApple OSS Distributions ip_frame_validate(const void * buf, u_int buf_len, bool dump)
387*4f1223e8SApple OSS Distributions {
388*4f1223e8SApple OSS Distributions 	char                    buf_dst[INET_ADDRSTRLEN];
389*4f1223e8SApple OSS Distributions 	char                    buf_src[INET_ADDRSTRLEN];
390*4f1223e8SApple OSS Distributions 	const ip_udp_header_t * ip_udp;
391*4f1223e8SApple OSS Distributions 	u_int                   ip_len;
392*4f1223e8SApple OSS Distributions 
393*4f1223e8SApple OSS Distributions 	T_QUIET;
394*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)sizeof(struct ip), NULL);
395*4f1223e8SApple OSS Distributions 	ip_udp = (const ip_udp_header_t *)buf;
396*4f1223e8SApple OSS Distributions 	ip_len = ntohs(ip_udp->ip.ip_len);
397*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET, &ip_udp->ip.ip_src,
398*4f1223e8SApple OSS Distributions 	    buf_src, sizeof(buf_src));
399*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET, &ip_udp->ip.ip_dst,
400*4f1223e8SApple OSS Distributions 	    buf_dst, sizeof(buf_dst));
401*4f1223e8SApple OSS Distributions 	if (dump) {
402*4f1223e8SApple OSS Distributions 		T_LOG("ip src %s dst %s len %u id %d",
403*4f1223e8SApple OSS Distributions 		    buf_src, buf_dst, ip_len,
404*4f1223e8SApple OSS Distributions 		    ntohs(ip_udp->ip.ip_id));
405*4f1223e8SApple OSS Distributions 	}
406*4f1223e8SApple OSS Distributions 	T_QUIET;
407*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, ip_len, NULL);
408*4f1223e8SApple OSS Distributions 	T_QUIET;
409*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)ip_udp->ip.ip_v, IPVERSION, NULL);
410*4f1223e8SApple OSS Distributions 	T_QUIET;
411*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)(ip_udp->ip.ip_hl << 2),
412*4f1223e8SApple OSS Distributions 	    (u_int)sizeof(struct ip), NULL);
413*4f1223e8SApple OSS Distributions 	if (ip_udp->ip.ip_p == IPPROTO_UDP) {
414*4f1223e8SApple OSS Distributions 		u_int   udp_len;
415*4f1223e8SApple OSS Distributions 		u_int   data_len;
416*4f1223e8SApple OSS Distributions 
417*4f1223e8SApple OSS Distributions 		T_QUIET;
418*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, (u_int)sizeof(*ip_udp), NULL);
419*4f1223e8SApple OSS Distributions 		udp_len = ntohs(ip_udp->udp.uh_ulen);
420*4f1223e8SApple OSS Distributions 		T_QUIET;
421*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(udp_len, (u_int)sizeof(ip_udp->udp), NULL);
422*4f1223e8SApple OSS Distributions 		data_len = udp_len - (u_int)sizeof(ip_udp->udp);
423*4f1223e8SApple OSS Distributions 		if (dump) {
424*4f1223e8SApple OSS Distributions 			T_LOG("udp src 0x%x dst 0x%x len %u"
425*4f1223e8SApple OSS Distributions 			    " csum 0x%x datalen %u",
426*4f1223e8SApple OSS Distributions 			    ntohs(ip_udp->udp.uh_sport),
427*4f1223e8SApple OSS Distributions 			    ntohs(ip_udp->udp.uh_dport),
428*4f1223e8SApple OSS Distributions 			    udp_len,
429*4f1223e8SApple OSS Distributions 			    ntohs(ip_udp->udp.uh_sum),
430*4f1223e8SApple OSS Distributions 			    data_len);
431*4f1223e8SApple OSS Distributions 		}
432*4f1223e8SApple OSS Distributions 	}
433*4f1223e8SApple OSS Distributions }
434*4f1223e8SApple OSS Distributions 
435*4f1223e8SApple OSS Distributions static void
ip6_frame_validate(const void * buf,u_int buf_len,bool dump)436*4f1223e8SApple OSS Distributions ip6_frame_validate(const void * buf, u_int buf_len, bool dump)
437*4f1223e8SApple OSS Distributions {
438*4f1223e8SApple OSS Distributions 	char                    buf_dst[INET6_ADDRSTRLEN];
439*4f1223e8SApple OSS Distributions 	char                    buf_src[INET6_ADDRSTRLEN];
440*4f1223e8SApple OSS Distributions 	const struct ip6_hdr *  ip6;
441*4f1223e8SApple OSS Distributions 	u_int                   ip6_len;
442*4f1223e8SApple OSS Distributions 
443*4f1223e8SApple OSS Distributions 	T_QUIET;
444*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)sizeof(struct ip6_hdr), NULL);
445*4f1223e8SApple OSS Distributions 	ip6 = (const struct ip6_hdr *)buf;
446*4f1223e8SApple OSS Distributions 	ip6_len = ntohs(ip6->ip6_plen);
447*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET6, &ip6->ip6_src, buf_src, sizeof(buf_src));
448*4f1223e8SApple OSS Distributions 	inet_ptrtop(AF_INET6, &ip6->ip6_dst, buf_dst, sizeof(buf_dst));
449*4f1223e8SApple OSS Distributions 	if (dump) {
450*4f1223e8SApple OSS Distributions 		T_LOG("ip6 src %s dst %s len %u", buf_src, buf_dst, ip6_len);
451*4f1223e8SApple OSS Distributions 	}
452*4f1223e8SApple OSS Distributions 	T_QUIET;
453*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, ip6_len + (u_int)sizeof(struct ip6_hdr), NULL);
454*4f1223e8SApple OSS Distributions 	T_QUIET;
455*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((ip6->ip6_vfc & IPV6_VERSION_MASK),
456*4f1223e8SApple OSS Distributions 	    IPV6_VERSION, NULL);
457*4f1223e8SApple OSS Distributions 	T_QUIET;
458*4f1223e8SApple OSS Distributions 	switch (ip6->ip6_nxt) {
459*4f1223e8SApple OSS Distributions 	case IPPROTO_UDP: {
460*4f1223e8SApple OSS Distributions 		u_int                   data_len;
461*4f1223e8SApple OSS Distributions 		const ip6_udp_header_t *ip6_udp;
462*4f1223e8SApple OSS Distributions 		u_int                   udp_len;
463*4f1223e8SApple OSS Distributions 
464*4f1223e8SApple OSS Distributions 		ip6_udp = (const ip6_udp_header_t *)buf;
465*4f1223e8SApple OSS Distributions 		T_QUIET;
466*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, (u_int)sizeof(*ip6_udp), NULL);
467*4f1223e8SApple OSS Distributions 		udp_len = ntohs(ip6_udp->udp.uh_ulen);
468*4f1223e8SApple OSS Distributions 		T_QUIET;
469*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(udp_len, (u_int)sizeof(ip6_udp->udp), NULL);
470*4f1223e8SApple OSS Distributions 		data_len = udp_len - (u_int)sizeof(ip6_udp->udp);
471*4f1223e8SApple OSS Distributions 		if (dump) {
472*4f1223e8SApple OSS Distributions 			T_LOG("udp src 0x%x dst 0x%x len %u"
473*4f1223e8SApple OSS Distributions 			    " csum 0x%x datalen %u",
474*4f1223e8SApple OSS Distributions 			    ntohs(ip6_udp->udp.uh_sport),
475*4f1223e8SApple OSS Distributions 			    ntohs(ip6_udp->udp.uh_dport),
476*4f1223e8SApple OSS Distributions 			    udp_len,
477*4f1223e8SApple OSS Distributions 			    ntohs(ip6_udp->udp.uh_sum),
478*4f1223e8SApple OSS Distributions 			    data_len);
479*4f1223e8SApple OSS Distributions 		}
480*4f1223e8SApple OSS Distributions 		break;
481*4f1223e8SApple OSS Distributions 	}
482*4f1223e8SApple OSS Distributions 	case IPPROTO_ICMPV6: {
483*4f1223e8SApple OSS Distributions 		const struct icmp6_hdr *icmp6;
484*4f1223e8SApple OSS Distributions 		u_int                   icmp6_len;
485*4f1223e8SApple OSS Distributions 
486*4f1223e8SApple OSS Distributions 		icmp6_len = buf_len - sizeof(*ip6);
487*4f1223e8SApple OSS Distributions 		T_QUIET;
488*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, icmp6_len, NULL);
489*4f1223e8SApple OSS Distributions 		icmp6 = (const struct icmp6_hdr *)(ip6 + 1);
490*4f1223e8SApple OSS Distributions 		switch (icmp6->icmp6_type) {
491*4f1223e8SApple OSS Distributions 		case ND_NEIGHBOR_SOLICIT:
492*4f1223e8SApple OSS Distributions 			if (dump) {
493*4f1223e8SApple OSS Distributions 				T_LOG("neighbor solicit");
494*4f1223e8SApple OSS Distributions 			}
495*4f1223e8SApple OSS Distributions 			break;
496*4f1223e8SApple OSS Distributions 		case ND_NEIGHBOR_ADVERT:
497*4f1223e8SApple OSS Distributions 			if (dump) {
498*4f1223e8SApple OSS Distributions 				T_LOG("neighbor advert");
499*4f1223e8SApple OSS Distributions 			}
500*4f1223e8SApple OSS Distributions 			break;
501*4f1223e8SApple OSS Distributions 		case ND_ROUTER_SOLICIT:
502*4f1223e8SApple OSS Distributions 			if (dump) {
503*4f1223e8SApple OSS Distributions 				T_LOG("router solicit");
504*4f1223e8SApple OSS Distributions 			}
505*4f1223e8SApple OSS Distributions 			break;
506*4f1223e8SApple OSS Distributions 		default:
507*4f1223e8SApple OSS Distributions 			if (dump) {
508*4f1223e8SApple OSS Distributions 				T_LOG("icmp6 code 0x%x", icmp6->icmp6_type);
509*4f1223e8SApple OSS Distributions 			}
510*4f1223e8SApple OSS Distributions 			break;
511*4f1223e8SApple OSS Distributions 		}
512*4f1223e8SApple OSS Distributions 		break;
513*4f1223e8SApple OSS Distributions 	}
514*4f1223e8SApple OSS Distributions 	default:
515*4f1223e8SApple OSS Distributions 		break;
516*4f1223e8SApple OSS Distributions 	}
517*4f1223e8SApple OSS Distributions }
518*4f1223e8SApple OSS Distributions 
519*4f1223e8SApple OSS Distributions static void
ethernet_frame_validate(const void * buf,u_int buf_len,bool dump)520*4f1223e8SApple OSS Distributions ethernet_frame_validate(const void * buf, u_int buf_len, bool dump)
521*4f1223e8SApple OSS Distributions {
522*4f1223e8SApple OSS Distributions 	char                    ether_dst[ETHER_NTOA_BUFSIZE];
523*4f1223e8SApple OSS Distributions 	char                    ether_src[ETHER_NTOA_BUFSIZE];
524*4f1223e8SApple OSS Distributions 	uint16_t                ether_type;
525*4f1223e8SApple OSS Distributions 	const ether_header_t *  eh_p;
526*4f1223e8SApple OSS Distributions 
527*4f1223e8SApple OSS Distributions 	T_QUIET;
528*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)sizeof(*eh_p), NULL);
529*4f1223e8SApple OSS Distributions 	eh_p = (const ether_header_t *)buf;
530*4f1223e8SApple OSS Distributions 	ether_type = ntohs(eh_p->ether_type);
531*4f1223e8SApple OSS Distributions 	ether_ntoa_buf((const ether_addr_t *)&eh_p->ether_dhost,
532*4f1223e8SApple OSS Distributions 	    ether_dst, sizeof(ether_dst));
533*4f1223e8SApple OSS Distributions 	ether_ntoa_buf((const ether_addr_t *)&eh_p->ether_shost,
534*4f1223e8SApple OSS Distributions 	    ether_src, sizeof(ether_src));
535*4f1223e8SApple OSS Distributions 	if (dump) {
536*4f1223e8SApple OSS Distributions 		T_LOG("ether dst %s src %s type 0x%x",
537*4f1223e8SApple OSS Distributions 		    ether_dst, ether_src, ether_type);
538*4f1223e8SApple OSS Distributions 	}
539*4f1223e8SApple OSS Distributions 	switch (ether_type) {
540*4f1223e8SApple OSS Distributions 	case ETHERTYPE_IP:
541*4f1223e8SApple OSS Distributions 		ip_frame_validate(eh_p + 1, (u_int)(buf_len - sizeof(*eh_p)),
542*4f1223e8SApple OSS Distributions 		    dump);
543*4f1223e8SApple OSS Distributions 		break;
544*4f1223e8SApple OSS Distributions 	case ETHERTYPE_ARP:
545*4f1223e8SApple OSS Distributions 		arp_frame_validate((const struct ether_arp *)(eh_p + 1),
546*4f1223e8SApple OSS Distributions 		    (u_int)(buf_len - sizeof(*eh_p)),
547*4f1223e8SApple OSS Distributions 		    dump);
548*4f1223e8SApple OSS Distributions 		break;
549*4f1223e8SApple OSS Distributions 	case ETHERTYPE_IPV6:
550*4f1223e8SApple OSS Distributions 		ip6_frame_validate(eh_p + 1, (u_int)(buf_len - sizeof(*eh_p)),
551*4f1223e8SApple OSS Distributions 		    dump);
552*4f1223e8SApple OSS Distributions 		break;
553*4f1223e8SApple OSS Distributions 	default:
554*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized ethertype 0x%x", ether_type);
555*4f1223e8SApple OSS Distributions 		break;
556*4f1223e8SApple OSS Distributions 	}
557*4f1223e8SApple OSS Distributions }
558*4f1223e8SApple OSS Distributions 
559*4f1223e8SApple OSS Distributions static u_int
ethernet_udp_frame_populate(void * buf,size_t buf_len,uint8_t af,const ether_addr_t * src,union ifbrip * src_ip,uint16_t src_port,const ether_addr_t * dst,union ifbrip * dst_ip,uint16_t dst_port,const void * data,u_int data_len)560*4f1223e8SApple OSS Distributions ethernet_udp_frame_populate(void * buf, size_t buf_len,
561*4f1223e8SApple OSS Distributions     uint8_t af,
562*4f1223e8SApple OSS Distributions     const ether_addr_t * src,
563*4f1223e8SApple OSS Distributions     union ifbrip * src_ip,
564*4f1223e8SApple OSS Distributions     uint16_t src_port,
565*4f1223e8SApple OSS Distributions     const ether_addr_t * dst,
566*4f1223e8SApple OSS Distributions     union ifbrip * dst_ip,
567*4f1223e8SApple OSS Distributions     uint16_t dst_port,
568*4f1223e8SApple OSS Distributions     const void * data, u_int data_len)
569*4f1223e8SApple OSS Distributions {
570*4f1223e8SApple OSS Distributions 	u_int   len;
571*4f1223e8SApple OSS Distributions 
572*4f1223e8SApple OSS Distributions 	switch (af) {
573*4f1223e8SApple OSS Distributions 	case AF_INET:
574*4f1223e8SApple OSS Distributions 		len = ethernet_udp4_frame_populate(buf, buf_len,
575*4f1223e8SApple OSS Distributions 		    src,
576*4f1223e8SApple OSS Distributions 		    src_ip->ifbrip_addr,
577*4f1223e8SApple OSS Distributions 		    src_port,
578*4f1223e8SApple OSS Distributions 		    dst,
579*4f1223e8SApple OSS Distributions 		    dst_ip->ifbrip_addr,
580*4f1223e8SApple OSS Distributions 		    dst_port,
581*4f1223e8SApple OSS Distributions 		    data, data_len);
582*4f1223e8SApple OSS Distributions 		break;
583*4f1223e8SApple OSS Distributions 	case AF_INET6:
584*4f1223e8SApple OSS Distributions 		len = ethernet_udp6_frame_populate(buf, buf_len,
585*4f1223e8SApple OSS Distributions 		    src,
586*4f1223e8SApple OSS Distributions 		    &src_ip->ifbrip_addr6,
587*4f1223e8SApple OSS Distributions 		    src_port,
588*4f1223e8SApple OSS Distributions 		    dst,
589*4f1223e8SApple OSS Distributions 		    &dst_ip->ifbrip_addr6,
590*4f1223e8SApple OSS Distributions 		    dst_port,
591*4f1223e8SApple OSS Distributions 		    data, data_len);
592*4f1223e8SApple OSS Distributions 		break;
593*4f1223e8SApple OSS Distributions 	default:
594*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
595*4f1223e8SApple OSS Distributions 		len = 0;
596*4f1223e8SApple OSS Distributions 		break;
597*4f1223e8SApple OSS Distributions 	}
598*4f1223e8SApple OSS Distributions 	return len;
599*4f1223e8SApple OSS Distributions }
600*4f1223e8SApple OSS Distributions 
601*4f1223e8SApple OSS Distributions static u_int
ethernet_arp_frame_populate(void * buf,u_int buf_len,uint16_t op,const ether_addr_t * sender_hw,struct in_addr sender_ip,const ether_addr_t * target_hw,struct in_addr target_ip)602*4f1223e8SApple OSS Distributions ethernet_arp_frame_populate(void * buf, u_int buf_len,
603*4f1223e8SApple OSS Distributions     uint16_t op,
604*4f1223e8SApple OSS Distributions     const ether_addr_t * sender_hw,
605*4f1223e8SApple OSS Distributions     struct in_addr sender_ip,
606*4f1223e8SApple OSS Distributions     const ether_addr_t * target_hw,
607*4f1223e8SApple OSS Distributions     struct in_addr target_ip)
608*4f1223e8SApple OSS Distributions {
609*4f1223e8SApple OSS Distributions 	ether_header_t *        eh_p;
610*4f1223e8SApple OSS Distributions 	struct ether_arp *      earp;
611*4f1223e8SApple OSS Distributions 	struct arphdr *         arp_p;
612*4f1223e8SApple OSS Distributions 	u_int                   frame_length;
613*4f1223e8SApple OSS Distributions 
614*4f1223e8SApple OSS Distributions 	frame_length = sizeof(*earp) + sizeof(*eh_p);
615*4f1223e8SApple OSS Distributions 	T_QUIET;
616*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, frame_length,
617*4f1223e8SApple OSS Distributions 	    "%s buffer size %u needed %u",
618*4f1223e8SApple OSS Distributions 	    __func__, buf_len, frame_length);
619*4f1223e8SApple OSS Distributions 
620*4f1223e8SApple OSS Distributions 	/* ethernet_header */
621*4f1223e8SApple OSS Distributions 	eh_p = (ether_header_t *)buf;
622*4f1223e8SApple OSS Distributions 	bcopy(sender_hw, eh_p->ether_shost, ETHER_ADDR_LEN);
623*4f1223e8SApple OSS Distributions 	if (target_hw != NULL) {
624*4f1223e8SApple OSS Distributions 		bcopy(target_hw, eh_p->ether_dhost,
625*4f1223e8SApple OSS Distributions 		    sizeof(eh_p->ether_dhost));
626*4f1223e8SApple OSS Distributions 	} else {
627*4f1223e8SApple OSS Distributions 		bcopy(&ether_broadcast, eh_p->ether_dhost,
628*4f1223e8SApple OSS Distributions 		    sizeof(eh_p->ether_dhost));
629*4f1223e8SApple OSS Distributions 	}
630*4f1223e8SApple OSS Distributions 	eh_p->ether_type = htons(ETHERTYPE_ARP);
631*4f1223e8SApple OSS Distributions 
632*4f1223e8SApple OSS Distributions 	/* ARP payload */
633*4f1223e8SApple OSS Distributions 	earp = (struct ether_arp *)(void *)(eh_p + 1);
634*4f1223e8SApple OSS Distributions 	arp_p = &earp->ea_hdr;
635*4f1223e8SApple OSS Distributions 	arp_p->ar_hrd = htons(ARPHRD_ETHER);
636*4f1223e8SApple OSS Distributions 	arp_p->ar_pro = htons(ETHERTYPE_IP);
637*4f1223e8SApple OSS Distributions 	arp_p->ar_hln = sizeof(earp->arp_sha);
638*4f1223e8SApple OSS Distributions 	arp_p->ar_pln = sizeof(struct in_addr);
639*4f1223e8SApple OSS Distributions 	arp_p->ar_op = htons(op);
640*4f1223e8SApple OSS Distributions 	bcopy(sender_hw, earp->arp_sha, sizeof(earp->arp_sha));
641*4f1223e8SApple OSS Distributions 	bcopy(&sender_ip, earp->arp_spa, sizeof(earp->arp_spa));
642*4f1223e8SApple OSS Distributions 	if (target_hw != NULL) {
643*4f1223e8SApple OSS Distributions 		bcopy(target_hw, earp->arp_tha, sizeof(earp->arp_tha));
644*4f1223e8SApple OSS Distributions 	} else {
645*4f1223e8SApple OSS Distributions 		bzero(earp->arp_tha, sizeof(earp->arp_tha));
646*4f1223e8SApple OSS Distributions 	}
647*4f1223e8SApple OSS Distributions 	bcopy(&target_ip, earp->arp_tpa, sizeof(earp->arp_tpa));
648*4f1223e8SApple OSS Distributions 	return frame_length;
649*4f1223e8SApple OSS Distributions }
650*4f1223e8SApple OSS Distributions 
651*4f1223e8SApple OSS Distributions static uint32_t G_generation;
652*4f1223e8SApple OSS Distributions 
653*4f1223e8SApple OSS Distributions static uint32_t
next_generation(void)654*4f1223e8SApple OSS Distributions next_generation(void)
655*4f1223e8SApple OSS Distributions {
656*4f1223e8SApple OSS Distributions 	return G_generation++;
657*4f1223e8SApple OSS Distributions }
658*4f1223e8SApple OSS Distributions 
659*4f1223e8SApple OSS Distributions static const void *
ethernet_frame_get_udp4_payload(void * buf,u_int buf_len,u_int * ret_payload_length)660*4f1223e8SApple OSS Distributions ethernet_frame_get_udp4_payload(void * buf, u_int buf_len,
661*4f1223e8SApple OSS Distributions     u_int * ret_payload_length)
662*4f1223e8SApple OSS Distributions {
663*4f1223e8SApple OSS Distributions 	ether_header_t *        eh_p;
664*4f1223e8SApple OSS Distributions 	uint16_t                ether_type;
665*4f1223e8SApple OSS Distributions 	ip_udp_header_t *       ip_udp;
666*4f1223e8SApple OSS Distributions 	u_int                   ip_len;
667*4f1223e8SApple OSS Distributions 	u_int                   left;
668*4f1223e8SApple OSS Distributions 	const void *            payload = NULL;
669*4f1223e8SApple OSS Distributions 	u_int                   payload_length = 0;
670*4f1223e8SApple OSS Distributions 	u_int                   udp_len;
671*4f1223e8SApple OSS Distributions 
672*4f1223e8SApple OSS Distributions 	T_QUIET;
673*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)), NULL);
674*4f1223e8SApple OSS Distributions 	left = buf_len;
675*4f1223e8SApple OSS Distributions 	eh_p = (ether_header_t *)buf;
676*4f1223e8SApple OSS Distributions 	ether_type = ntohs(eh_p->ether_type);
677*4f1223e8SApple OSS Distributions 	T_QUIET;
678*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ether_type, ETHERTYPE_IP, NULL);
679*4f1223e8SApple OSS Distributions 	ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
680*4f1223e8SApple OSS Distributions 	left -= sizeof(*eh_p);
681*4f1223e8SApple OSS Distributions 	ip_len = ntohs(ip_udp->ip.ip_len);
682*4f1223e8SApple OSS Distributions 	T_QUIET;
683*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(left, ip_len, NULL);
684*4f1223e8SApple OSS Distributions 	T_QUIET;
685*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ip_udp->ip.ip_v, IPVERSION, NULL);
686*4f1223e8SApple OSS Distributions 	T_QUIET;
687*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)ip_udp->ip.ip_hl << 2, (u_int)sizeof(struct ip),
688*4f1223e8SApple OSS Distributions 	        NULL);
689*4f1223e8SApple OSS Distributions 	T_QUIET;
690*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ip_udp->ip.ip_p, IPPROTO_UDP, NULL);
691*4f1223e8SApple OSS Distributions 	T_QUIET;
692*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)sizeof(*ip_udp), NULL);
693*4f1223e8SApple OSS Distributions 	udp_len = ntohs(ip_udp->udp.uh_ulen);
694*4f1223e8SApple OSS Distributions 	T_QUIET;
695*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(udp_len, (u_int)sizeof(ip_udp->udp), NULL);
696*4f1223e8SApple OSS Distributions 	payload_length = udp_len - (int)sizeof(ip_udp->udp);
697*4f1223e8SApple OSS Distributions 	if (payload_length > 0) {
698*4f1223e8SApple OSS Distributions 		payload = (ip_udp + 1);
699*4f1223e8SApple OSS Distributions 	}
700*4f1223e8SApple OSS Distributions 	if (payload == NULL) {
701*4f1223e8SApple OSS Distributions 		payload_length = 0;
702*4f1223e8SApple OSS Distributions 	}
703*4f1223e8SApple OSS Distributions 	*ret_payload_length = payload_length;
704*4f1223e8SApple OSS Distributions 	return payload;
705*4f1223e8SApple OSS Distributions }
706*4f1223e8SApple OSS Distributions 
707*4f1223e8SApple OSS Distributions static const void *
ethernet_frame_get_udp6_payload(void * buf,u_int buf_len,u_int * ret_payload_length)708*4f1223e8SApple OSS Distributions ethernet_frame_get_udp6_payload(void * buf, u_int buf_len,
709*4f1223e8SApple OSS Distributions     u_int * ret_payload_length)
710*4f1223e8SApple OSS Distributions {
711*4f1223e8SApple OSS Distributions 	ether_header_t *        eh_p;
712*4f1223e8SApple OSS Distributions 	uint16_t                ether_type;
713*4f1223e8SApple OSS Distributions 	ip6_udp_header_t *      ip6_udp;
714*4f1223e8SApple OSS Distributions 	u_int                   ip6_len;
715*4f1223e8SApple OSS Distributions 	u_int                   left;
716*4f1223e8SApple OSS Distributions 	const void *            payload = NULL;
717*4f1223e8SApple OSS Distributions 	u_int                   payload_length = 0;
718*4f1223e8SApple OSS Distributions 	u_int                   udp_len;
719*4f1223e8SApple OSS Distributions 
720*4f1223e8SApple OSS Distributions 	T_QUIET;
721*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)), NULL);
722*4f1223e8SApple OSS Distributions 	left = buf_len;
723*4f1223e8SApple OSS Distributions 	eh_p = (ether_header_t *)buf;
724*4f1223e8SApple OSS Distributions 	ether_type = ntohs(eh_p->ether_type);
725*4f1223e8SApple OSS Distributions 	T_QUIET;
726*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ether_type, ETHERTYPE_IPV6, NULL);
727*4f1223e8SApple OSS Distributions 	ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
728*4f1223e8SApple OSS Distributions 	left -= sizeof(*eh_p);
729*4f1223e8SApple OSS Distributions 	ip6_len = ntohs(ip6_udp->ip6.ip6_plen);
730*4f1223e8SApple OSS Distributions 	T_QUIET;
731*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(left, ip6_len + (u_int)sizeof(struct ip6_hdr), NULL);
732*4f1223e8SApple OSS Distributions 	T_QUIET;
733*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)(ip6_udp->ip6.ip6_vfc & IPV6_VERSION_MASK),
734*4f1223e8SApple OSS Distributions 	    IPV6_VERSION, NULL);
735*4f1223e8SApple OSS Distributions 	T_QUIET;
736*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ip6_udp->ip6.ip6_nxt, IPPROTO_UDP, NULL);
737*4f1223e8SApple OSS Distributions 	T_QUIET;
738*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, (u_int)sizeof(*ip6_udp), NULL);
739*4f1223e8SApple OSS Distributions 	udp_len = ntohs(ip6_udp->udp.uh_ulen);
740*4f1223e8SApple OSS Distributions 	T_QUIET;
741*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(udp_len, (u_int)sizeof(ip6_udp->udp), NULL);
742*4f1223e8SApple OSS Distributions 	payload_length = udp_len - (int)sizeof(ip6_udp->udp);
743*4f1223e8SApple OSS Distributions 	if (payload_length > 0) {
744*4f1223e8SApple OSS Distributions 		payload = (ip6_udp + 1);
745*4f1223e8SApple OSS Distributions 	}
746*4f1223e8SApple OSS Distributions 	if (payload == NULL) {
747*4f1223e8SApple OSS Distributions 		payload_length = 0;
748*4f1223e8SApple OSS Distributions 	}
749*4f1223e8SApple OSS Distributions 	*ret_payload_length = payload_length;
750*4f1223e8SApple OSS Distributions 	return payload;
751*4f1223e8SApple OSS Distributions }
752*4f1223e8SApple OSS Distributions 
753*4f1223e8SApple OSS Distributions static const void *
ethernet_frame_get_udp_payload(uint8_t af,void * buf,u_int buf_len,u_int * ret_payload_length)754*4f1223e8SApple OSS Distributions ethernet_frame_get_udp_payload(uint8_t af, void * buf, u_int buf_len,
755*4f1223e8SApple OSS Distributions     u_int * ret_payload_length)
756*4f1223e8SApple OSS Distributions {
757*4f1223e8SApple OSS Distributions 	const void *    payload;
758*4f1223e8SApple OSS Distributions 
759*4f1223e8SApple OSS Distributions 	switch (af) {
760*4f1223e8SApple OSS Distributions 	case AF_INET:
761*4f1223e8SApple OSS Distributions 		payload = ethernet_frame_get_udp4_payload(buf, buf_len,
762*4f1223e8SApple OSS Distributions 		    ret_payload_length);
763*4f1223e8SApple OSS Distributions 		break;
764*4f1223e8SApple OSS Distributions 	case AF_INET6:
765*4f1223e8SApple OSS Distributions 		payload = ethernet_frame_get_udp6_payload(buf, buf_len,
766*4f1223e8SApple OSS Distributions 		    ret_payload_length);
767*4f1223e8SApple OSS Distributions 		break;
768*4f1223e8SApple OSS Distributions 	default:
769*4f1223e8SApple OSS Distributions 		T_FAIL("unrecognized address family %u", af);
770*4f1223e8SApple OSS Distributions 		payload = NULL;
771*4f1223e8SApple OSS Distributions 		break;
772*4f1223e8SApple OSS Distributions 	}
773*4f1223e8SApple OSS Distributions 	return payload;
774*4f1223e8SApple OSS Distributions }
775*4f1223e8SApple OSS Distributions 
776*4f1223e8SApple OSS Distributions #define MIN_ICMP6_LEN           ((u_int)(sizeof(ether_header_t) +       \
777*4f1223e8SApple OSS Distributions 	                                 sizeof(struct ip6_hdr) +       \
778*4f1223e8SApple OSS Distributions 	                                 sizeof(struct icmp6_hdr)))
779*4f1223e8SApple OSS Distributions #define ALIGNED_ND_OPT_LEN      8
780*4f1223e8SApple OSS Distributions #define SET_ND_OPT_LEN(a)       (u_int)((a) >> 3)
781*4f1223e8SApple OSS Distributions #define GET_ND_OPT_LEN(a)       (u_int)((a) << 3)
782*4f1223e8SApple OSS Distributions #define ALIGN_ND_OPT(a)         (u_int)roundup(a, ALIGNED_ND_OPT_LEN)
783*4f1223e8SApple OSS Distributions #define LINKADDR_OPT_LEN        (ALIGN_ND_OPT(sizeof(struct nd_opt_hdr) + \
784*4f1223e8SApple OSS Distributions 	                                      sizeof(ether_addr_t)))
785*4f1223e8SApple OSS Distributions #define ETHER_IPV6_LEN  (sizeof(*eh_p) + sizeof(*ip6))
786*4f1223e8SApple OSS Distributions 
787*4f1223e8SApple OSS Distributions 
788*4f1223e8SApple OSS Distributions 
789*4f1223e8SApple OSS Distributions static u_int
ethernet_nd6_frame_populate(void * buf,u_int buf_len,uint8_t type,const ether_addr_t * sender_hw,struct in6_addr * sender_ip,const ether_addr_t * dest_ether,const ether_addr_t * target_hw,struct in6_addr * target_ip)790*4f1223e8SApple OSS Distributions ethernet_nd6_frame_populate(void * buf, u_int buf_len,
791*4f1223e8SApple OSS Distributions     uint8_t type,
792*4f1223e8SApple OSS Distributions     const ether_addr_t * sender_hw,
793*4f1223e8SApple OSS Distributions     struct in6_addr * sender_ip,
794*4f1223e8SApple OSS Distributions     const ether_addr_t * dest_ether,
795*4f1223e8SApple OSS Distributions     const ether_addr_t * target_hw,
796*4f1223e8SApple OSS Distributions     struct in6_addr * target_ip)
797*4f1223e8SApple OSS Distributions {
798*4f1223e8SApple OSS Distributions 	u_int                           data_len = 0;
799*4f1223e8SApple OSS Distributions 	ether_header_t *                eh_p;
800*4f1223e8SApple OSS Distributions 	u_int                           frame_length;
801*4f1223e8SApple OSS Distributions 	struct icmp6_hdr *              icmp6;
802*4f1223e8SApple OSS Distributions 	struct ip6_hdr *                ip6;
803*4f1223e8SApple OSS Distributions 	struct nd_opt_hdr *             nd_opt;
804*4f1223e8SApple OSS Distributions 
805*4f1223e8SApple OSS Distributions 	switch (type) {
806*4f1223e8SApple OSS Distributions 	case ND_ROUTER_SOLICIT:
807*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_ADVERT:
808*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_SOLICIT:
809*4f1223e8SApple OSS Distributions 		break;
810*4f1223e8SApple OSS Distributions 	default:
811*4f1223e8SApple OSS Distributions 		T_FAIL("%s: unsupported type %u", __func__, type);
812*4f1223e8SApple OSS Distributions 		return 0;
813*4f1223e8SApple OSS Distributions 	}
814*4f1223e8SApple OSS Distributions 
815*4f1223e8SApple OSS Distributions 	T_QUIET;
816*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(buf_len, MIN_ICMP6_LEN, NULL);
817*4f1223e8SApple OSS Distributions 
818*4f1223e8SApple OSS Distributions 	eh_p = (ether_header_t *)buf;
819*4f1223e8SApple OSS Distributions 	ip6 = (struct ip6_hdr *)(void *)(eh_p + 1);
820*4f1223e8SApple OSS Distributions 	icmp6 = (struct icmp6_hdr *)(void *)(ip6 + 1);
821*4f1223e8SApple OSS Distributions 	frame_length = sizeof(*eh_p) + sizeof(*ip6);
822*4f1223e8SApple OSS Distributions 	switch (type) {
823*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_SOLICIT: {
824*4f1223e8SApple OSS Distributions 		struct nd_neighbor_solicit *    nd_ns;
825*4f1223e8SApple OSS Distributions 		bool                            sender_is_specified;
826*4f1223e8SApple OSS Distributions 
827*4f1223e8SApple OSS Distributions 		sender_is_specified = !IN6_IS_ADDR_UNSPECIFIED(sender_ip);
828*4f1223e8SApple OSS Distributions 		data_len = sizeof(*nd_ns);
829*4f1223e8SApple OSS Distributions 		if (sender_is_specified) {
830*4f1223e8SApple OSS Distributions 			data_len += LINKADDR_OPT_LEN;
831*4f1223e8SApple OSS Distributions 		}
832*4f1223e8SApple OSS Distributions 		frame_length += data_len;
833*4f1223e8SApple OSS Distributions 		T_QUIET;
834*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, frame_length, NULL);
835*4f1223e8SApple OSS Distributions 		nd_ns = (struct nd_neighbor_solicit *)(void *)icmp6;
836*4f1223e8SApple OSS Distributions 		if (sender_is_specified) {
837*4f1223e8SApple OSS Distributions 			/* add the source lladdr option */
838*4f1223e8SApple OSS Distributions 			nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
839*4f1223e8SApple OSS Distributions 			nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
840*4f1223e8SApple OSS Distributions 			nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
841*4f1223e8SApple OSS Distributions 			bcopy(sender_hw, (nd_opt + 1), sizeof(*sender_hw));
842*4f1223e8SApple OSS Distributions 		}
843*4f1223e8SApple OSS Distributions 		bcopy(target_ip, &nd_ns->nd_ns_target,
844*4f1223e8SApple OSS Distributions 		    sizeof(nd_ns->nd_ns_target));
845*4f1223e8SApple OSS Distributions 		break;
846*4f1223e8SApple OSS Distributions 	}
847*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_ADVERT: {
848*4f1223e8SApple OSS Distributions 		struct nd_neighbor_advert *     nd_na;
849*4f1223e8SApple OSS Distributions 
850*4f1223e8SApple OSS Distributions 		data_len = sizeof(*nd_na) + LINKADDR_OPT_LEN;
851*4f1223e8SApple OSS Distributions 		frame_length += data_len;
852*4f1223e8SApple OSS Distributions 		T_QUIET;
853*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, frame_length, NULL);
854*4f1223e8SApple OSS Distributions 
855*4f1223e8SApple OSS Distributions 		nd_na = (struct nd_neighbor_advert *)(void *)icmp6;
856*4f1223e8SApple OSS Distributions 		bcopy(target_ip, &nd_na->nd_na_target,
857*4f1223e8SApple OSS Distributions 		    sizeof(nd_na->nd_na_target));
858*4f1223e8SApple OSS Distributions 		/* add the target lladdr option */
859*4f1223e8SApple OSS Distributions 		nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
860*4f1223e8SApple OSS Distributions 		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
861*4f1223e8SApple OSS Distributions 		nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
862*4f1223e8SApple OSS Distributions 		bcopy(target_hw, (nd_opt + 1), sizeof(*target_hw));
863*4f1223e8SApple OSS Distributions 		break;
864*4f1223e8SApple OSS Distributions 	}
865*4f1223e8SApple OSS Distributions 	case ND_ROUTER_SOLICIT: {
866*4f1223e8SApple OSS Distributions 		struct nd_router_solicit *      nd_rs;
867*4f1223e8SApple OSS Distributions 
868*4f1223e8SApple OSS Distributions 		data_len = sizeof(*nd_rs) + LINKADDR_OPT_LEN;
869*4f1223e8SApple OSS Distributions 		frame_length += data_len;
870*4f1223e8SApple OSS Distributions 		T_QUIET;
871*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(buf_len, frame_length, NULL);
872*4f1223e8SApple OSS Distributions 
873*4f1223e8SApple OSS Distributions 		nd_rs = (struct nd_router_solicit *)(void *)icmp6;
874*4f1223e8SApple OSS Distributions 
875*4f1223e8SApple OSS Distributions 		/* add the source lladdr option */
876*4f1223e8SApple OSS Distributions 		nd_opt = (struct nd_opt_hdr *)(nd_rs + 1);
877*4f1223e8SApple OSS Distributions 		nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
878*4f1223e8SApple OSS Distributions 		nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
879*4f1223e8SApple OSS Distributions 		bcopy(sender_hw, (nd_opt + 1), sizeof(*sender_hw));
880*4f1223e8SApple OSS Distributions 		break;
881*4f1223e8SApple OSS Distributions 	}
882*4f1223e8SApple OSS Distributions 	default:
883*4f1223e8SApple OSS Distributions 		T_FAIL("%s: unsupported type %u", __func__, type);
884*4f1223e8SApple OSS Distributions 		return 0;
885*4f1223e8SApple OSS Distributions 	}
886*4f1223e8SApple OSS Distributions 	/* icmp6 header */
887*4f1223e8SApple OSS Distributions 	icmp6->icmp6_type = type;
888*4f1223e8SApple OSS Distributions 	icmp6->icmp6_code = 0;
889*4f1223e8SApple OSS Distributions 	icmp6->icmp6_cksum = 0;
890*4f1223e8SApple OSS Distributions 	icmp6->icmp6_data32[0] = 0;
891*4f1223e8SApple OSS Distributions 
892*4f1223e8SApple OSS Distributions 	/* ethernet_header */
893*4f1223e8SApple OSS Distributions 	bcopy(sender_hw, eh_p->ether_shost, ETHER_ADDR_LEN);
894*4f1223e8SApple OSS Distributions 	if (dest_ether != NULL) {
895*4f1223e8SApple OSS Distributions 		bcopy(dest_ether, eh_p->ether_dhost,
896*4f1223e8SApple OSS Distributions 		    sizeof(eh_p->ether_dhost));
897*4f1223e8SApple OSS Distributions 	} else {
898*4f1223e8SApple OSS Distributions 		/* XXX ether_dhost should be multicast */
899*4f1223e8SApple OSS Distributions 		bcopy(&ether_broadcast, eh_p->ether_dhost,
900*4f1223e8SApple OSS Distributions 		    sizeof(eh_p->ether_dhost));
901*4f1223e8SApple OSS Distributions 	}
902*4f1223e8SApple OSS Distributions 	eh_p->ether_type = htons(ETHERTYPE_IPV6);
903*4f1223e8SApple OSS Distributions 
904*4f1223e8SApple OSS Distributions 	/* IPv6 header */
905*4f1223e8SApple OSS Distributions 	bzero(ip6, sizeof(*ip6));
906*4f1223e8SApple OSS Distributions 	ip6->ip6_nxt = IPPROTO_ICMPV6;
907*4f1223e8SApple OSS Distributions 	ip6->ip6_vfc = IPV6_VERSION;
908*4f1223e8SApple OSS Distributions 	bcopy(sender_ip, &ip6->ip6_src, sizeof(ip6->ip6_src));
909*4f1223e8SApple OSS Distributions 	/* XXX ip6_dst should be specific multicast */
910*4f1223e8SApple OSS Distributions 	bcopy(&in6addr_linklocal_allnodes, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
911*4f1223e8SApple OSS Distributions 	ip6->ip6_plen = htons(data_len);
912*4f1223e8SApple OSS Distributions 
913*4f1223e8SApple OSS Distributions 	return frame_length;
914*4f1223e8SApple OSS Distributions }
915*4f1223e8SApple OSS Distributions 
916*4f1223e8SApple OSS Distributions /**
917*4f1223e8SApple OSS Distributions ** Switch port
918*4f1223e8SApple OSS Distributions **/
919*4f1223e8SApple OSS Distributions static void
switch_port_check_tx(switch_port_t port)920*4f1223e8SApple OSS Distributions switch_port_check_tx(switch_port_t port)
921*4f1223e8SApple OSS Distributions {
922*4f1223e8SApple OSS Distributions 	int             error;
923*4f1223e8SApple OSS Distributions 	struct kevent   kev;
924*4f1223e8SApple OSS Distributions 	int             kq;
925*4f1223e8SApple OSS Distributions 	struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
926*4f1223e8SApple OSS Distributions 
927*4f1223e8SApple OSS Distributions 	kq = kqueue();
928*4f1223e8SApple OSS Distributions 	T_QUIET;
929*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(kq, "kqueue check_tx");
930*4f1223e8SApple OSS Distributions 	EV_SET(&kev, port->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
931*4f1223e8SApple OSS Distributions 	error = kevent(kq, &kev, 1, &kev, 1, &ts);
932*4f1223e8SApple OSS Distributions 	T_QUIET;
933*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(error, 1, "kevent");
934*4f1223e8SApple OSS Distributions 	T_QUIET;
935*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)kev.filter, EVFILT_WRITE, NULL);
936*4f1223e8SApple OSS Distributions 	T_QUIET;
937*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)kev.ident, port->fd, NULL);
938*4f1223e8SApple OSS Distributions 	T_QUIET;
939*4f1223e8SApple OSS Distributions 	T_ASSERT_NULL(kev.udata, NULL);
940*4f1223e8SApple OSS Distributions 	close(kq);
941*4f1223e8SApple OSS Distributions 	return;
942*4f1223e8SApple OSS Distributions }
943*4f1223e8SApple OSS Distributions 
944*4f1223e8SApple OSS Distributions static void
switch_port_send_arp(switch_port_t port,uint16_t op,const ether_addr_t * sender_hw,struct in_addr sender_ip,const ether_addr_t * target_hw,struct in_addr target_ip)945*4f1223e8SApple OSS Distributions switch_port_send_arp(switch_port_t port,
946*4f1223e8SApple OSS Distributions     uint16_t op,
947*4f1223e8SApple OSS Distributions     const ether_addr_t * sender_hw,
948*4f1223e8SApple OSS Distributions     struct in_addr sender_ip,
949*4f1223e8SApple OSS Distributions     const ether_addr_t * target_hw,
950*4f1223e8SApple OSS Distributions     struct in_addr target_ip)
951*4f1223e8SApple OSS Distributions {
952*4f1223e8SApple OSS Distributions 	u_int           frame_length;
953*4f1223e8SApple OSS Distributions 	ether_packet    pkt;
954*4f1223e8SApple OSS Distributions 	ssize_t         n;
955*4f1223e8SApple OSS Distributions 
956*4f1223e8SApple OSS Distributions 	/* make sure we can send */
957*4f1223e8SApple OSS Distributions 	switch_port_check_tx(port);
958*4f1223e8SApple OSS Distributions 	frame_length = ethernet_arp_frame_populate(&pkt, sizeof(pkt),
959*4f1223e8SApple OSS Distributions 	    op,
960*4f1223e8SApple OSS Distributions 	    sender_hw,
961*4f1223e8SApple OSS Distributions 	    sender_ip,
962*4f1223e8SApple OSS Distributions 	    target_hw,
963*4f1223e8SApple OSS Distributions 	    target_ip);
964*4f1223e8SApple OSS Distributions 	T_QUIET;
965*4f1223e8SApple OSS Distributions 	T_ASSERT_GT(frame_length, 0, "%s: frame_length %u",
966*4f1223e8SApple OSS Distributions 	    __func__, frame_length);
967*4f1223e8SApple OSS Distributions 	if (G_debug) {
968*4f1223e8SApple OSS Distributions 		T_LOG("Port %s -> %s transmitting %u bytes",
969*4f1223e8SApple OSS Distributions 		    port->ifname, port->member_ifname, frame_length);
970*4f1223e8SApple OSS Distributions 	}
971*4f1223e8SApple OSS Distributions 	ethernet_frame_validate(&pkt, frame_length, G_debug);
972*4f1223e8SApple OSS Distributions 	n = write(port->fd, &pkt, frame_length);
973*4f1223e8SApple OSS Distributions 	if (n < 0) {
974*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
975*4f1223e8SApple OSS Distributions 		    port->ifname, port->fd, n);
976*4f1223e8SApple OSS Distributions 	}
977*4f1223e8SApple OSS Distributions 	T_QUIET;
978*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)n, frame_length,
979*4f1223e8SApple OSS Distributions 	    "%s fd %d wrote %ld",
980*4f1223e8SApple OSS Distributions 	    port->ifname, port->fd, n);
981*4f1223e8SApple OSS Distributions }
982*4f1223e8SApple OSS Distributions 
983*4f1223e8SApple OSS Distributions 
984*4f1223e8SApple OSS Distributions static void
switch_port_send_nd6(switch_port_t port,uint8_t type,const ether_addr_t * sender_hw,struct in6_addr * sender_ip,const ether_addr_t * dest_ether,const ether_addr_t * target_hw,struct in6_addr * target_ip)985*4f1223e8SApple OSS Distributions switch_port_send_nd6(switch_port_t port,
986*4f1223e8SApple OSS Distributions     uint8_t type,
987*4f1223e8SApple OSS Distributions     const ether_addr_t * sender_hw,
988*4f1223e8SApple OSS Distributions     struct in6_addr * sender_ip,
989*4f1223e8SApple OSS Distributions     const ether_addr_t * dest_ether,
990*4f1223e8SApple OSS Distributions     const ether_addr_t * target_hw,
991*4f1223e8SApple OSS Distributions     struct in6_addr * target_ip)
992*4f1223e8SApple OSS Distributions {
993*4f1223e8SApple OSS Distributions 	u_int           frame_length;
994*4f1223e8SApple OSS Distributions 	ether_packet    pkt;
995*4f1223e8SApple OSS Distributions 	ssize_t         n;
996*4f1223e8SApple OSS Distributions 
997*4f1223e8SApple OSS Distributions 	/* make sure we can send */
998*4f1223e8SApple OSS Distributions 	switch_port_check_tx(port);
999*4f1223e8SApple OSS Distributions 	frame_length = ethernet_nd6_frame_populate(&pkt, sizeof(pkt),
1000*4f1223e8SApple OSS Distributions 	    type,
1001*4f1223e8SApple OSS Distributions 	    sender_hw,
1002*4f1223e8SApple OSS Distributions 	    sender_ip,
1003*4f1223e8SApple OSS Distributions 	    dest_ether,
1004*4f1223e8SApple OSS Distributions 	    target_hw,
1005*4f1223e8SApple OSS Distributions 	    target_ip);
1006*4f1223e8SApple OSS Distributions 	T_QUIET;
1007*4f1223e8SApple OSS Distributions 	T_ASSERT_GT(frame_length, 0, "%s: frame_length %u",
1008*4f1223e8SApple OSS Distributions 	    __func__, frame_length);
1009*4f1223e8SApple OSS Distributions 	if (G_debug) {
1010*4f1223e8SApple OSS Distributions 		T_LOG("Port %s -> %s transmitting %u bytes",
1011*4f1223e8SApple OSS Distributions 		    port->ifname, port->member_ifname, frame_length);
1012*4f1223e8SApple OSS Distributions 	}
1013*4f1223e8SApple OSS Distributions 	ethernet_frame_validate(&pkt, frame_length, G_debug);
1014*4f1223e8SApple OSS Distributions 	n = write(port->fd, &pkt, frame_length);
1015*4f1223e8SApple OSS Distributions 	if (n < 0) {
1016*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
1017*4f1223e8SApple OSS Distributions 		    port->ifname, port->fd, n);
1018*4f1223e8SApple OSS Distributions 	}
1019*4f1223e8SApple OSS Distributions 	T_QUIET;
1020*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)n, frame_length,
1021*4f1223e8SApple OSS Distributions 	    "%s fd %d wrote %ld",
1022*4f1223e8SApple OSS Distributions 	    port->ifname, port->fd, n);
1023*4f1223e8SApple OSS Distributions }
1024*4f1223e8SApple OSS Distributions 
1025*4f1223e8SApple OSS Distributions 
1026*4f1223e8SApple OSS Distributions static void
switch_port_send_udp(switch_port_t port,uint8_t af,const ether_addr_t * src_eaddr,union ifbrip * src_ip,uint16_t src_port,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,uint16_t dst_port,const void * payload,u_int payload_length)1027*4f1223e8SApple OSS Distributions switch_port_send_udp(switch_port_t port,
1028*4f1223e8SApple OSS Distributions     uint8_t af,
1029*4f1223e8SApple OSS Distributions     const ether_addr_t * src_eaddr,
1030*4f1223e8SApple OSS Distributions     union ifbrip * src_ip,
1031*4f1223e8SApple OSS Distributions     uint16_t src_port,
1032*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr,
1033*4f1223e8SApple OSS Distributions     union ifbrip * dst_ip,
1034*4f1223e8SApple OSS Distributions     uint16_t dst_port,
1035*4f1223e8SApple OSS Distributions     const void * payload, u_int payload_length)
1036*4f1223e8SApple OSS Distributions {
1037*4f1223e8SApple OSS Distributions 	u_int                   frame_length;
1038*4f1223e8SApple OSS Distributions 	ether_packet            pkt;
1039*4f1223e8SApple OSS Distributions 	ssize_t                 n;
1040*4f1223e8SApple OSS Distributions 
1041*4f1223e8SApple OSS Distributions 	/* make sure we can send */
1042*4f1223e8SApple OSS Distributions 	switch_port_check_tx(port);
1043*4f1223e8SApple OSS Distributions 
1044*4f1223e8SApple OSS Distributions 	/* generate the packet */
1045*4f1223e8SApple OSS Distributions 	frame_length
1046*4f1223e8SApple OSS Distributions 	        = ethernet_udp_frame_populate((void *)&pkt,
1047*4f1223e8SApple OSS Distributions 	    (u_int)sizeof(pkt),
1048*4f1223e8SApple OSS Distributions 	    af,
1049*4f1223e8SApple OSS Distributions 	    src_eaddr,
1050*4f1223e8SApple OSS Distributions 	    src_ip,
1051*4f1223e8SApple OSS Distributions 	    src_port,
1052*4f1223e8SApple OSS Distributions 	    dst_eaddr,
1053*4f1223e8SApple OSS Distributions 	    dst_ip,
1054*4f1223e8SApple OSS Distributions 	    dst_port,
1055*4f1223e8SApple OSS Distributions 	    payload,
1056*4f1223e8SApple OSS Distributions 	    payload_length);
1057*4f1223e8SApple OSS Distributions 	T_QUIET;
1058*4f1223e8SApple OSS Distributions 	T_ASSERT_GT(frame_length, 0, NULL);
1059*4f1223e8SApple OSS Distributions 	if (G_debug) {
1060*4f1223e8SApple OSS Distributions 		T_LOG("Port %s transmitting %u bytes",
1061*4f1223e8SApple OSS Distributions 		    port->ifname, frame_length);
1062*4f1223e8SApple OSS Distributions 	}
1063*4f1223e8SApple OSS Distributions 	ethernet_frame_validate(&pkt, frame_length, G_debug);
1064*4f1223e8SApple OSS Distributions 	n = write(port->fd, &pkt, frame_length);
1065*4f1223e8SApple OSS Distributions 	if (n < 0) {
1066*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
1067*4f1223e8SApple OSS Distributions 		    port->ifname, port->fd, n);
1068*4f1223e8SApple OSS Distributions 	}
1069*4f1223e8SApple OSS Distributions 	T_QUIET;
1070*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((u_int)n, frame_length,
1071*4f1223e8SApple OSS Distributions 	    "%s fd %d wrote %ld",
1072*4f1223e8SApple OSS Distributions 	    port->ifname, port->fd, n);
1073*4f1223e8SApple OSS Distributions }
1074*4f1223e8SApple OSS Distributions 
1075*4f1223e8SApple OSS Distributions 
1076*4f1223e8SApple OSS Distributions 
1077*4f1223e8SApple OSS Distributions static void
switch_port_send_udp_addr_index(switch_port_t port,uint8_t af,u_int addr_index,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,const void * payload,u_int payload_length)1078*4f1223e8SApple OSS Distributions switch_port_send_udp_addr_index(switch_port_t port,
1079*4f1223e8SApple OSS Distributions     uint8_t af,
1080*4f1223e8SApple OSS Distributions     u_int addr_index,
1081*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr,
1082*4f1223e8SApple OSS Distributions     union ifbrip * dst_ip,
1083*4f1223e8SApple OSS Distributions     const void * payload, u_int payload_length)
1084*4f1223e8SApple OSS Distributions {
1085*4f1223e8SApple OSS Distributions 	ether_addr_t    eaddr;
1086*4f1223e8SApple OSS Distributions 	union ifbrip    ip;
1087*4f1223e8SApple OSS Distributions 
1088*4f1223e8SApple OSS Distributions 	/* generate traffic for the unit and address */
1089*4f1223e8SApple OSS Distributions 	set_ethernet_address(&eaddr, port->unit, addr_index);
1090*4f1223e8SApple OSS Distributions 	get_ip_address(af, port->unit, addr_index, &ip);
1091*4f1223e8SApple OSS Distributions 	switch_port_send_udp(port, af,
1092*4f1223e8SApple OSS Distributions 	    &eaddr, &ip, TEST_SOURCE_PORT,
1093*4f1223e8SApple OSS Distributions 	    dst_eaddr, dst_ip, TEST_DEST_PORT,
1094*4f1223e8SApple OSS Distributions 	    payload, payload_length);
1095*4f1223e8SApple OSS Distributions }
1096*4f1223e8SApple OSS Distributions 
1097*4f1223e8SApple OSS Distributions typedef void
1098*4f1223e8SApple OSS Distributions (packet_validator)(switch_port_t port, const ether_header_t * eh_p,
1099*4f1223e8SApple OSS Distributions     u_int pkt_len, void * context);
1100*4f1223e8SApple OSS Distributions typedef packet_validator * packet_validator_t;
1101*4f1223e8SApple OSS Distributions 
1102*4f1223e8SApple OSS Distributions static void
switch_port_receive(switch_port_t port,uint8_t af,const void * payload,u_int payload_length,packet_validator_t validator,void * context)1103*4f1223e8SApple OSS Distributions switch_port_receive(switch_port_t port,
1104*4f1223e8SApple OSS Distributions     uint8_t af,
1105*4f1223e8SApple OSS Distributions     const void * payload, u_int payload_length,
1106*4f1223e8SApple OSS Distributions     packet_validator_t validator,
1107*4f1223e8SApple OSS Distributions     void * context)
1108*4f1223e8SApple OSS Distributions {
1109*4f1223e8SApple OSS Distributions 	ether_header_t *        eh_p;
1110*4f1223e8SApple OSS Distributions 	ssize_t                 n;
1111*4f1223e8SApple OSS Distributions 	char *                  offset;
1112*4f1223e8SApple OSS Distributions 
1113*4f1223e8SApple OSS Distributions 	n = read(port->fd, port->rx_buf, (unsigned)port->rx_buf_size);
1114*4f1223e8SApple OSS Distributions 	if (n < 0) {
1115*4f1223e8SApple OSS Distributions 		if (errno == EAGAIN) {
1116*4f1223e8SApple OSS Distributions 			return;
1117*4f1223e8SApple OSS Distributions 		}
1118*4f1223e8SApple OSS Distributions 		T_QUIET;
1119*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(n, "read %s port %d fd %d",
1120*4f1223e8SApple OSS Distributions 		    port->ifname, port->unit, port->fd);
1121*4f1223e8SApple OSS Distributions 		return;
1122*4f1223e8SApple OSS Distributions 	}
1123*4f1223e8SApple OSS Distributions 	for (offset = port->rx_buf; n > 0;) {
1124*4f1223e8SApple OSS Distributions 		struct bpf_hdr *        bpf = (struct bpf_hdr *)(void *)offset;
1125*4f1223e8SApple OSS Distributions 		u_int                   pkt_len;
1126*4f1223e8SApple OSS Distributions 		char *                  pkt;
1127*4f1223e8SApple OSS Distributions 		u_int                   skip;
1128*4f1223e8SApple OSS Distributions 
1129*4f1223e8SApple OSS Distributions 		pkt = offset + bpf->bh_hdrlen;
1130*4f1223e8SApple OSS Distributions 		pkt_len = bpf->bh_caplen;
1131*4f1223e8SApple OSS Distributions 
1132*4f1223e8SApple OSS Distributions 		eh_p = (ether_header_t *)(void *)pkt;
1133*4f1223e8SApple OSS Distributions 		T_QUIET;
1134*4f1223e8SApple OSS Distributions 		T_ASSERT_GE(pkt_len, (u_int)sizeof(*eh_p),
1135*4f1223e8SApple OSS Distributions 		    "short packet %ld", n);
1136*4f1223e8SApple OSS Distributions 
1137*4f1223e8SApple OSS Distributions 		/* source shouldn't be broadcast/multicast */
1138*4f1223e8SApple OSS Distributions 		T_QUIET;
1139*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(eh_p->ether_shost[0] & 0x01, 0,
1140*4f1223e8SApple OSS Distributions 		    "broadcast/multicast source");
1141*4f1223e8SApple OSS Distributions 
1142*4f1223e8SApple OSS Distributions 		if (G_debug) {
1143*4f1223e8SApple OSS Distributions 			T_LOG("Port %s [unit %d] [fd %d] Received %u bytes",
1144*4f1223e8SApple OSS Distributions 			    port->ifname, port->unit, port->fd, pkt_len);
1145*4f1223e8SApple OSS Distributions 		}
1146*4f1223e8SApple OSS Distributions 		ethernet_frame_validate(pkt, pkt_len, G_debug);
1147*4f1223e8SApple OSS Distributions 
1148*4f1223e8SApple OSS Distributions 		/* call the validation function */
1149*4f1223e8SApple OSS Distributions 		(*validator)(port, eh_p, pkt_len, context);
1150*4f1223e8SApple OSS Distributions 
1151*4f1223e8SApple OSS Distributions 		if (payload != NULL) {
1152*4f1223e8SApple OSS Distributions 			const void *    p;
1153*4f1223e8SApple OSS Distributions 			u_int           p_len;
1154*4f1223e8SApple OSS Distributions 
1155*4f1223e8SApple OSS Distributions 			p = ethernet_frame_get_udp_payload(af, pkt, pkt_len,
1156*4f1223e8SApple OSS Distributions 			    &p_len);
1157*4f1223e8SApple OSS Distributions 			T_QUIET;
1158*4f1223e8SApple OSS Distributions 			T_ASSERT_NOTNULL(p, "ethernet_frame_get_udp_payload");
1159*4f1223e8SApple OSS Distributions 			T_QUIET;
1160*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(p_len, payload_length,
1161*4f1223e8SApple OSS Distributions 			    "payload length %u < expected %u",
1162*4f1223e8SApple OSS Distributions 			    p_len, payload_length);
1163*4f1223e8SApple OSS Distributions 			T_QUIET;
1164*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(bcmp(payload, p, payload_length), 0,
1165*4f1223e8SApple OSS Distributions 			    "unexpected payload");
1166*4f1223e8SApple OSS Distributions 		}
1167*4f1223e8SApple OSS Distributions 		skip = BPF_WORDALIGN(pkt_len + bpf->bh_hdrlen);
1168*4f1223e8SApple OSS Distributions 		if (skip == 0) {
1169*4f1223e8SApple OSS Distributions 			break;
1170*4f1223e8SApple OSS Distributions 		}
1171*4f1223e8SApple OSS Distributions 		offset += skip;
1172*4f1223e8SApple OSS Distributions 		n -= skip;
1173*4f1223e8SApple OSS Distributions 	}
1174*4f1223e8SApple OSS Distributions 	return;
1175*4f1223e8SApple OSS Distributions }
1176*4f1223e8SApple OSS Distributions 
1177*4f1223e8SApple OSS Distributions static void
switch_port_log(switch_port_t port)1178*4f1223e8SApple OSS Distributions switch_port_log(switch_port_t port)
1179*4f1223e8SApple OSS Distributions {
1180*4f1223e8SApple OSS Distributions 	T_LOG("%s [unit %d] [member %s]%s bpf fd %d bufsize %d\n",
1181*4f1223e8SApple OSS Distributions 	    port->ifname, port->unit,
1182*4f1223e8SApple OSS Distributions 	    port->member_ifname,
1183*4f1223e8SApple OSS Distributions 	    port->mac_nat ? " [mac-nat]" : "",
1184*4f1223e8SApple OSS Distributions 	    port->fd, port->rx_buf_size);
1185*4f1223e8SApple OSS Distributions }
1186*4f1223e8SApple OSS Distributions 
1187*4f1223e8SApple OSS Distributions #define switch_port_list_size(port_count)               \
1188*4f1223e8SApple OSS Distributions 	offsetof(switch_port_list, list[port_count])
1189*4f1223e8SApple OSS Distributions 
1190*4f1223e8SApple OSS Distributions static switch_port_list_t
switch_port_list_alloc(u_int port_count,bool mac_nat)1191*4f1223e8SApple OSS Distributions switch_port_list_alloc(u_int port_count, bool mac_nat)
1192*4f1223e8SApple OSS Distributions {
1193*4f1223e8SApple OSS Distributions 	switch_port_list_t      list;
1194*4f1223e8SApple OSS Distributions 
1195*4f1223e8SApple OSS Distributions 	list = (switch_port_list_t)
1196*4f1223e8SApple OSS Distributions 	    calloc(1, switch_port_list_size(port_count));;
1197*4f1223e8SApple OSS Distributions 	list->size = port_count;
1198*4f1223e8SApple OSS Distributions 	list->mac_nat = mac_nat;
1199*4f1223e8SApple OSS Distributions 	return list;
1200*4f1223e8SApple OSS Distributions }
1201*4f1223e8SApple OSS Distributions 
1202*4f1223e8SApple OSS Distributions static void
switch_port_list_dealloc(switch_port_list_t list)1203*4f1223e8SApple OSS Distributions switch_port_list_dealloc(switch_port_list_t list)
1204*4f1223e8SApple OSS Distributions {
1205*4f1223e8SApple OSS Distributions 	u_int           i;
1206*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1207*4f1223e8SApple OSS Distributions 
1208*4f1223e8SApple OSS Distributions 	for (i = 0, port = list->list; i < list->count; i++, port++) {
1209*4f1223e8SApple OSS Distributions 		close(port->fd);
1210*4f1223e8SApple OSS Distributions 		free(port->rx_buf);
1211*4f1223e8SApple OSS Distributions 	}
1212*4f1223e8SApple OSS Distributions 	free(list);
1213*4f1223e8SApple OSS Distributions 	return;
1214*4f1223e8SApple OSS Distributions }
1215*4f1223e8SApple OSS Distributions 
1216*4f1223e8SApple OSS Distributions static errno_t
switch_port_list_add_port(switch_port_list_t port_list,u_int unit,const char * ifname,u_short if_index,const char * member_ifname,u_int num_addrs,bool mac_nat,struct in_addr * ip)1217*4f1223e8SApple OSS Distributions switch_port_list_add_port(switch_port_list_t port_list, u_int unit,
1218*4f1223e8SApple OSS Distributions     const char * ifname, u_short if_index, const char * member_ifname,
1219*4f1223e8SApple OSS Distributions     u_int num_addrs, bool mac_nat, struct in_addr * ip)
1220*4f1223e8SApple OSS Distributions {
1221*4f1223e8SApple OSS Distributions 	int             buf_size;
1222*4f1223e8SApple OSS Distributions 	errno_t         err = EINVAL;
1223*4f1223e8SApple OSS Distributions 	int             fd = -1;
1224*4f1223e8SApple OSS Distributions 	char            ntopbuf_ip[INET6_ADDRSTRLEN];
1225*4f1223e8SApple OSS Distributions 	int             opt;
1226*4f1223e8SApple OSS Distributions 	switch_port_t   p;
1227*4f1223e8SApple OSS Distributions 
1228*4f1223e8SApple OSS Distributions 	if (port_list->count >= port_list->size) {
1229*4f1223e8SApple OSS Distributions 		T_LOG("Internal error: port_list count %u >= size %u\n",
1230*4f1223e8SApple OSS Distributions 		    port_list->count, port_list->size);
1231*4f1223e8SApple OSS Distributions 		goto failed;
1232*4f1223e8SApple OSS Distributions 	}
1233*4f1223e8SApple OSS Distributions 	fd = bpf_new();
1234*4f1223e8SApple OSS Distributions 	if (fd < 0) {
1235*4f1223e8SApple OSS Distributions 		err = errno;
1236*4f1223e8SApple OSS Distributions 		T_LOG("bpf_new");
1237*4f1223e8SApple OSS Distributions 		goto failed;
1238*4f1223e8SApple OSS Distributions 	}
1239*4f1223e8SApple OSS Distributions 	bpf_set_traffic_class(fd, SO_TC_CTL);
1240*4f1223e8SApple OSS Distributions 	opt = 1;
1241*4f1223e8SApple OSS Distributions 	T_QUIET;
1242*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ioctl(fd, FIONBIO, &opt), NULL);
1243*4f1223e8SApple OSS Distributions 	T_QUIET;
1244*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_immediate(fd, 1), NULL);
1245*4f1223e8SApple OSS Distributions 	T_QUIET;
1246*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_setif(fd, ifname), "bpf set if %s",
1247*4f1223e8SApple OSS Distributions 	    ifname);
1248*4f1223e8SApple OSS Distributions 	T_QUIET;
1249*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_see_sent(fd, 0), NULL);
1250*4f1223e8SApple OSS Distributions 	T_QUIET;
1251*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_header_complete(fd, 1), NULL);
1252*4f1223e8SApple OSS Distributions 	T_QUIET;
1253*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_get_blen(fd, &buf_size), NULL);
1254*4f1223e8SApple OSS Distributions 	if (G_debug) {
1255*4f1223e8SApple OSS Distributions 		T_LOG("%s [unit %d] [member %s] bpf fd %d bufsize %d\n",
1256*4f1223e8SApple OSS Distributions 		    ifname, unit,
1257*4f1223e8SApple OSS Distributions 		    member_ifname, fd, buf_size);
1258*4f1223e8SApple OSS Distributions 	}
1259*4f1223e8SApple OSS Distributions 	p = port_list->list + port_list->count++;
1260*4f1223e8SApple OSS Distributions 	p->fd = fd;
1261*4f1223e8SApple OSS Distributions 	p->unit = unit;
1262*4f1223e8SApple OSS Distributions 	strlcpy(p->ifname, ifname, sizeof(p->ifname));
1263*4f1223e8SApple OSS Distributions 	strlcpy(p->member_ifname, member_ifname, sizeof(p->member_ifname));
1264*4f1223e8SApple OSS Distributions 	p->num_addrs = num_addrs;
1265*4f1223e8SApple OSS Distributions 	p->rx_buf_size = buf_size;
1266*4f1223e8SApple OSS Distributions 	p->rx_buf = malloc((unsigned)buf_size);
1267*4f1223e8SApple OSS Distributions 	p->mac_nat = mac_nat;
1268*4f1223e8SApple OSS Distributions 	ifnet_get_lladdr(ifname, &p->mac);
1269*4f1223e8SApple OSS Distributions 	ifnet_get_lladdr(member_ifname, &p->member_mac);
1270*4f1223e8SApple OSS Distributions 	p->ip = *ip;
1271*4f1223e8SApple OSS Distributions 	p->if_index = if_index;
1272*4f1223e8SApple OSS Distributions 	get_ipv6_ll_address(&p->mac, &p->ip6);
1273*4f1223e8SApple OSS Distributions 	inet_ntop(AF_INET6, &p->ip6, ntopbuf_ip, sizeof(ntopbuf_ip));
1274*4f1223e8SApple OSS Distributions 	T_LOG("%s %s", ifname, ntopbuf_ip);
1275*4f1223e8SApple OSS Distributions 	return 0;
1276*4f1223e8SApple OSS Distributions 
1277*4f1223e8SApple OSS Distributions failed:
1278*4f1223e8SApple OSS Distributions 	if (fd >= 0) {
1279*4f1223e8SApple OSS Distributions 		close(fd);
1280*4f1223e8SApple OSS Distributions 	}
1281*4f1223e8SApple OSS Distributions 	return err;
1282*4f1223e8SApple OSS Distributions }
1283*4f1223e8SApple OSS Distributions 
1284*4f1223e8SApple OSS Distributions static switch_port_t
switch_port_list_find_fd(switch_port_list_t ports,int fd)1285*4f1223e8SApple OSS Distributions switch_port_list_find_fd(switch_port_list_t ports, int fd)
1286*4f1223e8SApple OSS Distributions {
1287*4f1223e8SApple OSS Distributions 	u_int           i;
1288*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1289*4f1223e8SApple OSS Distributions 
1290*4f1223e8SApple OSS Distributions 	for (i = 0, port = ports->list; i < ports->count; i++, port++) {
1291*4f1223e8SApple OSS Distributions 		if (port->fd == fd) {
1292*4f1223e8SApple OSS Distributions 			return port;
1293*4f1223e8SApple OSS Distributions 		}
1294*4f1223e8SApple OSS Distributions 	}
1295*4f1223e8SApple OSS Distributions 	return NULL;
1296*4f1223e8SApple OSS Distributions }
1297*4f1223e8SApple OSS Distributions 
1298*4f1223e8SApple OSS Distributions static void
switch_port_list_log(switch_port_list_t port_list)1299*4f1223e8SApple OSS Distributions switch_port_list_log(switch_port_list_t port_list)
1300*4f1223e8SApple OSS Distributions {
1301*4f1223e8SApple OSS Distributions 	u_int           i;
1302*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1303*4f1223e8SApple OSS Distributions 
1304*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1305*4f1223e8SApple OSS Distributions 		switch_port_log(port);
1306*4f1223e8SApple OSS Distributions 	}
1307*4f1223e8SApple OSS Distributions 	return;
1308*4f1223e8SApple OSS Distributions }
1309*4f1223e8SApple OSS Distributions 
1310*4f1223e8SApple OSS Distributions static switch_port_t
switch_port_list_find_member(switch_port_list_t ports,const char * member_ifname)1311*4f1223e8SApple OSS Distributions switch_port_list_find_member(switch_port_list_t ports, const char * member_ifname)
1312*4f1223e8SApple OSS Distributions {
1313*4f1223e8SApple OSS Distributions 	u_int           i;
1314*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1315*4f1223e8SApple OSS Distributions 
1316*4f1223e8SApple OSS Distributions 	for (i = 0, port = ports->list; i < ports->count; i++, port++) {
1317*4f1223e8SApple OSS Distributions 		if (strcmp(port->member_ifname, member_ifname) == 0) {
1318*4f1223e8SApple OSS Distributions 			return port;
1319*4f1223e8SApple OSS Distributions 		}
1320*4f1223e8SApple OSS Distributions 	}
1321*4f1223e8SApple OSS Distributions 	return NULL;
1322*4f1223e8SApple OSS Distributions }
1323*4f1223e8SApple OSS Distributions 
1324*4f1223e8SApple OSS Distributions static void
switch_port_list_check_receive(switch_port_list_t ports,uint8_t af,const void * payload,u_int payload_length,packet_validator_t validator,void * context)1325*4f1223e8SApple OSS Distributions switch_port_list_check_receive(switch_port_list_t ports, uint8_t af,
1326*4f1223e8SApple OSS Distributions     const void * payload, u_int payload_length,
1327*4f1223e8SApple OSS Distributions     packet_validator_t validator,
1328*4f1223e8SApple OSS Distributions     void * context)
1329*4f1223e8SApple OSS Distributions {
1330*4f1223e8SApple OSS Distributions 	int             i;
1331*4f1223e8SApple OSS Distributions 	int             n_events;
1332*4f1223e8SApple OSS Distributions 	struct kevent   kev[ports->count];
1333*4f1223e8SApple OSS Distributions 	int             kq;
1334*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1335*4f1223e8SApple OSS Distributions 	struct timespec ts = { .tv_sec = 0, .tv_nsec = 10 * 1000 * 1000};
1336*4f1223e8SApple OSS Distributions 	u_int           u;
1337*4f1223e8SApple OSS Distributions 
1338*4f1223e8SApple OSS Distributions 	kq = kqueue();
1339*4f1223e8SApple OSS Distributions 	T_QUIET;
1340*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(kq, "kqueue check_receive");
1341*4f1223e8SApple OSS Distributions 	for (u = 0, port = ports->list; u < ports->count; u++, port++) {
1342*4f1223e8SApple OSS Distributions 		port->test_count = 0;
1343*4f1223e8SApple OSS Distributions 		EV_SET(kev + u, port->fd,
1344*4f1223e8SApple OSS Distributions 		    EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
1345*4f1223e8SApple OSS Distributions 	}
1346*4f1223e8SApple OSS Distributions 
1347*4f1223e8SApple OSS Distributions 	do {
1348*4f1223e8SApple OSS Distributions 		n_events = kevent(kq, kev, (int)ports->count, kev,
1349*4f1223e8SApple OSS Distributions 		    (int)ports->count, &ts);
1350*4f1223e8SApple OSS Distributions 		T_QUIET;
1351*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(n_events, "kevent receive %d", n_events);
1352*4f1223e8SApple OSS Distributions 		for (i = 0; i < n_events; i++) {
1353*4f1223e8SApple OSS Distributions 			T_QUIET;
1354*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ((int)kev[i].filter, EVFILT_READ, NULL);
1355*4f1223e8SApple OSS Distributions 			T_QUIET;
1356*4f1223e8SApple OSS Distributions 			T_ASSERT_NULL(kev[i].udata, NULL);
1357*4f1223e8SApple OSS Distributions 			port = switch_port_list_find_fd(ports,
1358*4f1223e8SApple OSS Distributions 			    (int)kev[i].ident);
1359*4f1223e8SApple OSS Distributions 			T_QUIET;
1360*4f1223e8SApple OSS Distributions 			T_ASSERT_NE(port, NULL,
1361*4f1223e8SApple OSS Distributions 			    "port %p fd %d", (void *)port,
1362*4f1223e8SApple OSS Distributions 			    (int)kev[i].ident);
1363*4f1223e8SApple OSS Distributions 			switch_port_receive(port, af, payload, payload_length,
1364*4f1223e8SApple OSS Distributions 			    validator, context);
1365*4f1223e8SApple OSS Distributions 		}
1366*4f1223e8SApple OSS Distributions 	} while (n_events != 0);
1367*4f1223e8SApple OSS Distributions 	close(kq);
1368*4f1223e8SApple OSS Distributions }
1369*4f1223e8SApple OSS Distributions 
1370*4f1223e8SApple OSS Distributions static bool
switch_port_list_verify_rt_table(switch_port_list_t port_list,bool log)1371*4f1223e8SApple OSS Distributions switch_port_list_verify_rt_table(switch_port_list_t port_list, bool log)
1372*4f1223e8SApple OSS Distributions {
1373*4f1223e8SApple OSS Distributions 	bool            all_present = true;
1374*4f1223e8SApple OSS Distributions 	u_int           i;
1375*4f1223e8SApple OSS Distributions 	u_int           count;
1376*4f1223e8SApple OSS Distributions 	struct ifbareq *ifba;
1377*4f1223e8SApple OSS Distributions 	struct ifbareq *rt_table;
1378*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1379*4f1223e8SApple OSS Distributions 
1380*4f1223e8SApple OSS Distributions 	/* clear out current notion of how many addresses are present */
1381*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1382*4f1223e8SApple OSS Distributions 		port->test_address_count = 0;
1383*4f1223e8SApple OSS Distributions 		port->test_address_present = 0;
1384*4f1223e8SApple OSS Distributions 	}
1385*4f1223e8SApple OSS Distributions 	rt_table = bridge_rt_table_copy(&count);
1386*4f1223e8SApple OSS Distributions 	if (rt_table == NULL) {
1387*4f1223e8SApple OSS Distributions 		return false;
1388*4f1223e8SApple OSS Distributions 	}
1389*4f1223e8SApple OSS Distributions 	if (log) {
1390*4f1223e8SApple OSS Distributions 		bridge_rt_table_log(rt_table, count);
1391*4f1223e8SApple OSS Distributions 	}
1392*4f1223e8SApple OSS Distributions 	for (i = 0, ifba = rt_table; i < count; i++, ifba++) {
1393*4f1223e8SApple OSS Distributions 		uint64_t        addr_bit;
1394*4f1223e8SApple OSS Distributions 		u_int           addr_index;
1395*4f1223e8SApple OSS Distributions 		u_int           unit_index;
1396*4f1223e8SApple OSS Distributions 		u_char *        ea;
1397*4f1223e8SApple OSS Distributions 		ether_addr_t *  eaddr;
1398*4f1223e8SApple OSS Distributions 
1399*4f1223e8SApple OSS Distributions 		eaddr = (ether_addr_t *)&ifba->ifba_dst;
1400*4f1223e8SApple OSS Distributions 		ea = eaddr->octet;
1401*4f1223e8SApple OSS Distributions 		addr_index = ea[EA_ADDR_INDEX];
1402*4f1223e8SApple OSS Distributions 		unit_index = ea[EA_UNIT_INDEX];
1403*4f1223e8SApple OSS Distributions 		port = switch_port_list_find_member(port_list,
1404*4f1223e8SApple OSS Distributions 		    ifba->ifba_ifsname);
1405*4f1223e8SApple OSS Distributions 		T_QUIET;
1406*4f1223e8SApple OSS Distributions 		T_ASSERT_NOTNULL(port, "switch_port_list_find_member %s",
1407*4f1223e8SApple OSS Distributions 		    ifba->ifba_ifsname);
1408*4f1223e8SApple OSS Distributions 		if (!S_cleaning_up) {
1409*4f1223e8SApple OSS Distributions 			T_QUIET;
1410*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(unit_index, port->unit, NULL);
1411*4f1223e8SApple OSS Distributions 			addr_bit = 1 << addr_index;
1412*4f1223e8SApple OSS Distributions 			T_QUIET;
1413*4f1223e8SApple OSS Distributions 			T_ASSERT_BITS_NOTSET(port->test_address_present,
1414*4f1223e8SApple OSS Distributions 			    addr_bit, "%s address %u",
1415*4f1223e8SApple OSS Distributions 			    ifba->ifba_ifsname, addr_index);
1416*4f1223e8SApple OSS Distributions 			port->test_address_present |= addr_bit;
1417*4f1223e8SApple OSS Distributions 			port->test_address_count++;
1418*4f1223e8SApple OSS Distributions 		}
1419*4f1223e8SApple OSS Distributions 	}
1420*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1421*4f1223e8SApple OSS Distributions 		if (G_debug) {
1422*4f1223e8SApple OSS Distributions 			T_LOG("%s unit %d [member %s] %u expect %u",
1423*4f1223e8SApple OSS Distributions 			    port->ifname, port->unit, port->member_ifname,
1424*4f1223e8SApple OSS Distributions 			    port->test_address_count, port->num_addrs);
1425*4f1223e8SApple OSS Distributions 		}
1426*4f1223e8SApple OSS Distributions 		if (port->test_address_count != port->num_addrs) {
1427*4f1223e8SApple OSS Distributions 			all_present = false;
1428*4f1223e8SApple OSS Distributions 		}
1429*4f1223e8SApple OSS Distributions 	}
1430*4f1223e8SApple OSS Distributions 
1431*4f1223e8SApple OSS Distributions 	free(rt_table);
1432*4f1223e8SApple OSS Distributions 	return all_present;
1433*4f1223e8SApple OSS Distributions }
1434*4f1223e8SApple OSS Distributions 
1435*4f1223e8SApple OSS Distributions static bool
switch_port_list_verify_mac_nat(switch_port_list_t port_list,bool log)1436*4f1223e8SApple OSS Distributions switch_port_list_verify_mac_nat(switch_port_list_t port_list, bool log)
1437*4f1223e8SApple OSS Distributions {
1438*4f1223e8SApple OSS Distributions 	bool                    all_present = true;
1439*4f1223e8SApple OSS Distributions 	u_int                   i;
1440*4f1223e8SApple OSS Distributions 	u_int                   count;
1441*4f1223e8SApple OSS Distributions 	static struct ifbrmne * entries;
1442*4f1223e8SApple OSS Distributions 	switch_port_t           port;
1443*4f1223e8SApple OSS Distributions 	struct ifbrmne *        scan;
1444*4f1223e8SApple OSS Distributions 
1445*4f1223e8SApple OSS Distributions 
1446*4f1223e8SApple OSS Distributions 	/* clear out current notion of how many addresses are present */
1447*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1448*4f1223e8SApple OSS Distributions 		port->test_address_count = 0;
1449*4f1223e8SApple OSS Distributions 		port->test_address_present = 0;
1450*4f1223e8SApple OSS Distributions 	}
1451*4f1223e8SApple OSS Distributions 	entries = bridge_mac_nat_entries_copy(&count);
1452*4f1223e8SApple OSS Distributions 	if (entries == NULL) {
1453*4f1223e8SApple OSS Distributions 		return false;
1454*4f1223e8SApple OSS Distributions 	}
1455*4f1223e8SApple OSS Distributions 	if (log) {
1456*4f1223e8SApple OSS Distributions 		bridge_mac_nat_entries_log(entries, count);
1457*4f1223e8SApple OSS Distributions 	}
1458*4f1223e8SApple OSS Distributions 	for (i = 0, scan = entries; i < count; i++, scan++) {
1459*4f1223e8SApple OSS Distributions 		uint8_t         af;
1460*4f1223e8SApple OSS Distributions 		uint64_t        addr_bit;
1461*4f1223e8SApple OSS Distributions 		u_int           addr_index;
1462*4f1223e8SApple OSS Distributions 		char            buf_ip1[INET6_ADDRSTRLEN];
1463*4f1223e8SApple OSS Distributions 		char            buf_ip2[INET6_ADDRSTRLEN];
1464*4f1223e8SApple OSS Distributions 		u_char *        ea;
1465*4f1223e8SApple OSS Distributions 		ether_addr_t *  eaddr;
1466*4f1223e8SApple OSS Distributions 		union ifbrip    ip;
1467*4f1223e8SApple OSS Distributions 		u_int           unit_index;
1468*4f1223e8SApple OSS Distributions 
1469*4f1223e8SApple OSS Distributions 		eaddr = (ether_addr_t *)&scan->ifbmne_mac;
1470*4f1223e8SApple OSS Distributions 		ea = eaddr->octet;
1471*4f1223e8SApple OSS Distributions 		addr_index = ea[EA_ADDR_INDEX];
1472*4f1223e8SApple OSS Distributions 		unit_index = ea[EA_UNIT_INDEX];
1473*4f1223e8SApple OSS Distributions 		port = switch_port_list_find_member(port_list,
1474*4f1223e8SApple OSS Distributions 		    scan->ifbmne_ifname);
1475*4f1223e8SApple OSS Distributions 		T_QUIET;
1476*4f1223e8SApple OSS Distributions 		T_ASSERT_NOTNULL(port,
1477*4f1223e8SApple OSS Distributions 		    "switch_port_list_find_member %s",
1478*4f1223e8SApple OSS Distributions 		    scan->ifbmne_ifname);
1479*4f1223e8SApple OSS Distributions 		T_QUIET;
1480*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(unit_index, port->unit, NULL);
1481*4f1223e8SApple OSS Distributions 		af = scan->ifbmne_af;
1482*4f1223e8SApple OSS Distributions 		get_ip_address(af, port->unit, addr_index, &ip);
1483*4f1223e8SApple OSS Distributions 		addr_bit = 1 << addr_index;
1484*4f1223e8SApple OSS Distributions 		T_QUIET;
1485*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(ip_addresses_are_equal(af, &ip, &scan->ifbmne_ip),
1486*4f1223e8SApple OSS Distributions 		    "mac nat entry IP address %s expected %s",
1487*4f1223e8SApple OSS Distributions 		    inet_ntop(af, &scan->ifbmne_ip_addr,
1488*4f1223e8SApple OSS Distributions 		    buf_ip1, sizeof(buf_ip1)),
1489*4f1223e8SApple OSS Distributions 		    inet_ntop(af, &ip,
1490*4f1223e8SApple OSS Distributions 		    buf_ip2, sizeof(buf_ip2)));
1491*4f1223e8SApple OSS Distributions 		T_QUIET;
1492*4f1223e8SApple OSS Distributions 		T_ASSERT_BITS_NOTSET(port->test_address_present,
1493*4f1223e8SApple OSS Distributions 		    addr_bit, "%s address %u",
1494*4f1223e8SApple OSS Distributions 		    scan->ifbmne_ifname, addr_index);
1495*4f1223e8SApple OSS Distributions 		port->test_address_present |= addr_bit;
1496*4f1223e8SApple OSS Distributions 		port->test_address_count++;
1497*4f1223e8SApple OSS Distributions 	}
1498*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1499*4f1223e8SApple OSS Distributions 		if (port->mac_nat) {
1500*4f1223e8SApple OSS Distributions 			/* MAC-NAT interface should have no entries */
1501*4f1223e8SApple OSS Distributions 			T_QUIET;
1502*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(port->test_address_count, 0,
1503*4f1223e8SApple OSS Distributions 			    "mac nat interface %s has %u entries",
1504*4f1223e8SApple OSS Distributions 			    port->member_ifname,
1505*4f1223e8SApple OSS Distributions 			    port->test_address_count);
1506*4f1223e8SApple OSS Distributions 		} else {
1507*4f1223e8SApple OSS Distributions 			if (G_debug) {
1508*4f1223e8SApple OSS Distributions 				T_LOG("%s unit %d [member %s] %u expect %u",
1509*4f1223e8SApple OSS Distributions 				    port->ifname, port->unit,
1510*4f1223e8SApple OSS Distributions 				    port->member_ifname,
1511*4f1223e8SApple OSS Distributions 				    port->test_address_count, port->num_addrs);
1512*4f1223e8SApple OSS Distributions 			}
1513*4f1223e8SApple OSS Distributions 			if (port->test_address_count != port->num_addrs) {
1514*4f1223e8SApple OSS Distributions 				all_present = false;
1515*4f1223e8SApple OSS Distributions 			}
1516*4f1223e8SApple OSS Distributions 		}
1517*4f1223e8SApple OSS Distributions 	}
1518*4f1223e8SApple OSS Distributions 
1519*4f1223e8SApple OSS Distributions 	free(entries);
1520*4f1223e8SApple OSS Distributions 
1521*4f1223e8SApple OSS Distributions 	return all_present;
1522*4f1223e8SApple OSS Distributions }
1523*4f1223e8SApple OSS Distributions 
1524*4f1223e8SApple OSS Distributions /**
1525*4f1223e8SApple OSS Distributions ** Basic Bridge Tests
1526*4f1223e8SApple OSS Distributions **/
1527*4f1223e8SApple OSS Distributions static void
send_generation(switch_port_t port,uint8_t af,u_int addr_index,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,uint32_t generation)1528*4f1223e8SApple OSS Distributions send_generation(switch_port_t port, uint8_t af, u_int addr_index,
1529*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr, union ifbrip * dst_ip,
1530*4f1223e8SApple OSS Distributions     uint32_t generation)
1531*4f1223e8SApple OSS Distributions {
1532*4f1223e8SApple OSS Distributions 	uint32_t        payload;
1533*4f1223e8SApple OSS Distributions 
1534*4f1223e8SApple OSS Distributions 	payload = htonl(generation);
1535*4f1223e8SApple OSS Distributions 	switch_port_send_udp_addr_index(port, af, addr_index, dst_eaddr, dst_ip,
1536*4f1223e8SApple OSS Distributions 	    &payload, sizeof(payload));
1537*4f1223e8SApple OSS Distributions }
1538*4f1223e8SApple OSS Distributions 
1539*4f1223e8SApple OSS Distributions static void
check_receive_generation(switch_port_list_t ports,uint8_t af,uint32_t generation,packet_validator_t validator,__unused void * context)1540*4f1223e8SApple OSS Distributions check_receive_generation(switch_port_list_t ports, uint8_t af,
1541*4f1223e8SApple OSS Distributions     uint32_t generation, packet_validator_t validator,
1542*4f1223e8SApple OSS Distributions     __unused void * context)
1543*4f1223e8SApple OSS Distributions {
1544*4f1223e8SApple OSS Distributions 	uint32_t        payload;
1545*4f1223e8SApple OSS Distributions 
1546*4f1223e8SApple OSS Distributions 	payload = htonl(generation);
1547*4f1223e8SApple OSS Distributions 	switch_port_list_check_receive(ports, af, &payload, sizeof(payload),
1548*4f1223e8SApple OSS Distributions 	    validator, context);
1549*4f1223e8SApple OSS Distributions }
1550*4f1223e8SApple OSS Distributions 
1551*4f1223e8SApple OSS Distributions static void
validate_source_ether_mismatch(switch_port_t port,const ether_header_t * eh_p)1552*4f1223e8SApple OSS Distributions validate_source_ether_mismatch(switch_port_t port, const ether_header_t * eh_p)
1553*4f1223e8SApple OSS Distributions {
1554*4f1223e8SApple OSS Distributions 	/* source shouldn't be our own MAC addresses */
1555*4f1223e8SApple OSS Distributions 	T_QUIET;
1556*4f1223e8SApple OSS Distributions 	T_ASSERT_NE(eh_p->ether_shost[EA_UNIT_INDEX], port->unit,
1557*4f1223e8SApple OSS Distributions 	    "ether source matches unit %d", port->unit);
1558*4f1223e8SApple OSS Distributions }
1559*4f1223e8SApple OSS Distributions 
1560*4f1223e8SApple OSS Distributions static void
validate_not_present_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)1561*4f1223e8SApple OSS Distributions validate_not_present_dhost(switch_port_t port, const ether_header_t * eh_p,
1562*4f1223e8SApple OSS Distributions     __unused u_int pkt_len,
1563*4f1223e8SApple OSS Distributions     __unused void * context)
1564*4f1223e8SApple OSS Distributions {
1565*4f1223e8SApple OSS Distributions 	validate_source_ether_mismatch(port, eh_p);
1566*4f1223e8SApple OSS Distributions 	T_QUIET;
1567*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(bcmp(eh_p->ether_dhost, &ether_external,
1568*4f1223e8SApple OSS Distributions 	    sizeof(eh_p->ether_dhost)), 0,
1569*4f1223e8SApple OSS Distributions 	    "%s", __func__);
1570*4f1223e8SApple OSS Distributions 	port->test_count++;
1571*4f1223e8SApple OSS Distributions }
1572*4f1223e8SApple OSS Distributions 
1573*4f1223e8SApple OSS Distributions static void
validate_broadcast_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)1574*4f1223e8SApple OSS Distributions validate_broadcast_dhost(switch_port_t port, const ether_header_t * eh_p,
1575*4f1223e8SApple OSS Distributions     __unused u_int pkt_len,
1576*4f1223e8SApple OSS Distributions     __unused void * context)
1577*4f1223e8SApple OSS Distributions {
1578*4f1223e8SApple OSS Distributions 	validate_source_ether_mismatch(port, eh_p);
1579*4f1223e8SApple OSS Distributions 	T_QUIET;
1580*4f1223e8SApple OSS Distributions 	T_ASSERT_NE((eh_p->ether_dhost[0] & 0x01), 0,
1581*4f1223e8SApple OSS Distributions 	    "%s", __func__);
1582*4f1223e8SApple OSS Distributions 	port->test_count++;
1583*4f1223e8SApple OSS Distributions }
1584*4f1223e8SApple OSS Distributions 
1585*4f1223e8SApple OSS Distributions static void
validate_port_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)1586*4f1223e8SApple OSS Distributions validate_port_dhost(switch_port_t port, const ether_header_t * eh_p,
1587*4f1223e8SApple OSS Distributions     __unused u_int pkt_len,
1588*4f1223e8SApple OSS Distributions     __unused void * context)
1589*4f1223e8SApple OSS Distributions {
1590*4f1223e8SApple OSS Distributions 	validate_source_ether_mismatch(port, eh_p);
1591*4f1223e8SApple OSS Distributions 	T_QUIET;
1592*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
1593*4f1223e8SApple OSS Distributions 	    "wrong dhost unit %d != %d",
1594*4f1223e8SApple OSS Distributions 	    eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
1595*4f1223e8SApple OSS Distributions 	port->test_count++;
1596*4f1223e8SApple OSS Distributions }
1597*4f1223e8SApple OSS Distributions 
1598*4f1223e8SApple OSS Distributions 
1599*4f1223e8SApple OSS Distributions static void
check_received_count(switch_port_list_t port_list,switch_port_t port,uint32_t expected_packets)1600*4f1223e8SApple OSS Distributions check_received_count(switch_port_list_t port_list,
1601*4f1223e8SApple OSS Distributions     switch_port_t port, uint32_t expected_packets)
1602*4f1223e8SApple OSS Distributions {
1603*4f1223e8SApple OSS Distributions 	u_int           i;
1604*4f1223e8SApple OSS Distributions 	switch_port_t   scan;
1605*4f1223e8SApple OSS Distributions 
1606*4f1223e8SApple OSS Distributions 	for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
1607*4f1223e8SApple OSS Distributions 		if (scan == port) {
1608*4f1223e8SApple OSS Distributions 			T_QUIET;
1609*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(port->test_count, 0,
1610*4f1223e8SApple OSS Distributions 			    "unexpected receive on port %d",
1611*4f1223e8SApple OSS Distributions 			    port->unit);
1612*4f1223e8SApple OSS Distributions 		} else if (expected_packets == ALL_ADDRS) {
1613*4f1223e8SApple OSS Distributions 			T_QUIET;
1614*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(scan->test_count, scan->num_addrs,
1615*4f1223e8SApple OSS Distributions 			    "didn't receive on all addrs");
1616*4f1223e8SApple OSS Distributions 		} else {
1617*4f1223e8SApple OSS Distributions 			T_QUIET;
1618*4f1223e8SApple OSS Distributions 			T_ASSERT_EQ(scan->test_count, expected_packets,
1619*4f1223e8SApple OSS Distributions 			    "wrong receive count on port %s", scan->member_ifname);
1620*4f1223e8SApple OSS Distributions 		}
1621*4f1223e8SApple OSS Distributions 	}
1622*4f1223e8SApple OSS Distributions }
1623*4f1223e8SApple OSS Distributions 
1624*4f1223e8SApple OSS Distributions static void
unicast_send_all(switch_port_list_t port_list,uint8_t af,switch_port_t port)1625*4f1223e8SApple OSS Distributions unicast_send_all(switch_port_list_t port_list, uint8_t af, switch_port_t port)
1626*4f1223e8SApple OSS Distributions {
1627*4f1223e8SApple OSS Distributions 	u_int           i;
1628*4f1223e8SApple OSS Distributions 	switch_port_t   scan;
1629*4f1223e8SApple OSS Distributions 
1630*4f1223e8SApple OSS Distributions 	for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
1631*4f1223e8SApple OSS Distributions 		if (G_debug) {
1632*4f1223e8SApple OSS Distributions 			T_LOG("Unicast send on %s", port->ifname);
1633*4f1223e8SApple OSS Distributions 		}
1634*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < scan->num_addrs; j++) {
1635*4f1223e8SApple OSS Distributions 			ether_addr_t    eaddr;
1636*4f1223e8SApple OSS Distributions 			union ifbrip    ip;
1637*4f1223e8SApple OSS Distributions 
1638*4f1223e8SApple OSS Distributions 			set_ethernet_address(&eaddr, scan->unit, j);
1639*4f1223e8SApple OSS Distributions 			get_ip_address(af, scan->unit, j, &ip);
1640*4f1223e8SApple OSS Distributions 			switch_port_send_udp_addr_index(port, af, 0, &eaddr, &ip,
1641*4f1223e8SApple OSS Distributions 			    NULL, 0);
1642*4f1223e8SApple OSS Distributions 		}
1643*4f1223e8SApple OSS Distributions 	}
1644*4f1223e8SApple OSS Distributions }
1645*4f1223e8SApple OSS Distributions 
1646*4f1223e8SApple OSS Distributions 
1647*4f1223e8SApple OSS Distributions static void
bridge_learning_test_once(switch_port_list_t port_list,uint8_t af,packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr,bool retry)1648*4f1223e8SApple OSS Distributions bridge_learning_test_once(switch_port_list_t port_list,
1649*4f1223e8SApple OSS Distributions     uint8_t af,
1650*4f1223e8SApple OSS Distributions     packet_validator_t validator,
1651*4f1223e8SApple OSS Distributions     void * context,
1652*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr,
1653*4f1223e8SApple OSS Distributions     bool retry)
1654*4f1223e8SApple OSS Distributions {
1655*4f1223e8SApple OSS Distributions 	u_int           i;
1656*4f1223e8SApple OSS Distributions 	union ifbrip    dst_ip;
1657*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1658*4f1223e8SApple OSS Distributions 
1659*4f1223e8SApple OSS Distributions 	get_broadcast_ip_address(af, &dst_ip);
1660*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1661*4f1223e8SApple OSS Distributions 		if (port->test_address_count == port->num_addrs) {
1662*4f1223e8SApple OSS Distributions 			/* already populated */
1663*4f1223e8SApple OSS Distributions 			continue;
1664*4f1223e8SApple OSS Distributions 		}
1665*4f1223e8SApple OSS Distributions 		if (G_debug) {
1666*4f1223e8SApple OSS Distributions 			T_LOG("Sending on %s", port->ifname);
1667*4f1223e8SApple OSS Distributions 		}
1668*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
1669*4f1223e8SApple OSS Distributions 			uint32_t        generation;
1670*4f1223e8SApple OSS Distributions 
1671*4f1223e8SApple OSS Distributions 			if (retry) {
1672*4f1223e8SApple OSS Distributions 				uint64_t        addr_bit;
1673*4f1223e8SApple OSS Distributions 
1674*4f1223e8SApple OSS Distributions 				addr_bit = 1 << j;
1675*4f1223e8SApple OSS Distributions 				if ((port->test_address_present & addr_bit)
1676*4f1223e8SApple OSS Distributions 				    != 0) {
1677*4f1223e8SApple OSS Distributions 					/* already present */
1678*4f1223e8SApple OSS Distributions 					continue;
1679*4f1223e8SApple OSS Distributions 				}
1680*4f1223e8SApple OSS Distributions 				T_LOG("Retry port %s unit %u address %u",
1681*4f1223e8SApple OSS Distributions 				    port->ifname, port->unit, j);
1682*4f1223e8SApple OSS Distributions 			}
1683*4f1223e8SApple OSS Distributions 			generation = next_generation();
1684*4f1223e8SApple OSS Distributions 			send_generation(port,
1685*4f1223e8SApple OSS Distributions 			    af,
1686*4f1223e8SApple OSS Distributions 			    j,
1687*4f1223e8SApple OSS Distributions 			    dst_eaddr,
1688*4f1223e8SApple OSS Distributions 			    &dst_ip,
1689*4f1223e8SApple OSS Distributions 			    generation);
1690*4f1223e8SApple OSS Distributions 
1691*4f1223e8SApple OSS Distributions 			/* receive across all ports */
1692*4f1223e8SApple OSS Distributions 			check_receive_generation(port_list,
1693*4f1223e8SApple OSS Distributions 			    af,
1694*4f1223e8SApple OSS Distributions 			    generation,
1695*4f1223e8SApple OSS Distributions 			    validator,
1696*4f1223e8SApple OSS Distributions 			    context);
1697*4f1223e8SApple OSS Distributions 
1698*4f1223e8SApple OSS Distributions 			/* ensure that every port saw the packet */
1699*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
1700*4f1223e8SApple OSS Distributions 		}
1701*4f1223e8SApple OSS Distributions 	}
1702*4f1223e8SApple OSS Distributions 	return;
1703*4f1223e8SApple OSS Distributions }
1704*4f1223e8SApple OSS Distributions 
1705*4f1223e8SApple OSS Distributions static void
bridge_learning_test(switch_port_list_t port_list,uint8_t af,packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr)1706*4f1223e8SApple OSS Distributions bridge_learning_test(switch_port_list_t port_list,
1707*4f1223e8SApple OSS Distributions     uint8_t af,
1708*4f1223e8SApple OSS Distributions     packet_validator_t validator,
1709*4f1223e8SApple OSS Distributions     void * context,
1710*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr)
1711*4f1223e8SApple OSS Distributions {
1712*4f1223e8SApple OSS Distributions 	char            ntoabuf[ETHER_NTOA_BUFSIZE];
1713*4f1223e8SApple OSS Distributions 	u_int           i;
1714*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1715*4f1223e8SApple OSS Distributions 	bool            verified = false;
1716*4f1223e8SApple OSS Distributions 
1717*4f1223e8SApple OSS Distributions 	ether_ntoa_buf(dst_eaddr, ntoabuf, sizeof(ntoabuf));
1718*4f1223e8SApple OSS Distributions 
1719*4f1223e8SApple OSS Distributions 	/*
1720*4f1223e8SApple OSS Distributions 	 * Send a broadcast frame from every port in the list so that the bridge
1721*4f1223e8SApple OSS Distributions 	 * learns our MAC address.
1722*4f1223e8SApple OSS Distributions 	 */
1723*4f1223e8SApple OSS Distributions #define BROADCAST_MAX_TRIES             20
1724*4f1223e8SApple OSS Distributions 	for (int try = 1; try < BROADCAST_MAX_TRIES; try++) {
1725*4f1223e8SApple OSS Distributions 		bool    retry = (try > 1);
1726*4f1223e8SApple OSS Distributions 
1727*4f1223e8SApple OSS Distributions 		if (!retry) {
1728*4f1223e8SApple OSS Distributions 			T_LOG("%s: %s #ports %u #addrs %u dest %s",
1729*4f1223e8SApple OSS Distributions 			    __func__,
1730*4f1223e8SApple OSS Distributions 			    af_get_str(af),
1731*4f1223e8SApple OSS Distributions 			    port_list->count, port_list->list->num_addrs,
1732*4f1223e8SApple OSS Distributions 			    ntoabuf);
1733*4f1223e8SApple OSS Distributions 		} else {
1734*4f1223e8SApple OSS Distributions 			T_LOG("%s: %s #ports %u #addrs %u dest %s (TRY=%d)",
1735*4f1223e8SApple OSS Distributions 			    __func__,
1736*4f1223e8SApple OSS Distributions 			    af_get_str(af),
1737*4f1223e8SApple OSS Distributions 			    port_list->count, port_list->list->num_addrs,
1738*4f1223e8SApple OSS Distributions 			    ntoabuf, try);
1739*4f1223e8SApple OSS Distributions 		}
1740*4f1223e8SApple OSS Distributions 		bridge_learning_test_once(port_list, af, validator, context,
1741*4f1223e8SApple OSS Distributions 		    dst_eaddr, retry);
1742*4f1223e8SApple OSS Distributions 		/*
1743*4f1223e8SApple OSS Distributions 		 * In the event of a memory allocation failure, it's possible
1744*4f1223e8SApple OSS Distributions 		 * that the address was not learned. Figure out whether
1745*4f1223e8SApple OSS Distributions 		 * all addresses are present, and if not, we'll retry on
1746*4f1223e8SApple OSS Distributions 		 * those that are not present.
1747*4f1223e8SApple OSS Distributions 		 */
1748*4f1223e8SApple OSS Distributions 		verified = switch_port_list_verify_rt_table(port_list, false);
1749*4f1223e8SApple OSS Distributions 		if (verified) {
1750*4f1223e8SApple OSS Distributions 			break;
1751*4f1223e8SApple OSS Distributions 		}
1752*4f1223e8SApple OSS Distributions 		/* wait a short time to allow the system to recover */
1753*4f1223e8SApple OSS Distributions 		usleep(100 * 1000);
1754*4f1223e8SApple OSS Distributions 	}
1755*4f1223e8SApple OSS Distributions 	T_QUIET;
1756*4f1223e8SApple OSS Distributions 	T_ASSERT_TRUE(verified, "All addresses present");
1757*4f1223e8SApple OSS Distributions 
1758*4f1223e8SApple OSS Distributions 	/*
1759*4f1223e8SApple OSS Distributions 	 * Since we just broadcast on every port in the switch, the bridge knows
1760*4f1223e8SApple OSS Distributions 	 * the port's MAC addresses. The bridge should not need to broadcast the
1761*4f1223e8SApple OSS Distributions 	 * packet to learn, which means the unicast traffic should only arrive
1762*4f1223e8SApple OSS Distributions 	 * on the intended port.
1763*4f1223e8SApple OSS Distributions 	 */
1764*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1765*4f1223e8SApple OSS Distributions 		/* send unicast packets to every other port's MAC addresses */
1766*4f1223e8SApple OSS Distributions 		unicast_send_all(port_list, af, port);
1767*4f1223e8SApple OSS Distributions 
1768*4f1223e8SApple OSS Distributions 		/* receive all of that generated traffic */
1769*4f1223e8SApple OSS Distributions 		switch_port_list_check_receive(port_list, af, NULL, 0,
1770*4f1223e8SApple OSS Distributions 		    validate_port_dhost, NULL);
1771*4f1223e8SApple OSS Distributions 		/* check that we saw all of the unicast packets */
1772*4f1223e8SApple OSS Distributions 		check_received_count(port_list, port, ALL_ADDRS);
1773*4f1223e8SApple OSS Distributions 	}
1774*4f1223e8SApple OSS Distributions 	T_PASS("%s", __func__);
1775*4f1223e8SApple OSS Distributions }
1776*4f1223e8SApple OSS Distributions 
1777*4f1223e8SApple OSS Distributions /**
1778*4f1223e8SApple OSS Distributions ** MAC-NAT tests
1779*4f1223e8SApple OSS Distributions **/
1780*4f1223e8SApple OSS Distributions static void
mac_nat_check_received_count(switch_port_list_t port_list,switch_port_t port)1781*4f1223e8SApple OSS Distributions mac_nat_check_received_count(switch_port_list_t port_list, switch_port_t port)
1782*4f1223e8SApple OSS Distributions {
1783*4f1223e8SApple OSS Distributions 	u_int           i;
1784*4f1223e8SApple OSS Distributions 	switch_port_t   scan;
1785*4f1223e8SApple OSS Distributions 
1786*4f1223e8SApple OSS Distributions 	for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
1787*4f1223e8SApple OSS Distributions 		u_int   expected = 0;
1788*4f1223e8SApple OSS Distributions 
1789*4f1223e8SApple OSS Distributions 		if (scan == port) {
1790*4f1223e8SApple OSS Distributions 			expected = scan->num_addrs;
1791*4f1223e8SApple OSS Distributions 		}
1792*4f1223e8SApple OSS Distributions 		T_QUIET;
1793*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(scan->test_count, expected,
1794*4f1223e8SApple OSS Distributions 		    "%s [member %s]%s expected %u actual %u",
1795*4f1223e8SApple OSS Distributions 		    scan->ifname, scan->member_ifname,
1796*4f1223e8SApple OSS Distributions 		    scan->mac_nat ? " [mac-nat]" : "",
1797*4f1223e8SApple OSS Distributions 		    expected, scan->test_count);
1798*4f1223e8SApple OSS Distributions 	}
1799*4f1223e8SApple OSS Distributions }
1800*4f1223e8SApple OSS Distributions 
1801*4f1223e8SApple OSS Distributions static void
validate_mac_nat(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)1802*4f1223e8SApple OSS Distributions validate_mac_nat(switch_port_t port, const ether_header_t * eh_p,
1803*4f1223e8SApple OSS Distributions     __unused u_int pkt_len,
1804*4f1223e8SApple OSS Distributions     __unused void * context)
1805*4f1223e8SApple OSS Distributions {
1806*4f1223e8SApple OSS Distributions 	if (port->mac_nat) {
1807*4f1223e8SApple OSS Distributions 		bool    equal;
1808*4f1223e8SApple OSS Distributions 
1809*4f1223e8SApple OSS Distributions 		/* source must match MAC-NAT interface */
1810*4f1223e8SApple OSS Distributions 		equal = (bcmp(eh_p->ether_shost, &port->member_mac,
1811*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
1812*4f1223e8SApple OSS Distributions 		if (!equal) {
1813*4f1223e8SApple OSS Distributions 			ethernet_frame_validate(eh_p, pkt_len, true);
1814*4f1223e8SApple OSS Distributions 		}
1815*4f1223e8SApple OSS Distributions 		T_QUIET;
1816*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "source address match");
1817*4f1223e8SApple OSS Distributions 		port->test_count++;
1818*4f1223e8SApple OSS Distributions 	} else {
1819*4f1223e8SApple OSS Distributions 		validate_not_present_dhost(port, eh_p, pkt_len, NULL);
1820*4f1223e8SApple OSS Distributions 	}
1821*4f1223e8SApple OSS Distributions }
1822*4f1223e8SApple OSS Distributions 
1823*4f1223e8SApple OSS Distributions static void
validate_mac_nat_in(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,__unused void * context)1824*4f1223e8SApple OSS Distributions validate_mac_nat_in(switch_port_t port, const ether_header_t * eh_p,
1825*4f1223e8SApple OSS Distributions     u_int pkt_len, __unused void * context)
1826*4f1223e8SApple OSS Distributions {
1827*4f1223e8SApple OSS Distributions 	if (G_debug) {
1828*4f1223e8SApple OSS Distributions 		T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
1829*4f1223e8SApple OSS Distributions 		ethernet_frame_validate(eh_p, pkt_len, true);
1830*4f1223e8SApple OSS Distributions 	}
1831*4f1223e8SApple OSS Distributions 	T_QUIET;
1832*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
1833*4f1223e8SApple OSS Distributions 	    "dhost unit %u expected %u",
1834*4f1223e8SApple OSS Distributions 	    eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
1835*4f1223e8SApple OSS Distributions 	port->test_count++;
1836*4f1223e8SApple OSS Distributions }
1837*4f1223e8SApple OSS Distributions 
1838*4f1223e8SApple OSS Distributions static void
validate_mac_nat_arp_out(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)1839*4f1223e8SApple OSS Distributions validate_mac_nat_arp_out(switch_port_t port, const ether_header_t * eh_p,
1840*4f1223e8SApple OSS Distributions     u_int pkt_len, void * context)
1841*4f1223e8SApple OSS Distributions {
1842*4f1223e8SApple OSS Distributions 	const struct ether_arp *        earp;
1843*4f1223e8SApple OSS Distributions 	switch_port_t                   send_port = (switch_port_t)context;
1844*4f1223e8SApple OSS Distributions 
1845*4f1223e8SApple OSS Distributions 	if (G_debug) {
1846*4f1223e8SApple OSS Distributions 		T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
1847*4f1223e8SApple OSS Distributions 		ethernet_frame_validate(eh_p, pkt_len, true);
1848*4f1223e8SApple OSS Distributions 	}
1849*4f1223e8SApple OSS Distributions 	T_QUIET;
1850*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_ARP, NULL);
1851*4f1223e8SApple OSS Distributions 	earp = (const struct ether_arp *)(const void *)(eh_p + 1);
1852*4f1223e8SApple OSS Distributions 	T_QUIET;
1853*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(pkt_len, (u_int)(sizeof(*eh_p) + sizeof(*earp)), NULL);
1854*4f1223e8SApple OSS Distributions 	if (port->mac_nat) {
1855*4f1223e8SApple OSS Distributions 		bool            equal;
1856*4f1223e8SApple OSS Distributions 
1857*4f1223e8SApple OSS Distributions 		/* source ethernet must match MAC-NAT interface */
1858*4f1223e8SApple OSS Distributions 		equal = (bcmp(eh_p->ether_shost, &port->member_mac,
1859*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
1860*4f1223e8SApple OSS Distributions 		if (!equal) {
1861*4f1223e8SApple OSS Distributions 			ethernet_frame_validate(eh_p, pkt_len, true);
1862*4f1223e8SApple OSS Distributions 		}
1863*4f1223e8SApple OSS Distributions 		T_QUIET;
1864*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "%s -> %s source address translated",
1865*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
1866*4f1223e8SApple OSS Distributions 		    port->member_ifname);
1867*4f1223e8SApple OSS Distributions 		/* sender hw must match MAC-NAT interface */
1868*4f1223e8SApple OSS Distributions 		equal = (bcmp(earp->arp_sha, &port->member_mac,
1869*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
1870*4f1223e8SApple OSS Distributions 		if (!equal) {
1871*4f1223e8SApple OSS Distributions 			ethernet_frame_validate(eh_p, pkt_len, true);
1872*4f1223e8SApple OSS Distributions 		}
1873*4f1223e8SApple OSS Distributions 		T_QUIET;
1874*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "%s -> %s sender hardware translated",
1875*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
1876*4f1223e8SApple OSS Distributions 		    port->member_ifname);
1877*4f1223e8SApple OSS Distributions 	} else {
1878*4f1223e8SApple OSS Distributions 		/* source ethernet must match the sender */
1879*4f1223e8SApple OSS Distributions 		T_QUIET;
1880*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
1881*4f1223e8SApple OSS Distributions 		    "%s -> %s unit %u expected %u",
1882*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
1883*4f1223e8SApple OSS Distributions 		    port->member_ifname,
1884*4f1223e8SApple OSS Distributions 		    eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
1885*4f1223e8SApple OSS Distributions 		/* source hw must match the sender */
1886*4f1223e8SApple OSS Distributions 		T_QUIET;
1887*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(earp->arp_sha[EA_UNIT_INDEX], send_port->unit,
1888*4f1223e8SApple OSS Distributions 		    "%s -> %s unit %u expected %u",
1889*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
1890*4f1223e8SApple OSS Distributions 		    port->member_ifname,
1891*4f1223e8SApple OSS Distributions 		    earp->arp_sha[EA_UNIT_INDEX], send_port->unit);
1892*4f1223e8SApple OSS Distributions 	}
1893*4f1223e8SApple OSS Distributions 	port->test_count++;
1894*4f1223e8SApple OSS Distributions }
1895*4f1223e8SApple OSS Distributions 
1896*4f1223e8SApple OSS Distributions static void
validate_mac_nat_arp_in(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)1897*4f1223e8SApple OSS Distributions validate_mac_nat_arp_in(switch_port_t port, const ether_header_t * eh_p,
1898*4f1223e8SApple OSS Distributions     u_int pkt_len, void * context)
1899*4f1223e8SApple OSS Distributions {
1900*4f1223e8SApple OSS Distributions 	const struct ether_arp *        earp;
1901*4f1223e8SApple OSS Distributions 	switch_port_t                   send_port = (switch_port_t)context;
1902*4f1223e8SApple OSS Distributions 
1903*4f1223e8SApple OSS Distributions 	if (G_debug) {
1904*4f1223e8SApple OSS Distributions 		T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
1905*4f1223e8SApple OSS Distributions 		ethernet_frame_validate(eh_p, pkt_len, true);
1906*4f1223e8SApple OSS Distributions 	}
1907*4f1223e8SApple OSS Distributions 	earp = (const struct ether_arp *)(const void *)(eh_p + 1);
1908*4f1223e8SApple OSS Distributions 	T_QUIET;
1909*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_ARP, NULL);
1910*4f1223e8SApple OSS Distributions 	T_QUIET;
1911*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(pkt_len, (u_int)(sizeof(*eh_p) + sizeof(*earp)), NULL);
1912*4f1223e8SApple OSS Distributions 	T_QUIET;
1913*4f1223e8SApple OSS Distributions 	T_ASSERT_FALSE(port->mac_nat, NULL);
1914*4f1223e8SApple OSS Distributions 
1915*4f1223e8SApple OSS Distributions 	/* destination ethernet must match the unit */
1916*4f1223e8SApple OSS Distributions 	T_QUIET;
1917*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
1918*4f1223e8SApple OSS Distributions 	    "%s -> %s unit %u expected %u",
1919*4f1223e8SApple OSS Distributions 	    send_port->member_ifname,
1920*4f1223e8SApple OSS Distributions 	    port->member_ifname,
1921*4f1223e8SApple OSS Distributions 	    eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
1922*4f1223e8SApple OSS Distributions 	/* source hw must match the sender */
1923*4f1223e8SApple OSS Distributions 	T_QUIET;
1924*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(earp->arp_tha[EA_UNIT_INDEX], port->unit,
1925*4f1223e8SApple OSS Distributions 	    "%s -> %s unit %u expected %u",
1926*4f1223e8SApple OSS Distributions 	    send_port->member_ifname,
1927*4f1223e8SApple OSS Distributions 	    port->member_ifname,
1928*4f1223e8SApple OSS Distributions 	    earp->arp_tha[EA_UNIT_INDEX], port->unit);
1929*4f1223e8SApple OSS Distributions 	port->test_count++;
1930*4f1223e8SApple OSS Distributions }
1931*4f1223e8SApple OSS Distributions 
1932*4f1223e8SApple OSS Distributions static void
mac_nat_test_arp_out(switch_port_list_t port_list)1933*4f1223e8SApple OSS Distributions mac_nat_test_arp_out(switch_port_list_t port_list)
1934*4f1223e8SApple OSS Distributions {
1935*4f1223e8SApple OSS Distributions 	u_int           i;
1936*4f1223e8SApple OSS Distributions 	struct in_addr  ip_dst;
1937*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1938*4f1223e8SApple OSS Distributions 
1939*4f1223e8SApple OSS Distributions 	ip_dst = get_external_ipv4_address();
1940*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1941*4f1223e8SApple OSS Distributions 		if (port->mac_nat) {
1942*4f1223e8SApple OSS Distributions 			continue;
1943*4f1223e8SApple OSS Distributions 		}
1944*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
1945*4f1223e8SApple OSS Distributions 			ether_addr_t    eaddr;
1946*4f1223e8SApple OSS Distributions 			struct in_addr  ip_src;
1947*4f1223e8SApple OSS Distributions 
1948*4f1223e8SApple OSS Distributions 			set_ethernet_address(&eaddr, port->unit, j);
1949*4f1223e8SApple OSS Distributions 			get_ipv4_address(port->unit, j, &ip_src);
1950*4f1223e8SApple OSS Distributions 			switch_port_send_arp(port,
1951*4f1223e8SApple OSS Distributions 			    ARPOP_REQUEST,
1952*4f1223e8SApple OSS Distributions 			    &eaddr,
1953*4f1223e8SApple OSS Distributions 			    ip_src,
1954*4f1223e8SApple OSS Distributions 			    NULL,
1955*4f1223e8SApple OSS Distributions 			    ip_dst);
1956*4f1223e8SApple OSS Distributions 			switch_port_list_check_receive(port_list, AF_INET,
1957*4f1223e8SApple OSS Distributions 			    NULL, 0,
1958*4f1223e8SApple OSS Distributions 			    validate_mac_nat_arp_out,
1959*4f1223e8SApple OSS Distributions 			    port);
1960*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
1961*4f1223e8SApple OSS Distributions 		}
1962*4f1223e8SApple OSS Distributions 	}
1963*4f1223e8SApple OSS Distributions 	T_PASS("%s", __func__);
1964*4f1223e8SApple OSS Distributions }
1965*4f1223e8SApple OSS Distributions 
1966*4f1223e8SApple OSS Distributions static void
mac_nat_send_arp_response(switch_port_t ext_port,switch_port_t port)1967*4f1223e8SApple OSS Distributions mac_nat_send_arp_response(switch_port_t ext_port, switch_port_t port)
1968*4f1223e8SApple OSS Distributions {
1969*4f1223e8SApple OSS Distributions 	struct in_addr  ip_src;
1970*4f1223e8SApple OSS Distributions 
1971*4f1223e8SApple OSS Distributions 	T_QUIET;
1972*4f1223e8SApple OSS Distributions 	T_ASSERT_TRUE(ext_port->mac_nat, "%s is MAC-NAT interface",
1973*4f1223e8SApple OSS Distributions 	    ext_port->member_ifname);
1974*4f1223e8SApple OSS Distributions 	ip_src = get_external_ipv4_address();
1975*4f1223e8SApple OSS Distributions 	for (u_int j = 0; j < port->num_addrs; j++) {
1976*4f1223e8SApple OSS Distributions 		struct in_addr  ip_dst;
1977*4f1223e8SApple OSS Distributions 
1978*4f1223e8SApple OSS Distributions 		get_ipv4_address(port->unit, j, &ip_dst);
1979*4f1223e8SApple OSS Distributions 		if (G_debug) {
1980*4f1223e8SApple OSS Distributions 			T_LOG("Generating ARP destined to %s %s",
1981*4f1223e8SApple OSS Distributions 			    port->ifname, inet_ntoa(ip_dst));
1982*4f1223e8SApple OSS Distributions 		}
1983*4f1223e8SApple OSS Distributions 		switch_port_send_arp(ext_port,
1984*4f1223e8SApple OSS Distributions 		    ARPOP_REPLY,
1985*4f1223e8SApple OSS Distributions 		    &ether_external,
1986*4f1223e8SApple OSS Distributions 		    ip_src,
1987*4f1223e8SApple OSS Distributions 		    &ext_port->member_mac,
1988*4f1223e8SApple OSS Distributions 		    ip_dst);
1989*4f1223e8SApple OSS Distributions 	}
1990*4f1223e8SApple OSS Distributions }
1991*4f1223e8SApple OSS Distributions 
1992*4f1223e8SApple OSS Distributions static void
mac_nat_test_arp_in(switch_port_list_t port_list)1993*4f1223e8SApple OSS Distributions mac_nat_test_arp_in(switch_port_list_t port_list)
1994*4f1223e8SApple OSS Distributions {
1995*4f1223e8SApple OSS Distributions 	u_int           i;
1996*4f1223e8SApple OSS Distributions 	struct in_addr  ip_src;
1997*4f1223e8SApple OSS Distributions 	switch_port_t   port;
1998*4f1223e8SApple OSS Distributions 
1999*4f1223e8SApple OSS Distributions 	ip_src = get_external_ipv4_address();
2000*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2001*4f1223e8SApple OSS Distributions 		if (port->mac_nat) {
2002*4f1223e8SApple OSS Distributions 			continue;
2003*4f1223e8SApple OSS Distributions 		}
2004*4f1223e8SApple OSS Distributions 		mac_nat_send_arp_response(port_list->list, port);
2005*4f1223e8SApple OSS Distributions 
2006*4f1223e8SApple OSS Distributions 		/* receive the generated traffic */
2007*4f1223e8SApple OSS Distributions 		switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2008*4f1223e8SApple OSS Distributions 		    validate_mac_nat_arp_in,
2009*4f1223e8SApple OSS Distributions 		    port_list->list);
2010*4f1223e8SApple OSS Distributions 
2011*4f1223e8SApple OSS Distributions 		/* verify that only the single port got the packet */
2012*4f1223e8SApple OSS Distributions 		mac_nat_check_received_count(port_list, port);
2013*4f1223e8SApple OSS Distributions 	}
2014*4f1223e8SApple OSS Distributions 	T_PASS("%s", __func__);
2015*4f1223e8SApple OSS Distributions }
2016*4f1223e8SApple OSS Distributions 
2017*4f1223e8SApple OSS Distributions static void
validate_mac_nat_dhcp(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2018*4f1223e8SApple OSS Distributions validate_mac_nat_dhcp(switch_port_t port, const ether_header_t * eh_p,
2019*4f1223e8SApple OSS Distributions     u_int pkt_len, void * context)
2020*4f1223e8SApple OSS Distributions {
2021*4f1223e8SApple OSS Distributions 	u_int                           dp_flags;
2022*4f1223e8SApple OSS Distributions 	const struct bootp_packet *     pkt;
2023*4f1223e8SApple OSS Distributions 	switch_port_t                   send_port = (switch_port_t)context;
2024*4f1223e8SApple OSS Distributions 
2025*4f1223e8SApple OSS Distributions 
2026*4f1223e8SApple OSS Distributions 	T_QUIET;
2027*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(pkt_len, (u_int)sizeof(*pkt), NULL);
2028*4f1223e8SApple OSS Distributions 	T_QUIET;
2029*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_IP, NULL);
2030*4f1223e8SApple OSS Distributions 	pkt = (const struct bootp_packet *)(const void *)(eh_p + 1);
2031*4f1223e8SApple OSS Distributions 
2032*4f1223e8SApple OSS Distributions 	dp_flags = ntohs(pkt->bp_bootp.bp_unused);
2033*4f1223e8SApple OSS Distributions 	if (port->mac_nat) {
2034*4f1223e8SApple OSS Distributions 		bool            equal;
2035*4f1223e8SApple OSS Distributions 
2036*4f1223e8SApple OSS Distributions 		/* Broadcast bit must be set */
2037*4f1223e8SApple OSS Distributions 		T_QUIET;
2038*4f1223e8SApple OSS Distributions 		T_ASSERT_BITS_SET(dp_flags, (u_int)DHCP_FLAGS_BROADCAST,
2039*4f1223e8SApple OSS Distributions 		    "%s -> %s: flags 0x%x must have 0x%x",
2040*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2041*4f1223e8SApple OSS Distributions 		    port->member_ifname,
2042*4f1223e8SApple OSS Distributions 		    dp_flags, DHCP_FLAGS_BROADCAST);
2043*4f1223e8SApple OSS Distributions 
2044*4f1223e8SApple OSS Distributions 		/* source must match MAC-NAT interface */
2045*4f1223e8SApple OSS Distributions 		equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2046*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
2047*4f1223e8SApple OSS Distributions 		if (!equal) {
2048*4f1223e8SApple OSS Distributions 			ethernet_frame_validate(eh_p, pkt_len, true);
2049*4f1223e8SApple OSS Distributions 		}
2050*4f1223e8SApple OSS Distributions 		T_QUIET;
2051*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2052*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2053*4f1223e8SApple OSS Distributions 		    port->member_ifname);
2054*4f1223e8SApple OSS Distributions 	} else {
2055*4f1223e8SApple OSS Distributions 		/* Broadcast bit must not be set */
2056*4f1223e8SApple OSS Distributions 		T_QUIET;
2057*4f1223e8SApple OSS Distributions 		T_ASSERT_BITS_NOTSET(dp_flags, DHCP_FLAGS_BROADCAST,
2058*4f1223e8SApple OSS Distributions 		    "%s -> %s flags 0x%x must not have 0x%x",
2059*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2060*4f1223e8SApple OSS Distributions 		    port->member_ifname,
2061*4f1223e8SApple OSS Distributions 		    dp_flags, DHCP_FLAGS_BROADCAST);
2062*4f1223e8SApple OSS Distributions 		T_QUIET;
2063*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2064*4f1223e8SApple OSS Distributions 		    "%s -> %s unit %u expected %u",
2065*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2066*4f1223e8SApple OSS Distributions 		    port->member_ifname,
2067*4f1223e8SApple OSS Distributions 		    eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2068*4f1223e8SApple OSS Distributions 	}
2069*4f1223e8SApple OSS Distributions 	port->test_count++;
2070*4f1223e8SApple OSS Distributions }
2071*4f1223e8SApple OSS Distributions 
2072*4f1223e8SApple OSS Distributions static void
mac_nat_test_dhcp(switch_port_list_t port_list,bool link_layer_unicast)2073*4f1223e8SApple OSS Distributions mac_nat_test_dhcp(switch_port_list_t port_list, bool link_layer_unicast)
2074*4f1223e8SApple OSS Distributions {
2075*4f1223e8SApple OSS Distributions 	u_int           i;
2076*4f1223e8SApple OSS Distributions 	struct in_addr  ip_dst = { INADDR_BROADCAST };
2077*4f1223e8SApple OSS Distributions 	struct in_addr  ip_src = { INADDR_ANY };
2078*4f1223e8SApple OSS Distributions 	switch_port_t   port;
2079*4f1223e8SApple OSS Distributions 	ether_addr_t *  ether_dst;
2080*4f1223e8SApple OSS Distributions 
2081*4f1223e8SApple OSS Distributions 	if (link_layer_unicast) {
2082*4f1223e8SApple OSS Distributions 		/* use link-layer address of MAC-NAT interface */
2083*4f1223e8SApple OSS Distributions 		ether_dst = &port_list->list[0].member_mac;
2084*4f1223e8SApple OSS Distributions 	} else {
2085*4f1223e8SApple OSS Distributions 		/* use link-layer broadcast address */
2086*4f1223e8SApple OSS Distributions 		ether_dst = &ether_broadcast;
2087*4f1223e8SApple OSS Distributions 	}
2088*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2089*4f1223e8SApple OSS Distributions 		ether_addr_t            eaddr;
2090*4f1223e8SApple OSS Distributions 		dhcp_min_payload        payload;
2091*4f1223e8SApple OSS Distributions 		u_int                   payload_len;
2092*4f1223e8SApple OSS Distributions 
2093*4f1223e8SApple OSS Distributions 		if (!link_layer_unicast && port->mac_nat) {
2094*4f1223e8SApple OSS Distributions 			/* only send through non-MAC-NAT ports */
2095*4f1223e8SApple OSS Distributions 			continue;
2096*4f1223e8SApple OSS Distributions 		}
2097*4f1223e8SApple OSS Distributions 		set_ethernet_address(&eaddr, port->unit, 0);
2098*4f1223e8SApple OSS Distributions 		payload_len = make_dhcp_payload(&payload, &eaddr);
2099*4f1223e8SApple OSS Distributions 		if (G_debug) {
2100*4f1223e8SApple OSS Distributions 			T_LOG("%s: transmit DHCP packet (member %s)",
2101*4f1223e8SApple OSS Distributions 			    port->ifname, port->member_ifname);
2102*4f1223e8SApple OSS Distributions 		}
2103*4f1223e8SApple OSS Distributions 		switch_port_send_udp(port,
2104*4f1223e8SApple OSS Distributions 		    AF_INET,
2105*4f1223e8SApple OSS Distributions 		    &eaddr,
2106*4f1223e8SApple OSS Distributions 		    (union ifbrip *)&ip_src,
2107*4f1223e8SApple OSS Distributions 		    BOOTP_CLIENT_PORT,
2108*4f1223e8SApple OSS Distributions 		    ether_dst,
2109*4f1223e8SApple OSS Distributions 		    (union ifbrip *)&ip_dst,
2110*4f1223e8SApple OSS Distributions 		    BOOTP_SERVER_PORT,
2111*4f1223e8SApple OSS Distributions 		    &payload,
2112*4f1223e8SApple OSS Distributions 		    payload_len);
2113*4f1223e8SApple OSS Distributions 
2114*4f1223e8SApple OSS Distributions 		switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2115*4f1223e8SApple OSS Distributions 		    validate_mac_nat_dhcp,
2116*4f1223e8SApple OSS Distributions 		    port);
2117*4f1223e8SApple OSS Distributions 
2118*4f1223e8SApple OSS Distributions 		check_received_count(port_list, port, 1);
2119*4f1223e8SApple OSS Distributions 		if (link_layer_unicast) {
2120*4f1223e8SApple OSS Distributions 			/* send a single unicast to MAC-NAT interface */
2121*4f1223e8SApple OSS Distributions 			break;
2122*4f1223e8SApple OSS Distributions 		}
2123*4f1223e8SApple OSS Distributions 	}
2124*4f1223e8SApple OSS Distributions 	T_PASS("%s %s", __func__,
2125*4f1223e8SApple OSS Distributions 	    link_layer_unicast ? "unicast" : "broadcast");
2126*4f1223e8SApple OSS Distributions }
2127*4f1223e8SApple OSS Distributions 
2128*4f1223e8SApple OSS Distributions 
2129*4f1223e8SApple OSS Distributions static void
validate_mac_nat_nd6(switch_port_t port,const struct icmp6_hdr * icmp6,u_int icmp6_len,uint8_t opt_type,u_int nd_hdr_size,switch_port_t send_port)2130*4f1223e8SApple OSS Distributions validate_mac_nat_nd6(switch_port_t port,
2131*4f1223e8SApple OSS Distributions     const struct icmp6_hdr * icmp6,
2132*4f1223e8SApple OSS Distributions     u_int icmp6_len,
2133*4f1223e8SApple OSS Distributions     uint8_t opt_type,
2134*4f1223e8SApple OSS Distributions     u_int nd_hdr_size,
2135*4f1223e8SApple OSS Distributions     switch_port_t send_port)
2136*4f1223e8SApple OSS Distributions {
2137*4f1223e8SApple OSS Distributions 	const uint8_t *                 linkaddr;
2138*4f1223e8SApple OSS Distributions 	const uint8_t *                 ptr;
2139*4f1223e8SApple OSS Distributions 	const struct nd_opt_hdr *       nd_opt;
2140*4f1223e8SApple OSS Distributions 	u_int                           nd_size;
2141*4f1223e8SApple OSS Distributions 
2142*4f1223e8SApple OSS Distributions 	ptr = (const uint8_t *)icmp6;
2143*4f1223e8SApple OSS Distributions 	nd_size = nd_hdr_size + LINKADDR_OPT_LEN;
2144*4f1223e8SApple OSS Distributions 	if (icmp6_len < nd_size) {
2145*4f1223e8SApple OSS Distributions 		/* no LINKADDR option */
2146*4f1223e8SApple OSS Distributions 		return;
2147*4f1223e8SApple OSS Distributions 	}
2148*4f1223e8SApple OSS Distributions 	nd_opt = (const struct nd_opt_hdr *)(const void *)(ptr + nd_hdr_size);
2149*4f1223e8SApple OSS Distributions 	T_QUIET;
2150*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(nd_opt->nd_opt_type, opt_type,
2151*4f1223e8SApple OSS Distributions 	    "nd_opt->nd_opt_type 0x%x, opt_type 0x%x",
2152*4f1223e8SApple OSS Distributions 	    nd_opt->nd_opt_type, opt_type);
2153*4f1223e8SApple OSS Distributions 	T_QUIET;
2154*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(GET_ND_OPT_LEN(nd_opt->nd_opt_len), LINKADDR_OPT_LEN, NULL);
2155*4f1223e8SApple OSS Distributions 	linkaddr = (const uint8_t *)(nd_opt + 1);
2156*4f1223e8SApple OSS Distributions 	if (port->mac_nat) {
2157*4f1223e8SApple OSS Distributions 		bool    equal;
2158*4f1223e8SApple OSS Distributions 
2159*4f1223e8SApple OSS Distributions 		equal = (bcmp(linkaddr, &port->member_mac,
2160*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
2161*4f1223e8SApple OSS Distributions 		T_QUIET;
2162*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "%s -> %s sender hardware translated",
2163*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2164*4f1223e8SApple OSS Distributions 		    port->member_ifname);
2165*4f1223e8SApple OSS Distributions 	} else {
2166*4f1223e8SApple OSS Distributions 		/* source hw must match the sender */
2167*4f1223e8SApple OSS Distributions 		T_QUIET;
2168*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(linkaddr[EA_UNIT_INDEX], send_port->unit,
2169*4f1223e8SApple OSS Distributions 		    "%s -> %s unit %u expected %u",
2170*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2171*4f1223e8SApple OSS Distributions 		    port->member_ifname,
2172*4f1223e8SApple OSS Distributions 		    linkaddr[EA_UNIT_INDEX], send_port->unit);
2173*4f1223e8SApple OSS Distributions 	}
2174*4f1223e8SApple OSS Distributions }
2175*4f1223e8SApple OSS Distributions 
2176*4f1223e8SApple OSS Distributions static void
validate_mac_nat_icmp6_out(switch_port_t port,const struct icmp6_hdr * icmp6,u_int icmp6_len,switch_port_t send_port)2177*4f1223e8SApple OSS Distributions validate_mac_nat_icmp6_out(switch_port_t port, const struct icmp6_hdr * icmp6,
2178*4f1223e8SApple OSS Distributions     u_int icmp6_len, switch_port_t send_port)
2179*4f1223e8SApple OSS Distributions {
2180*4f1223e8SApple OSS Distributions 	switch (icmp6->icmp6_type) {
2181*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_ADVERT:
2182*4f1223e8SApple OSS Distributions 		validate_mac_nat_nd6(port, icmp6, icmp6_len,
2183*4f1223e8SApple OSS Distributions 		    ND_OPT_TARGET_LINKADDR,
2184*4f1223e8SApple OSS Distributions 		    sizeof(struct nd_neighbor_advert),
2185*4f1223e8SApple OSS Distributions 		    send_port);
2186*4f1223e8SApple OSS Distributions 		break;
2187*4f1223e8SApple OSS Distributions 	case ND_NEIGHBOR_SOLICIT:
2188*4f1223e8SApple OSS Distributions 		validate_mac_nat_nd6(port, icmp6, icmp6_len,
2189*4f1223e8SApple OSS Distributions 		    ND_OPT_SOURCE_LINKADDR,
2190*4f1223e8SApple OSS Distributions 		    sizeof(struct nd_neighbor_solicit),
2191*4f1223e8SApple OSS Distributions 		    send_port);
2192*4f1223e8SApple OSS Distributions 		break;
2193*4f1223e8SApple OSS Distributions 	case ND_ROUTER_SOLICIT:
2194*4f1223e8SApple OSS Distributions 		validate_mac_nat_nd6(port, icmp6, icmp6_len,
2195*4f1223e8SApple OSS Distributions 		    ND_OPT_SOURCE_LINKADDR,
2196*4f1223e8SApple OSS Distributions 		    sizeof(struct nd_router_solicit),
2197*4f1223e8SApple OSS Distributions 		    send_port);
2198*4f1223e8SApple OSS Distributions 		break;
2199*4f1223e8SApple OSS Distributions 	default:
2200*4f1223e8SApple OSS Distributions 		T_FAIL("Unsupported icmp6 type %d", icmp6->icmp6_type);
2201*4f1223e8SApple OSS Distributions 		break;
2202*4f1223e8SApple OSS Distributions 	}
2203*4f1223e8SApple OSS Distributions }
2204*4f1223e8SApple OSS Distributions 
2205*4f1223e8SApple OSS Distributions static void
validate_mac_nat_nd6_out(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2206*4f1223e8SApple OSS Distributions validate_mac_nat_nd6_out(switch_port_t port, const ether_header_t * eh_p,
2207*4f1223e8SApple OSS Distributions     u_int pkt_len, void * context)
2208*4f1223e8SApple OSS Distributions {
2209*4f1223e8SApple OSS Distributions 	const struct icmp6_hdr *        icmp6;
2210*4f1223e8SApple OSS Distributions 	const struct ip6_hdr *          ip6;
2211*4f1223e8SApple OSS Distributions 	unsigned int                    payload_length;
2212*4f1223e8SApple OSS Distributions 	switch_port_t                   send_port = (switch_port_t)context;
2213*4f1223e8SApple OSS Distributions 
2214*4f1223e8SApple OSS Distributions 	if (G_debug) {
2215*4f1223e8SApple OSS Distributions 		T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2216*4f1223e8SApple OSS Distributions 		ethernet_frame_validate(eh_p, pkt_len, true);
2217*4f1223e8SApple OSS Distributions 	}
2218*4f1223e8SApple OSS Distributions 	T_QUIET;
2219*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(ntohs(eh_p->ether_type), (u_short)ETHERTYPE_IPV6, NULL);
2220*4f1223e8SApple OSS Distributions 	ip6 = (const struct ip6_hdr *)(const void *)(eh_p + 1);
2221*4f1223e8SApple OSS Distributions 	icmp6 = (const struct icmp6_hdr *)(const void *)(ip6 + 1);
2222*4f1223e8SApple OSS Distributions 	T_QUIET;
2223*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(pkt_len, (u_int)MIN_ICMP6_LEN, NULL);
2224*4f1223e8SApple OSS Distributions 	T_QUIET;
2225*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(ip6->ip6_nxt, IPPROTO_ICMPV6, NULL);
2226*4f1223e8SApple OSS Distributions 
2227*4f1223e8SApple OSS Distributions 	/* validate the ethernet header */
2228*4f1223e8SApple OSS Distributions 	if (port->mac_nat) {
2229*4f1223e8SApple OSS Distributions 		bool            equal;
2230*4f1223e8SApple OSS Distributions 
2231*4f1223e8SApple OSS Distributions 		/* source ethernet must match MAC-NAT interface */
2232*4f1223e8SApple OSS Distributions 		equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2233*4f1223e8SApple OSS Distributions 		    sizeof(port->member_mac)) == 0);
2234*4f1223e8SApple OSS Distributions 		if (!equal) {
2235*4f1223e8SApple OSS Distributions 			ethernet_frame_validate(eh_p, pkt_len, true);
2236*4f1223e8SApple OSS Distributions 		}
2237*4f1223e8SApple OSS Distributions 		T_QUIET;
2238*4f1223e8SApple OSS Distributions 		T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2239*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2240*4f1223e8SApple OSS Distributions 		    port->member_ifname);
2241*4f1223e8SApple OSS Distributions 	} else {
2242*4f1223e8SApple OSS Distributions 		/* source ethernet must match the sender */
2243*4f1223e8SApple OSS Distributions 		T_QUIET;
2244*4f1223e8SApple OSS Distributions 		T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2245*4f1223e8SApple OSS Distributions 		    "%s -> %s unit %u expected %u",
2246*4f1223e8SApple OSS Distributions 		    send_port->member_ifname,
2247*4f1223e8SApple OSS Distributions 		    port->member_ifname,
2248*4f1223e8SApple OSS Distributions 		    eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2249*4f1223e8SApple OSS Distributions 	}
2250*4f1223e8SApple OSS Distributions 	/* validate the icmp6 payload */
2251*4f1223e8SApple OSS Distributions 	payload_length = ntohs(ip6->ip6_plen);
2252*4f1223e8SApple OSS Distributions 	validate_mac_nat_icmp6_out(port, icmp6, payload_length, send_port);
2253*4f1223e8SApple OSS Distributions 	port->test_count++;
2254*4f1223e8SApple OSS Distributions }
2255*4f1223e8SApple OSS Distributions 
2256*4f1223e8SApple OSS Distributions static void
mac_nat_test_nd6_out(switch_port_list_t port_list)2257*4f1223e8SApple OSS Distributions mac_nat_test_nd6_out(switch_port_list_t port_list)
2258*4f1223e8SApple OSS Distributions {
2259*4f1223e8SApple OSS Distributions 	ether_addr_t *  ext_mac;
2260*4f1223e8SApple OSS Distributions 	switch_port_t   ext_port;
2261*4f1223e8SApple OSS Distributions 	u_int           i;
2262*4f1223e8SApple OSS Distributions 	union ifbrip    ip_dst;
2263*4f1223e8SApple OSS Distributions 	switch_port_t   port;
2264*4f1223e8SApple OSS Distributions 
2265*4f1223e8SApple OSS Distributions 	get_external_ip_address(AF_INET6, &ip_dst);
2266*4f1223e8SApple OSS Distributions 	ext_port = port_list->list;
2267*4f1223e8SApple OSS Distributions 	T_QUIET;
2268*4f1223e8SApple OSS Distributions 	T_ASSERT_TRUE(ext_port->mac_nat, NULL);
2269*4f1223e8SApple OSS Distributions 	ext_mac = &ext_port->member_mac;
2270*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2271*4f1223e8SApple OSS Distributions 		if (port->mac_nat) {
2272*4f1223e8SApple OSS Distributions 			continue;
2273*4f1223e8SApple OSS Distributions 		}
2274*4f1223e8SApple OSS Distributions 		/* neighbor solicit */
2275*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
2276*4f1223e8SApple OSS Distributions 			ether_addr_t    eaddr;
2277*4f1223e8SApple OSS Distributions 			union ifbrip    ip_src;
2278*4f1223e8SApple OSS Distributions 
2279*4f1223e8SApple OSS Distributions 			set_ethernet_address(&eaddr, port->unit, j);
2280*4f1223e8SApple OSS Distributions 			get_ip_address(AF_INET6, port->unit, j, &ip_src);
2281*4f1223e8SApple OSS Distributions 			switch_port_send_nd6(port,
2282*4f1223e8SApple OSS Distributions 			    ND_NEIGHBOR_SOLICIT,
2283*4f1223e8SApple OSS Distributions 			    &eaddr,
2284*4f1223e8SApple OSS Distributions 			    &ip_src.ifbrip_addr6,
2285*4f1223e8SApple OSS Distributions 			    NULL,
2286*4f1223e8SApple OSS Distributions 			    NULL,
2287*4f1223e8SApple OSS Distributions 			    &ip_dst.ifbrip_addr6);
2288*4f1223e8SApple OSS Distributions 			switch_port_list_check_receive(port_list, AF_INET,
2289*4f1223e8SApple OSS Distributions 			    NULL, 0,
2290*4f1223e8SApple OSS Distributions 			    validate_mac_nat_nd6_out,
2291*4f1223e8SApple OSS Distributions 			    port);
2292*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
2293*4f1223e8SApple OSS Distributions 		}
2294*4f1223e8SApple OSS Distributions 		/* neighbor advert */
2295*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
2296*4f1223e8SApple OSS Distributions 			ether_addr_t    eaddr;
2297*4f1223e8SApple OSS Distributions 			union ifbrip    ip_src;
2298*4f1223e8SApple OSS Distributions 
2299*4f1223e8SApple OSS Distributions 			set_ethernet_address(&eaddr, port->unit, j);
2300*4f1223e8SApple OSS Distributions 			get_ip_address(AF_INET6, port->unit, j, &ip_src);
2301*4f1223e8SApple OSS Distributions 			switch_port_send_nd6(port,
2302*4f1223e8SApple OSS Distributions 			    ND_NEIGHBOR_ADVERT,
2303*4f1223e8SApple OSS Distributions 			    &eaddr,
2304*4f1223e8SApple OSS Distributions 			    &ip_src.ifbrip_addr6,
2305*4f1223e8SApple OSS Distributions 			    NULL,
2306*4f1223e8SApple OSS Distributions 			    &eaddr,
2307*4f1223e8SApple OSS Distributions 			    &ip_src.ifbrip_addr6);
2308*4f1223e8SApple OSS Distributions 			switch_port_list_check_receive(port_list, AF_INET,
2309*4f1223e8SApple OSS Distributions 			    NULL, 0,
2310*4f1223e8SApple OSS Distributions 			    validate_mac_nat_nd6_out,
2311*4f1223e8SApple OSS Distributions 			    port);
2312*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
2313*4f1223e8SApple OSS Distributions 		}
2314*4f1223e8SApple OSS Distributions 		/* router solicit */
2315*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
2316*4f1223e8SApple OSS Distributions 			ether_addr_t    eaddr;
2317*4f1223e8SApple OSS Distributions 			union ifbrip    ip_src;
2318*4f1223e8SApple OSS Distributions 
2319*4f1223e8SApple OSS Distributions 			set_ethernet_address(&eaddr, port->unit, j);
2320*4f1223e8SApple OSS Distributions 			get_ip_address(AF_INET6, port->unit, j, &ip_src);
2321*4f1223e8SApple OSS Distributions 			//get_ipv6ll_address(port->unit, j, &ip_src.ifbrip_addr6);
2322*4f1223e8SApple OSS Distributions 			switch_port_send_nd6(port,
2323*4f1223e8SApple OSS Distributions 			    ND_ROUTER_SOLICIT,
2324*4f1223e8SApple OSS Distributions 			    &eaddr,
2325*4f1223e8SApple OSS Distributions 			    &ip_src.ifbrip_addr6,
2326*4f1223e8SApple OSS Distributions 			    NULL,
2327*4f1223e8SApple OSS Distributions 			    NULL,
2328*4f1223e8SApple OSS Distributions 			    NULL);
2329*4f1223e8SApple OSS Distributions 			switch_port_list_check_receive(port_list, AF_INET,
2330*4f1223e8SApple OSS Distributions 			    NULL, 0,
2331*4f1223e8SApple OSS Distributions 			    validate_mac_nat_nd6_out,
2332*4f1223e8SApple OSS Distributions 			    port);
2333*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
2334*4f1223e8SApple OSS Distributions 		}
2335*4f1223e8SApple OSS Distributions 	}
2336*4f1223e8SApple OSS Distributions 	T_PASS("%s", __func__);
2337*4f1223e8SApple OSS Distributions }
2338*4f1223e8SApple OSS Distributions 
2339*4f1223e8SApple OSS Distributions static void
mac_nat_send_response(switch_port_t ext_port,uint8_t af,switch_port_t port)2340*4f1223e8SApple OSS Distributions mac_nat_send_response(switch_port_t ext_port, uint8_t af, switch_port_t port)
2341*4f1223e8SApple OSS Distributions {
2342*4f1223e8SApple OSS Distributions 	union ifbrip    src_ip;
2343*4f1223e8SApple OSS Distributions 
2344*4f1223e8SApple OSS Distributions 	T_QUIET;
2345*4f1223e8SApple OSS Distributions 	T_ASSERT_TRUE(ext_port->mac_nat, "%s is MAC-NAT interface",
2346*4f1223e8SApple OSS Distributions 	    ext_port->member_ifname);
2347*4f1223e8SApple OSS Distributions 	if (G_debug) {
2348*4f1223e8SApple OSS Distributions 		T_LOG("Generating UDP traffic destined to %s", port->ifname);
2349*4f1223e8SApple OSS Distributions 	}
2350*4f1223e8SApple OSS Distributions 	get_external_ip_address(af, &src_ip);
2351*4f1223e8SApple OSS Distributions 	for (u_int j = 0; j < port->num_addrs; j++) {
2352*4f1223e8SApple OSS Distributions 		union ifbrip    ip;
2353*4f1223e8SApple OSS Distributions 
2354*4f1223e8SApple OSS Distributions 		get_ip_address(af, port->unit, j, &ip);
2355*4f1223e8SApple OSS Distributions 		switch_port_send_udp(ext_port,
2356*4f1223e8SApple OSS Distributions 		    af,
2357*4f1223e8SApple OSS Distributions 		    &ether_external,
2358*4f1223e8SApple OSS Distributions 		    &src_ip,
2359*4f1223e8SApple OSS Distributions 		    TEST_DEST_PORT,
2360*4f1223e8SApple OSS Distributions 		    &ext_port->member_mac,
2361*4f1223e8SApple OSS Distributions 		    &ip,
2362*4f1223e8SApple OSS Distributions 		    TEST_SOURCE_PORT,
2363*4f1223e8SApple OSS Distributions 		    NULL, 0);
2364*4f1223e8SApple OSS Distributions 	}
2365*4f1223e8SApple OSS Distributions }
2366*4f1223e8SApple OSS Distributions 
2367*4f1223e8SApple OSS Distributions 
2368*4f1223e8SApple OSS Distributions static void
mac_nat_test_ip_once(switch_port_list_t port_list,uint8_t af,bool retry)2369*4f1223e8SApple OSS Distributions mac_nat_test_ip_once(switch_port_list_t port_list, uint8_t af, bool retry)
2370*4f1223e8SApple OSS Distributions {
2371*4f1223e8SApple OSS Distributions 	union ifbrip    dst_ip;
2372*4f1223e8SApple OSS Distributions 	u_int           i;
2373*4f1223e8SApple OSS Distributions 	switch_port_t   port;
2374*4f1223e8SApple OSS Distributions 
2375*4f1223e8SApple OSS Distributions 	get_external_ip_address(af, &dst_ip);
2376*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2377*4f1223e8SApple OSS Distributions 		if (port->test_address_count == port->num_addrs) {
2378*4f1223e8SApple OSS Distributions 			/* already populated */
2379*4f1223e8SApple OSS Distributions 			continue;
2380*4f1223e8SApple OSS Distributions 		}
2381*4f1223e8SApple OSS Distributions 		if (G_debug) {
2382*4f1223e8SApple OSS Distributions 			T_LOG("Sending on %s", port->ifname);
2383*4f1223e8SApple OSS Distributions 		}
2384*4f1223e8SApple OSS Distributions 		for (u_int j = 0; j < port->num_addrs; j++) {
2385*4f1223e8SApple OSS Distributions 			uint32_t        generation;
2386*4f1223e8SApple OSS Distributions 
2387*4f1223e8SApple OSS Distributions 			if (retry) {
2388*4f1223e8SApple OSS Distributions 				uint64_t        addr_bit;
2389*4f1223e8SApple OSS Distributions 
2390*4f1223e8SApple OSS Distributions 				addr_bit = 1 << j;
2391*4f1223e8SApple OSS Distributions 				if ((port->test_address_present & addr_bit)
2392*4f1223e8SApple OSS Distributions 				    != 0) {
2393*4f1223e8SApple OSS Distributions 					/* already present */
2394*4f1223e8SApple OSS Distributions 					continue;
2395*4f1223e8SApple OSS Distributions 				}
2396*4f1223e8SApple OSS Distributions 				T_LOG("Retry port %s unit %u address %u",
2397*4f1223e8SApple OSS Distributions 				    port->ifname, port->unit, j);
2398*4f1223e8SApple OSS Distributions 			}
2399*4f1223e8SApple OSS Distributions 
2400*4f1223e8SApple OSS Distributions 			generation = next_generation();
2401*4f1223e8SApple OSS Distributions 			send_generation(port,
2402*4f1223e8SApple OSS Distributions 			    af,
2403*4f1223e8SApple OSS Distributions 			    j,
2404*4f1223e8SApple OSS Distributions 			    &ether_external,
2405*4f1223e8SApple OSS Distributions 			    &dst_ip,
2406*4f1223e8SApple OSS Distributions 			    generation);
2407*4f1223e8SApple OSS Distributions 
2408*4f1223e8SApple OSS Distributions 			/* receive across all ports */
2409*4f1223e8SApple OSS Distributions 			check_receive_generation(port_list,
2410*4f1223e8SApple OSS Distributions 			    af,
2411*4f1223e8SApple OSS Distributions 			    generation,
2412*4f1223e8SApple OSS Distributions 			    validate_mac_nat,
2413*4f1223e8SApple OSS Distributions 			    NULL);
2414*4f1223e8SApple OSS Distributions 
2415*4f1223e8SApple OSS Distributions 			/* ensure that every port saw the packet */
2416*4f1223e8SApple OSS Distributions 			check_received_count(port_list, port, 1);
2417*4f1223e8SApple OSS Distributions 		}
2418*4f1223e8SApple OSS Distributions 	}
2419*4f1223e8SApple OSS Distributions 	return;
2420*4f1223e8SApple OSS Distributions }
2421*4f1223e8SApple OSS Distributions 
2422*4f1223e8SApple OSS Distributions static void
mac_nat_test_ip(switch_port_list_t port_list,uint8_t af)2423*4f1223e8SApple OSS Distributions mac_nat_test_ip(switch_port_list_t port_list, uint8_t af)
2424*4f1223e8SApple OSS Distributions {
2425*4f1223e8SApple OSS Distributions 	u_int           i;
2426*4f1223e8SApple OSS Distributions 	switch_port_t   port;
2427*4f1223e8SApple OSS Distributions 	bool            verified = false;
2428*4f1223e8SApple OSS Distributions 
2429*4f1223e8SApple OSS Distributions 	/*
2430*4f1223e8SApple OSS Distributions 	 * Send a packet from every port in the list so that the bridge
2431*4f1223e8SApple OSS Distributions 	 * learns the MAC addresses and IP addresses.
2432*4f1223e8SApple OSS Distributions 	 */
2433*4f1223e8SApple OSS Distributions #define MAC_NAT_MAX_TRIES               20
2434*4f1223e8SApple OSS Distributions 	for (int try = 1; try < BROADCAST_MAX_TRIES; try++) {
2435*4f1223e8SApple OSS Distributions 		bool    retry = (try > 1);
2436*4f1223e8SApple OSS Distributions 
2437*4f1223e8SApple OSS Distributions 		if (!retry) {
2438*4f1223e8SApple OSS Distributions 			T_LOG("%s: #ports %u #addrs %u",
2439*4f1223e8SApple OSS Distributions 			    __func__,
2440*4f1223e8SApple OSS Distributions 			    port_list->count, port_list->list->num_addrs);
2441*4f1223e8SApple OSS Distributions 		} else {
2442*4f1223e8SApple OSS Distributions 			T_LOG("%s: #ports %u #addrs %u destination (TRY=%d)",
2443*4f1223e8SApple OSS Distributions 			    __func__,
2444*4f1223e8SApple OSS Distributions 			    port_list->count, port_list->list->num_addrs,
2445*4f1223e8SApple OSS Distributions 			    try);
2446*4f1223e8SApple OSS Distributions 		}
2447*4f1223e8SApple OSS Distributions 		mac_nat_test_ip_once(port_list, af, retry);
2448*4f1223e8SApple OSS Distributions 		/*
2449*4f1223e8SApple OSS Distributions 		 * In the event of a memory allocation failure, it's possible
2450*4f1223e8SApple OSS Distributions 		 * that the address was not learned. Figure out whether
2451*4f1223e8SApple OSS Distributions 		 * all addresses are present, and if not, we'll retry on
2452*4f1223e8SApple OSS Distributions 		 * those that are not present.
2453*4f1223e8SApple OSS Distributions 		 */
2454*4f1223e8SApple OSS Distributions 		verified = switch_port_list_verify_mac_nat(port_list, false);
2455*4f1223e8SApple OSS Distributions 		if (verified) {
2456*4f1223e8SApple OSS Distributions 			break;
2457*4f1223e8SApple OSS Distributions 		}
2458*4f1223e8SApple OSS Distributions 		/* wait a short time to allow the system to recover */
2459*4f1223e8SApple OSS Distributions 		usleep(100 * 1000);
2460*4f1223e8SApple OSS Distributions 	}
2461*4f1223e8SApple OSS Distributions 	T_QUIET;
2462*4f1223e8SApple OSS Distributions 	T_ASSERT_TRUE(verified, "All addresses present");
2463*4f1223e8SApple OSS Distributions 
2464*4f1223e8SApple OSS Distributions 	/*
2465*4f1223e8SApple OSS Distributions 	 * The bridge now has an IP address <-> MAC address binding for every
2466*4f1223e8SApple OSS Distributions 	 * address on each internal interface.
2467*4f1223e8SApple OSS Distributions 	 *
2468*4f1223e8SApple OSS Distributions 	 * Generate an inbound packet on the MAC-NAT interface targeting
2469*4f1223e8SApple OSS Distributions 	 * each interface address. Verify that the packet appears on
2470*4f1223e8SApple OSS Distributions 	 * the appropriate internal address with appropriate translation.
2471*4f1223e8SApple OSS Distributions 	 */
2472*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2473*4f1223e8SApple OSS Distributions 		if (port->mac_nat) {
2474*4f1223e8SApple OSS Distributions 			continue;
2475*4f1223e8SApple OSS Distributions 		}
2476*4f1223e8SApple OSS Distributions 		mac_nat_send_response(port_list->list, af, port);
2477*4f1223e8SApple OSS Distributions 
2478*4f1223e8SApple OSS Distributions 		/* receive the generated traffic */
2479*4f1223e8SApple OSS Distributions 		switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2480*4f1223e8SApple OSS Distributions 		    validate_mac_nat_in,
2481*4f1223e8SApple OSS Distributions 		    NULL);
2482*4f1223e8SApple OSS Distributions 
2483*4f1223e8SApple OSS Distributions 		/* verify that only the single port got the packet */
2484*4f1223e8SApple OSS Distributions 		mac_nat_check_received_count(port_list, port);
2485*4f1223e8SApple OSS Distributions 	}
2486*4f1223e8SApple OSS Distributions 	T_PASS("%s", __func__);
2487*4f1223e8SApple OSS Distributions }
2488*4f1223e8SApple OSS Distributions 
2489*4f1223e8SApple OSS Distributions /**
2490*4f1223e8SApple OSS Distributions ** interface management
2491*4f1223e8SApple OSS Distributions **/
2492*4f1223e8SApple OSS Distributions 
2493*4f1223e8SApple OSS Distributions static int
bridge_delete_member(const char * bridge,const char * member)2494*4f1223e8SApple OSS Distributions bridge_delete_member(const char * bridge, const char * member)
2495*4f1223e8SApple OSS Distributions {
2496*4f1223e8SApple OSS Distributions 	struct ifbreq           req;
2497*4f1223e8SApple OSS Distributions 	int                     ret;
2498*4f1223e8SApple OSS Distributions 
2499*4f1223e8SApple OSS Distributions 	memset(&req, 0, sizeof(req));
2500*4f1223e8SApple OSS Distributions 	strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
2501*4f1223e8SApple OSS Distributions 	ret = siocdrvspec(bridge, BRDGDEL, &req, sizeof(req), true);
2502*4f1223e8SApple OSS Distributions 	T_QUIET;
2503*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s", __func__, bridge, member);
2504*4f1223e8SApple OSS Distributions 	return ret;
2505*4f1223e8SApple OSS Distributions }
2506*4f1223e8SApple OSS Distributions 
2507*4f1223e8SApple OSS Distributions 
2508*4f1223e8SApple OSS Distributions static int
bridge_member_modify_ifflags(const char * bridge,const char * member,uint32_t flags_to_modify,bool set)2509*4f1223e8SApple OSS Distributions bridge_member_modify_ifflags(const char * bridge, const char * member,
2510*4f1223e8SApple OSS Distributions     uint32_t flags_to_modify, bool set)
2511*4f1223e8SApple OSS Distributions {
2512*4f1223e8SApple OSS Distributions 	uint32_t        flags;
2513*4f1223e8SApple OSS Distributions 	bool            need_set = false;
2514*4f1223e8SApple OSS Distributions 	struct ifbreq   req;
2515*4f1223e8SApple OSS Distributions 	int             ret;
2516*4f1223e8SApple OSS Distributions 
2517*4f1223e8SApple OSS Distributions 	memset(&req, 0, sizeof(req));
2518*4f1223e8SApple OSS Distributions 	strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
2519*4f1223e8SApple OSS Distributions 	ret = siocdrvspec(bridge, BRDGGIFFLGS, &req, sizeof(req), false);
2520*4f1223e8SApple OSS Distributions 	T_QUIET;
2521*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "BRDGGIFFLGS %s %s", bridge, member);
2522*4f1223e8SApple OSS Distributions 	flags = req.ifbr_ifsflags;
2523*4f1223e8SApple OSS Distributions 	if (set) {
2524*4f1223e8SApple OSS Distributions 		if ((flags & flags_to_modify) != flags_to_modify) {
2525*4f1223e8SApple OSS Distributions 			need_set = true;
2526*4f1223e8SApple OSS Distributions 			req.ifbr_ifsflags |= flags_to_modify;
2527*4f1223e8SApple OSS Distributions 		}
2528*4f1223e8SApple OSS Distributions 		/* need to set it */
2529*4f1223e8SApple OSS Distributions 	} else if ((flags & flags_to_modify) != 0) {
2530*4f1223e8SApple OSS Distributions 		/* need to clear it */
2531*4f1223e8SApple OSS Distributions 		need_set = true;
2532*4f1223e8SApple OSS Distributions 		req.ifbr_ifsflags &= ~flags_to_modify;
2533*4f1223e8SApple OSS Distributions 	}
2534*4f1223e8SApple OSS Distributions 	if (need_set) {
2535*4f1223e8SApple OSS Distributions 		ret = siocdrvspec(bridge, BRDGSIFFLGS,
2536*4f1223e8SApple OSS Distributions 		    &req, sizeof(req), true);
2537*4f1223e8SApple OSS Distributions 		T_QUIET;
2538*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "BRDGSIFFLGS %s %s 0x%x => 0x%x",
2539*4f1223e8SApple OSS Distributions 		    bridge, member,
2540*4f1223e8SApple OSS Distributions 		    flags, req.ifbr_ifsflags);
2541*4f1223e8SApple OSS Distributions 	}
2542*4f1223e8SApple OSS Distributions 	return ret;
2543*4f1223e8SApple OSS Distributions }
2544*4f1223e8SApple OSS Distributions 
2545*4f1223e8SApple OSS Distributions static int
bridge_member_modify_mac_nat(const char * bridge,const char * member,bool enable)2546*4f1223e8SApple OSS Distributions bridge_member_modify_mac_nat(const char * bridge,
2547*4f1223e8SApple OSS Distributions     const char * member, bool enable)
2548*4f1223e8SApple OSS Distributions {
2549*4f1223e8SApple OSS Distributions 	return bridge_member_modify_ifflags(bridge, member,
2550*4f1223e8SApple OSS Distributions 	           IFBIF_MAC_NAT,
2551*4f1223e8SApple OSS Distributions 	           enable);
2552*4f1223e8SApple OSS Distributions }
2553*4f1223e8SApple OSS Distributions 
2554*4f1223e8SApple OSS Distributions static int
bridge_member_modify_checksum_offload(const char * bridge,const char * member,bool enable)2555*4f1223e8SApple OSS Distributions bridge_member_modify_checksum_offload(const char * bridge,
2556*4f1223e8SApple OSS Distributions     const char * member, bool enable)
2557*4f1223e8SApple OSS Distributions {
2558*4f1223e8SApple OSS Distributions #ifndef IFBIF_CHECKSUM_OFFLOAD
2559*4f1223e8SApple OSS Distributions #define IFBIF_CHECKSUM_OFFLOAD  0x10000 /* checksum inbound packets,
2560*4f1223e8SApple OSS Distributions 	                                 * drop outbound packets with
2561*4f1223e8SApple OSS Distributions 	                                 * bad checksum
2562*4f1223e8SApple OSS Distributions 	                                 */
2563*4f1223e8SApple OSS Distributions #endif
2564*4f1223e8SApple OSS Distributions 	return bridge_member_modify_ifflags(bridge, member,
2565*4f1223e8SApple OSS Distributions 	           IFBIF_CHECKSUM_OFFLOAD,
2566*4f1223e8SApple OSS Distributions 	           enable);
2567*4f1223e8SApple OSS Distributions }
2568*4f1223e8SApple OSS Distributions 
2569*4f1223e8SApple OSS Distributions static struct ifbareq *
bridge_rt_table_copy_common(const char * bridge,u_int * ret_count)2570*4f1223e8SApple OSS Distributions bridge_rt_table_copy_common(const char * bridge, u_int * ret_count)
2571*4f1223e8SApple OSS Distributions {
2572*4f1223e8SApple OSS Distributions 	struct ifbaconf         ifbac;
2573*4f1223e8SApple OSS Distributions 	u_int                   len = 8 * 1024;
2574*4f1223e8SApple OSS Distributions 	char *                  inbuf = NULL;
2575*4f1223e8SApple OSS Distributions 	char *                  ninbuf;
2576*4f1223e8SApple OSS Distributions 	int                     ret;
2577*4f1223e8SApple OSS Distributions 	struct ifbareq *        rt_table = NULL;
2578*4f1223e8SApple OSS Distributions 
2579*4f1223e8SApple OSS Distributions 	/*
2580*4f1223e8SApple OSS Distributions 	 * BRDGRTS should work like other ioctl's where passing in NULL
2581*4f1223e8SApple OSS Distributions 	 * for the buffer says "tell me how many there are". Unfortunately,
2582*4f1223e8SApple OSS Distributions 	 * it doesn't so we have to pass in a buffer, then check that it
2583*4f1223e8SApple OSS Distributions 	 * was too big.
2584*4f1223e8SApple OSS Distributions 	 */
2585*4f1223e8SApple OSS Distributions 	for (;;) {
2586*4f1223e8SApple OSS Distributions 		ninbuf = realloc(inbuf, len);
2587*4f1223e8SApple OSS Distributions 		T_QUIET;
2588*4f1223e8SApple OSS Distributions 		T_ASSERT_NOTNULL((void *)ninbuf, "realloc %u", len);
2589*4f1223e8SApple OSS Distributions 		ifbac.ifbac_len = len;
2590*4f1223e8SApple OSS Distributions 		ifbac.ifbac_buf = inbuf = ninbuf;
2591*4f1223e8SApple OSS Distributions 		ret = siocdrvspec(bridge, BRDGRTS,
2592*4f1223e8SApple OSS Distributions 		    &ifbac, sizeof(ifbac), false);
2593*4f1223e8SApple OSS Distributions 		T_QUIET;
2594*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "%s %s", __func__, bridge);
2595*4f1223e8SApple OSS Distributions 		if ((ifbac.ifbac_len + sizeof(*rt_table)) < len) {
2596*4f1223e8SApple OSS Distributions 			/* we passed a buffer larger than what was required */
2597*4f1223e8SApple OSS Distributions 			break;
2598*4f1223e8SApple OSS Distributions 		}
2599*4f1223e8SApple OSS Distributions 		len *= 2;
2600*4f1223e8SApple OSS Distributions 	}
2601*4f1223e8SApple OSS Distributions 	if (ifbac.ifbac_len == 0) {
2602*4f1223e8SApple OSS Distributions 		free(ninbuf);
2603*4f1223e8SApple OSS Distributions 		T_LOG("No bridge routing entries");
2604*4f1223e8SApple OSS Distributions 		goto done;
2605*4f1223e8SApple OSS Distributions 	}
2606*4f1223e8SApple OSS Distributions 	*ret_count = ifbac.ifbac_len / sizeof(*rt_table);
2607*4f1223e8SApple OSS Distributions 	rt_table = (struct ifbareq *)(void *)ninbuf;
2608*4f1223e8SApple OSS Distributions done:
2609*4f1223e8SApple OSS Distributions 	if (rt_table == NULL) {
2610*4f1223e8SApple OSS Distributions 		*ret_count = 0;
2611*4f1223e8SApple OSS Distributions 	}
2612*4f1223e8SApple OSS Distributions 	return rt_table;
2613*4f1223e8SApple OSS Distributions }
2614*4f1223e8SApple OSS Distributions 
2615*4f1223e8SApple OSS Distributions static struct ifbareq *
bridge_rt_table_copy(u_int * ret_count)2616*4f1223e8SApple OSS Distributions bridge_rt_table_copy(u_int * ret_count)
2617*4f1223e8SApple OSS Distributions {
2618*4f1223e8SApple OSS Distributions 	return bridge_rt_table_copy_common(BRIDGE200, ret_count);
2619*4f1223e8SApple OSS Distributions }
2620*4f1223e8SApple OSS Distributions 
2621*4f1223e8SApple OSS Distributions static void
bridge_rt_table_log(struct ifbareq * rt_table,u_int count)2622*4f1223e8SApple OSS Distributions bridge_rt_table_log(struct ifbareq *rt_table, u_int count)
2623*4f1223e8SApple OSS Distributions {
2624*4f1223e8SApple OSS Distributions 	u_int                   i;
2625*4f1223e8SApple OSS Distributions 	char                    ntoabuf[ETHER_NTOA_BUFSIZE];
2626*4f1223e8SApple OSS Distributions 	struct ifbareq *        ifba;
2627*4f1223e8SApple OSS Distributions 
2628*4f1223e8SApple OSS Distributions 	for (i = 0, ifba = rt_table; i < count; i++, ifba++) {
2629*4f1223e8SApple OSS Distributions 		ether_ntoa_buf((const ether_addr_t *)&ifba->ifba_dst,
2630*4f1223e8SApple OSS Distributions 		    ntoabuf, sizeof(ntoabuf));
2631*4f1223e8SApple OSS Distributions 		T_LOG("%s %s %lu", ifba->ifba_ifsname, ntoabuf,
2632*4f1223e8SApple OSS Distributions 		    ifba->ifba_expire);
2633*4f1223e8SApple OSS Distributions 	}
2634*4f1223e8SApple OSS Distributions 	return;
2635*4f1223e8SApple OSS Distributions }
2636*4f1223e8SApple OSS Distributions 
2637*4f1223e8SApple OSS Distributions static struct ifbrmne *
bridge_mac_nat_entries_copy_common(const char * bridge,u_int * ret_count)2638*4f1223e8SApple OSS Distributions bridge_mac_nat_entries_copy_common(const char * bridge, u_int * ret_count)
2639*4f1223e8SApple OSS Distributions {
2640*4f1223e8SApple OSS Distributions 	char *                  buf = NULL;
2641*4f1223e8SApple OSS Distributions 	u_int                   count = 0;
2642*4f1223e8SApple OSS Distributions 	int                     err;
2643*4f1223e8SApple OSS Distributions 	u_int                   i;
2644*4f1223e8SApple OSS Distributions 	struct ifbrmnelist      mnl;
2645*4f1223e8SApple OSS Distributions 	struct ifbrmne *        ret_list = NULL;
2646*4f1223e8SApple OSS Distributions 	char *                  scan;
2647*4f1223e8SApple OSS Distributions 
2648*4f1223e8SApple OSS Distributions 	/* find out how many there are */
2649*4f1223e8SApple OSS Distributions 	bzero(&mnl, sizeof(mnl));
2650*4f1223e8SApple OSS Distributions 	err = siocdrvspec(bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
2651*4f1223e8SApple OSS Distributions 	if (err != 0 && S_cleaning_up) {
2652*4f1223e8SApple OSS Distributions 		T_LOG("BRDGGMACNATLIST %s failed %d", bridge, errno);
2653*4f1223e8SApple OSS Distributions 		goto done;
2654*4f1223e8SApple OSS Distributions 	}
2655*4f1223e8SApple OSS Distributions 	T_QUIET;
2656*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
2657*4f1223e8SApple OSS Distributions 	T_QUIET;
2658*4f1223e8SApple OSS Distributions 	T_ASSERT_GE(mnl.ifbml_elsize, (uint16_t)sizeof(struct ifbrmne),
2659*4f1223e8SApple OSS Distributions 	    "mac nat entry size %u minsize %u",
2660*4f1223e8SApple OSS Distributions 	    mnl.ifbml_elsize, (u_int)sizeof(struct ifbrmne));
2661*4f1223e8SApple OSS Distributions 	if (mnl.ifbml_len == 0) {
2662*4f1223e8SApple OSS Distributions 		goto done;
2663*4f1223e8SApple OSS Distributions 	}
2664*4f1223e8SApple OSS Distributions 
2665*4f1223e8SApple OSS Distributions 	/* call again with a buffer large enough to hold them */
2666*4f1223e8SApple OSS Distributions 	buf = malloc(mnl.ifbml_len);
2667*4f1223e8SApple OSS Distributions 	T_QUIET;
2668*4f1223e8SApple OSS Distributions 	T_ASSERT_NOTNULL(buf, "mac nat entries buffer");
2669*4f1223e8SApple OSS Distributions 	mnl.ifbml_buf = buf;
2670*4f1223e8SApple OSS Distributions 	err = siocdrvspec(bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
2671*4f1223e8SApple OSS Distributions 	T_QUIET;
2672*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
2673*4f1223e8SApple OSS Distributions 	count = mnl.ifbml_len / mnl.ifbml_elsize;
2674*4f1223e8SApple OSS Distributions 	if (count == 0) {
2675*4f1223e8SApple OSS Distributions 		goto done;
2676*4f1223e8SApple OSS Distributions 	}
2677*4f1223e8SApple OSS Distributions 	if (mnl.ifbml_elsize == sizeof(struct ifbrmne)) {
2678*4f1223e8SApple OSS Distributions 		/* element size is expected size, no need to "right-size" it */
2679*4f1223e8SApple OSS Distributions 		ret_list = (struct ifbrmne *)(void *)buf;
2680*4f1223e8SApple OSS Distributions 		buf = NULL;
2681*4f1223e8SApple OSS Distributions 		goto done;
2682*4f1223e8SApple OSS Distributions 	}
2683*4f1223e8SApple OSS Distributions 	/* element size is larger than we expect, create a "right-sized" array */
2684*4f1223e8SApple OSS Distributions 	ret_list = malloc(count * sizeof(*ret_list));
2685*4f1223e8SApple OSS Distributions 	T_QUIET;
2686*4f1223e8SApple OSS Distributions 	T_ASSERT_NOTNULL(ret_list, "mac nat entries list");
2687*4f1223e8SApple OSS Distributions 	for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) {
2688*4f1223e8SApple OSS Distributions 		struct ifbrmne *        ifbmne;
2689*4f1223e8SApple OSS Distributions 
2690*4f1223e8SApple OSS Distributions 		ifbmne = (struct ifbrmne *)(void *)scan;
2691*4f1223e8SApple OSS Distributions 		ret_list[i] = *ifbmne;
2692*4f1223e8SApple OSS Distributions 	}
2693*4f1223e8SApple OSS Distributions done:
2694*4f1223e8SApple OSS Distributions 	if (buf != NULL) {
2695*4f1223e8SApple OSS Distributions 		free(buf);
2696*4f1223e8SApple OSS Distributions 	}
2697*4f1223e8SApple OSS Distributions 	*ret_count = count;
2698*4f1223e8SApple OSS Distributions 	return ret_list;
2699*4f1223e8SApple OSS Distributions }
2700*4f1223e8SApple OSS Distributions 
2701*4f1223e8SApple OSS Distributions static struct ifbrmne *
bridge_mac_nat_entries_copy(u_int * ret_count)2702*4f1223e8SApple OSS Distributions bridge_mac_nat_entries_copy(u_int * ret_count)
2703*4f1223e8SApple OSS Distributions {
2704*4f1223e8SApple OSS Distributions 	return bridge_mac_nat_entries_copy_common(BRIDGE200, ret_count);
2705*4f1223e8SApple OSS Distributions }
2706*4f1223e8SApple OSS Distributions 
2707*4f1223e8SApple OSS Distributions static void
bridge_mac_nat_entries_log(struct ifbrmne * entries,u_int count)2708*4f1223e8SApple OSS Distributions bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count)
2709*4f1223e8SApple OSS Distributions {
2710*4f1223e8SApple OSS Distributions 	u_int                   i;
2711*4f1223e8SApple OSS Distributions 	char                    ntoabuf[ETHER_NTOA_BUFSIZE];
2712*4f1223e8SApple OSS Distributions 	char                    ntopbuf[INET6_ADDRSTRLEN];
2713*4f1223e8SApple OSS Distributions 	struct ifbrmne *        scan;
2714*4f1223e8SApple OSS Distributions 
2715*4f1223e8SApple OSS Distributions 	for (i = 0, scan = entries; i < count; i++, scan++) {
2716*4f1223e8SApple OSS Distributions 		ether_ntoa_buf((const ether_addr_t *)&scan->ifbmne_mac,
2717*4f1223e8SApple OSS Distributions 		    ntoabuf, sizeof(ntoabuf));
2718*4f1223e8SApple OSS Distributions 		inet_ntop(scan->ifbmne_af, &scan->ifbmne_ip,
2719*4f1223e8SApple OSS Distributions 		    ntopbuf, sizeof(ntopbuf));
2720*4f1223e8SApple OSS Distributions 		printf("%s %s %s %lu\n",
2721*4f1223e8SApple OSS Distributions 		    scan->ifbmne_ifname, ntopbuf, ntoabuf,
2722*4f1223e8SApple OSS Distributions 		    (unsigned long)scan->ifbmne_expire);
2723*4f1223e8SApple OSS Distributions 	}
2724*4f1223e8SApple OSS Distributions 	return;
2725*4f1223e8SApple OSS Distributions }
2726*4f1223e8SApple OSS Distributions 
2727*4f1223e8SApple OSS Distributions /**
2728*4f1223e8SApple OSS Distributions ** Test Main
2729*4f1223e8SApple OSS Distributions **/
2730*4f1223e8SApple OSS Distributions static u_int                    S_n_ports;
2731*4f1223e8SApple OSS Distributions static switch_port_list_t       S_port_list;
2732*4f1223e8SApple OSS Distributions 
2733*4f1223e8SApple OSS Distributions static void
2734*4f1223e8SApple OSS Distributions bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error);
2735*4f1223e8SApple OSS Distributions 
2736*4f1223e8SApple OSS Distributions static int fake_bsd_mode;
2737*4f1223e8SApple OSS Distributions static int fake_fcs;
2738*4f1223e8SApple OSS Distributions static int fake_trailer_length;
2739*4f1223e8SApple OSS Distributions 
2740*4f1223e8SApple OSS Distributions static void
fake_set_trailers_fcs(bool enable)2741*4f1223e8SApple OSS Distributions fake_set_trailers_fcs(bool enable)
2742*4f1223e8SApple OSS Distributions {
2743*4f1223e8SApple OSS Distributions 	int     error;
2744*4f1223e8SApple OSS Distributions 	int     fcs;
2745*4f1223e8SApple OSS Distributions 	size_t  len;
2746*4f1223e8SApple OSS Distributions 	int     trailer_length;
2747*4f1223e8SApple OSS Distributions 
2748*4f1223e8SApple OSS Distributions 	if (enable) {
2749*4f1223e8SApple OSS Distributions 		fcs = 1;
2750*4f1223e8SApple OSS Distributions 		trailer_length = 28;
2751*4f1223e8SApple OSS Distributions 	} else {
2752*4f1223e8SApple OSS Distributions 		fcs = 0;
2753*4f1223e8SApple OSS Distributions 		trailer_length = 0;
2754*4f1223e8SApple OSS Distributions 	}
2755*4f1223e8SApple OSS Distributions 
2756*4f1223e8SApple OSS Distributions 	/* set fcs */
2757*4f1223e8SApple OSS Distributions 	len = sizeof(fake_fcs);
2758*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.fcs",
2759*4f1223e8SApple OSS Distributions 	    &fake_fcs, &len,
2760*4f1223e8SApple OSS Distributions 	    &fcs, sizeof(fcs));
2761*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(error, 0, "sysctl net.link.fake.fcs %d", fcs);
2762*4f1223e8SApple OSS Distributions 
2763*4f1223e8SApple OSS Distributions 	/* set trailer_length */
2764*4f1223e8SApple OSS Distributions 	len = sizeof(fake_trailer_length);
2765*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.trailer_length",
2766*4f1223e8SApple OSS Distributions 	    &fake_trailer_length, &len,
2767*4f1223e8SApple OSS Distributions 	    &trailer_length, sizeof(trailer_length));
2768*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(error, 0, "sysctl net.link.fake.trailer_length %d",
2769*4f1223e8SApple OSS Distributions 	    trailer_length);
2770*4f1223e8SApple OSS Distributions }
2771*4f1223e8SApple OSS Distributions 
2772*4f1223e8SApple OSS Distributions static void
fake_restore_trailers_fcs(void)2773*4f1223e8SApple OSS Distributions fake_restore_trailers_fcs(void)
2774*4f1223e8SApple OSS Distributions {
2775*4f1223e8SApple OSS Distributions 	int     error;
2776*4f1223e8SApple OSS Distributions 
2777*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.fcs",
2778*4f1223e8SApple OSS Distributions 	    NULL, 0, &fake_fcs, sizeof(fake_fcs));
2779*4f1223e8SApple OSS Distributions 	T_LOG("sysctl net.link.fake.fcs=%d returned %d", fake_fcs, error);
2780*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.trailer_length",
2781*4f1223e8SApple OSS Distributions 	    NULL, 0, &fake_trailer_length, sizeof(fake_trailer_length));
2782*4f1223e8SApple OSS Distributions 	T_LOG("sysctl net.link.fake.trailer_length=%d returned %d",
2783*4f1223e8SApple OSS Distributions 	    fake_trailer_length, error);
2784*4f1223e8SApple OSS Distributions }
2785*4f1223e8SApple OSS Distributions 
2786*4f1223e8SApple OSS Distributions static void
fake_set_bsd_mode(bool enable)2787*4f1223e8SApple OSS Distributions fake_set_bsd_mode(bool enable)
2788*4f1223e8SApple OSS Distributions {
2789*4f1223e8SApple OSS Distributions 	int     error;
2790*4f1223e8SApple OSS Distributions 	int     bsd_mode;
2791*4f1223e8SApple OSS Distributions 	size_t  len;
2792*4f1223e8SApple OSS Distributions 
2793*4f1223e8SApple OSS Distributions 	bsd_mode = (enable) ? 1 : 0;
2794*4f1223e8SApple OSS Distributions 	len = sizeof(fake_bsd_mode);
2795*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.bsd_mode",
2796*4f1223e8SApple OSS Distributions 	    &fake_bsd_mode, &len,
2797*4f1223e8SApple OSS Distributions 	    &bsd_mode, sizeof(bsd_mode));
2798*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(error, 0, "sysctl net.link.fake.bsd_mode %d", bsd_mode);
2799*4f1223e8SApple OSS Distributions }
2800*4f1223e8SApple OSS Distributions 
2801*4f1223e8SApple OSS Distributions static void
fake_restore_bsd_mode(void)2802*4f1223e8SApple OSS Distributions fake_restore_bsd_mode(void)
2803*4f1223e8SApple OSS Distributions {
2804*4f1223e8SApple OSS Distributions 	int     error;
2805*4f1223e8SApple OSS Distributions 
2806*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.bsd_mode",
2807*4f1223e8SApple OSS Distributions 	    NULL, 0, &fake_bsd_mode, sizeof(fake_bsd_mode));
2808*4f1223e8SApple OSS Distributions 	T_LOG("sysctl net.link.fake.bsd_mode=%d returned %d",
2809*4f1223e8SApple OSS Distributions 	    fake_bsd_mode, error);
2810*4f1223e8SApple OSS Distributions }
2811*4f1223e8SApple OSS Distributions 
2812*4f1223e8SApple OSS Distributions static void
fake_set_lro(bool enable)2813*4f1223e8SApple OSS Distributions fake_set_lro(bool enable)
2814*4f1223e8SApple OSS Distributions {
2815*4f1223e8SApple OSS Distributions 	int     error;
2816*4f1223e8SApple OSS Distributions 	int     lro;
2817*4f1223e8SApple OSS Distributions 	size_t  len;
2818*4f1223e8SApple OSS Distributions 
2819*4f1223e8SApple OSS Distributions 	lro = (enable) ? 1 : 0;
2820*4f1223e8SApple OSS Distributions 	len = sizeof(fake_bsd_mode);
2821*4f1223e8SApple OSS Distributions 	error = sysctlbyname("net.link.fake.lro", NULL, 0,
2822*4f1223e8SApple OSS Distributions 	    &lro, sizeof(lro));
2823*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(error, 0, "sysctl net.link.fake.lro %d", lro);
2824*4f1223e8SApple OSS Distributions }
2825*4f1223e8SApple OSS Distributions 
2826*4f1223e8SApple OSS Distributions static void
cleanup_common(bool dump_table)2827*4f1223e8SApple OSS Distributions cleanup_common(bool dump_table)
2828*4f1223e8SApple OSS Distributions {
2829*4f1223e8SApple OSS Distributions 	if (S_n_ports == 0) {
2830*4f1223e8SApple OSS Distributions 		return;
2831*4f1223e8SApple OSS Distributions 	}
2832*4f1223e8SApple OSS Distributions 	S_cleaning_up = true;
2833*4f1223e8SApple OSS Distributions 	if (S_port_list != NULL &&
2834*4f1223e8SApple OSS Distributions 	    (S_port_list->mac_nat || dump_table)) {
2835*4f1223e8SApple OSS Distributions 		switch_port_list_log(S_port_list);
2836*4f1223e8SApple OSS Distributions 		if (S_port_list->mac_nat) {
2837*4f1223e8SApple OSS Distributions 			switch_port_list_verify_mac_nat(S_port_list, true);
2838*4f1223e8SApple OSS Distributions 		}
2839*4f1223e8SApple OSS Distributions 		(void)switch_port_list_verify_rt_table(S_port_list, true);
2840*4f1223e8SApple OSS Distributions 	}
2841*4f1223e8SApple OSS Distributions 	if (G_debug) {
2842*4f1223e8SApple OSS Distributions 		T_LOG("sleeping for 5 seconds\n");
2843*4f1223e8SApple OSS Distributions 		sleep(5);
2844*4f1223e8SApple OSS Distributions 	}
2845*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, S_n_ports, false);
2846*4f1223e8SApple OSS Distributions 	return;
2847*4f1223e8SApple OSS Distributions }
2848*4f1223e8SApple OSS Distributions 
2849*4f1223e8SApple OSS Distributions static void
cleanup(void)2850*4f1223e8SApple OSS Distributions cleanup(void)
2851*4f1223e8SApple OSS Distributions {
2852*4f1223e8SApple OSS Distributions 	cleanup_common(true);
2853*4f1223e8SApple OSS Distributions 	return;
2854*4f1223e8SApple OSS Distributions }
2855*4f1223e8SApple OSS Distributions 
2856*4f1223e8SApple OSS Distributions static void
sigint_handler(__unused int sig)2857*4f1223e8SApple OSS Distributions sigint_handler(__unused int sig)
2858*4f1223e8SApple OSS Distributions {
2859*4f1223e8SApple OSS Distributions 	cleanup_common(false);
2860*4f1223e8SApple OSS Distributions 	signal(SIGINT, SIG_DFL);
2861*4f1223e8SApple OSS Distributions }
2862*4f1223e8SApple OSS Distributions 
2863*4f1223e8SApple OSS Distributions static switch_port_list_t
bridge_setup(char * bridge,u_int n_ports,u_int num_addrs,uint8_t setup_flags)2864*4f1223e8SApple OSS Distributions bridge_setup(char * bridge, u_int n_ports, u_int num_addrs,
2865*4f1223e8SApple OSS Distributions     uint8_t setup_flags)
2866*4f1223e8SApple OSS Distributions {
2867*4f1223e8SApple OSS Distributions 	u_int                   addr_index = 1;
2868*4f1223e8SApple OSS Distributions 	bool                    attach_stack;
2869*4f1223e8SApple OSS Distributions 	ether_addr_t            bridge_mac;
2870*4f1223e8SApple OSS Distributions 	bool                    checksum_offload;
2871*4f1223e8SApple OSS Distributions 	errno_t                 err;
2872*4f1223e8SApple OSS Distributions 	struct in_addr          ip;
2873*4f1223e8SApple OSS Distributions 	switch_port_list_t      list = NULL;
2874*4f1223e8SApple OSS Distributions 	bool                    mac_nat;
2875*4f1223e8SApple OSS Distributions 	bool                    share_member_mac = false;
2876*4f1223e8SApple OSS Distributions 	uint8_t                 trailers;
2877*4f1223e8SApple OSS Distributions 
2878*4f1223e8SApple OSS Distributions 	attach_stack = (setup_flags & SETUP_FLAGS_ATTACH_STACK) != 0;
2879*4f1223e8SApple OSS Distributions 	checksum_offload = (setup_flags & SETUP_FLAGS_CHECKSUM_OFFLOAD) != 0;
2880*4f1223e8SApple OSS Distributions 	mac_nat = (setup_flags & SETUP_FLAGS_MAC_NAT) != 0;
2881*4f1223e8SApple OSS Distributions 	trailers = (setup_flags & SETUP_FLAGS_TRAILERS) != 0;
2882*4f1223e8SApple OSS Distributions 	share_member_mac = (setup_flags & SETUP_FLAGS_SHARE_MEMBER_MAC) != 0;
2883*4f1223e8SApple OSS Distributions 
2884*4f1223e8SApple OSS Distributions 	S_n_ports = n_ports;
2885*4f1223e8SApple OSS Distributions 	T_ATEND(cleanup);
2886*4f1223e8SApple OSS Distributions 	T_SETUPBEGIN;
2887*4f1223e8SApple OSS Distributions 	err = ifnet_create(bridge);
2888*4f1223e8SApple OSS Distributions 	if (err != 0) {
2889*4f1223e8SApple OSS Distributions 		goto done;
2890*4f1223e8SApple OSS Distributions 	}
2891*4f1223e8SApple OSS Distributions 	ifnet_get_lladdr(bridge, &bridge_mac);
2892*4f1223e8SApple OSS Distributions 	bridge_if_index = (u_short)if_nametoindex(bridge);
2893*4f1223e8SApple OSS Distributions 	if (attach_stack) {
2894*4f1223e8SApple OSS Distributions 		char            ntopbuf_ip[INET6_ADDRSTRLEN];
2895*4f1223e8SApple OSS Distributions 
2896*4f1223e8SApple OSS Distributions 		/* bridge gets .1 */
2897*4f1223e8SApple OSS Distributions 		get_ipv4_address(0, addr_index, &bridge_ip_addr);
2898*4f1223e8SApple OSS Distributions 		addr_index++;
2899*4f1223e8SApple OSS Distributions 		ifnet_add_ip_address(bridge, bridge_ip_addr,
2900*4f1223e8SApple OSS Distributions 		    inet_class_c_subnet_mask);
2901*4f1223e8SApple OSS Distributions 		ifnet_start_ipv6(bridge);
2902*4f1223e8SApple OSS Distributions 		get_ipv6_ll_address(&bridge_mac, &bridge_ipv6_addr);
2903*4f1223e8SApple OSS Distributions 		inet_ntop(AF_INET6, &bridge_ipv6_addr, ntopbuf_ip,
2904*4f1223e8SApple OSS Distributions 		    sizeof(ntopbuf_ip));
2905*4f1223e8SApple OSS Distributions 		T_LOG("%s %s", bridge, ntopbuf_ip);
2906*4f1223e8SApple OSS Distributions 	}
2907*4f1223e8SApple OSS Distributions 	list = switch_port_list_alloc(n_ports, mac_nat);
2908*4f1223e8SApple OSS Distributions 	fake_set_bsd_mode(true);
2909*4f1223e8SApple OSS Distributions 	fake_set_trailers_fcs(trailers);
2910*4f1223e8SApple OSS Distributions 	for (u_int i = 0; i < n_ports; i++) {
2911*4f1223e8SApple OSS Distributions 		bool    do_mac_nat;
2912*4f1223e8SApple OSS Distributions 		char    ifname[IFNAMSIZ];
2913*4f1223e8SApple OSS Distributions 		u_short if_index = 0;
2914*4f1223e8SApple OSS Distributions 		char    member_ifname[IFNAMSIZ];
2915*4f1223e8SApple OSS Distributions 
2916*4f1223e8SApple OSS Distributions 		snprintf(ifname, sizeof(ifname), "%s%d",
2917*4f1223e8SApple OSS Distributions 		    FETH_NAME, i);
2918*4f1223e8SApple OSS Distributions 		snprintf(member_ifname, sizeof(member_ifname), "%s%d",
2919*4f1223e8SApple OSS Distributions 		    FETH_NAME, i + n_ports);
2920*4f1223e8SApple OSS Distributions 		err = ifnet_create(ifname);
2921*4f1223e8SApple OSS Distributions 		if (err != 0) {
2922*4f1223e8SApple OSS Distributions 			goto done;
2923*4f1223e8SApple OSS Distributions 		}
2924*4f1223e8SApple OSS Distributions 		ifnet_attach_ip(ifname);
2925*4f1223e8SApple OSS Distributions 		err = ifnet_create(member_ifname);
2926*4f1223e8SApple OSS Distributions 		if (err != 0) {
2927*4f1223e8SApple OSS Distributions 			goto done;
2928*4f1223e8SApple OSS Distributions 		}
2929*4f1223e8SApple OSS Distributions 		if (i == 0 && share_member_mac) {
2930*4f1223e8SApple OSS Distributions 			err = ifnet_set_lladdr(member_ifname, &bridge_mac);
2931*4f1223e8SApple OSS Distributions 			if (err != 0) {
2932*4f1223e8SApple OSS Distributions 				goto done;
2933*4f1223e8SApple OSS Distributions 			}
2934*4f1223e8SApple OSS Distributions 		}
2935*4f1223e8SApple OSS Distributions 		fake_set_peer(ifname, member_ifname);
2936*4f1223e8SApple OSS Distributions 		if (attach_stack) {
2937*4f1223e8SApple OSS Distributions 			/* members get .2, .3, etc. */
2938*4f1223e8SApple OSS Distributions 			if_index = (u_short)if_nametoindex(ifname);
2939*4f1223e8SApple OSS Distributions 			get_ipv4_address(0, addr_index, &ip);
2940*4f1223e8SApple OSS Distributions 			ifnet_add_ip_address(ifname, ip,
2941*4f1223e8SApple OSS Distributions 			    inet_class_c_subnet_mask);
2942*4f1223e8SApple OSS Distributions 			route_add_inet_scoped_subnet(ifname, if_index,
2943*4f1223e8SApple OSS Distributions 			    ip, inet_class_c_subnet_mask);
2944*4f1223e8SApple OSS Distributions 			addr_index++;
2945*4f1223e8SApple OSS Distributions 			ifnet_start_ipv6(ifname);
2946*4f1223e8SApple OSS Distributions 		}
2947*4f1223e8SApple OSS Distributions 		/* add the interface's peer to the bridge */
2948*4f1223e8SApple OSS Distributions 		err = bridge_add_member(bridge, member_ifname);
2949*4f1223e8SApple OSS Distributions 		if (err != 0) {
2950*4f1223e8SApple OSS Distributions 			goto done;
2951*4f1223e8SApple OSS Distributions 		}
2952*4f1223e8SApple OSS Distributions 
2953*4f1223e8SApple OSS Distributions 		do_mac_nat = (i == 0 && mac_nat);
2954*4f1223e8SApple OSS Distributions 		if (do_mac_nat) {
2955*4f1223e8SApple OSS Distributions 			/* enable MAC NAT on unit 0 */
2956*4f1223e8SApple OSS Distributions 			err = bridge_member_modify_mac_nat(bridge,
2957*4f1223e8SApple OSS Distributions 			    member_ifname,
2958*4f1223e8SApple OSS Distributions 			    true);
2959*4f1223e8SApple OSS Distributions 			if (err != 0) {
2960*4f1223e8SApple OSS Distributions 				goto done;
2961*4f1223e8SApple OSS Distributions 			}
2962*4f1223e8SApple OSS Distributions 		} else if (checksum_offload) {
2963*4f1223e8SApple OSS Distributions 			err = bridge_member_modify_checksum_offload(bridge,
2964*4f1223e8SApple OSS Distributions 			    member_ifname,
2965*4f1223e8SApple OSS Distributions 			    true);
2966*4f1223e8SApple OSS Distributions 			if (err != 0) {
2967*4f1223e8SApple OSS Distributions 				goto done;
2968*4f1223e8SApple OSS Distributions 			}
2969*4f1223e8SApple OSS Distributions 		}
2970*4f1223e8SApple OSS Distributions 		/* we'll send/receive on the interface */
2971*4f1223e8SApple OSS Distributions 		err = switch_port_list_add_port(list, i, ifname, if_index,
2972*4f1223e8SApple OSS Distributions 		    member_ifname, num_addrs, do_mac_nat, &ip);
2973*4f1223e8SApple OSS Distributions 		if (err != 0) {
2974*4f1223e8SApple OSS Distributions 			goto done;
2975*4f1223e8SApple OSS Distributions 		}
2976*4f1223e8SApple OSS Distributions 	}
2977*4f1223e8SApple OSS Distributions done:
2978*4f1223e8SApple OSS Distributions 	if (err != 0 && list != NULL) {
2979*4f1223e8SApple OSS Distributions 		switch_port_list_dealloc(list);
2980*4f1223e8SApple OSS Distributions 		list = NULL;
2981*4f1223e8SApple OSS Distributions 	}
2982*4f1223e8SApple OSS Distributions 	T_SETUPEND;
2983*4f1223e8SApple OSS Distributions 	return list;
2984*4f1223e8SApple OSS Distributions }
2985*4f1223e8SApple OSS Distributions 
2986*4f1223e8SApple OSS Distributions static void
bridge_cleanup(const char * bridge,u_int n_ports,bool fail_on_error)2987*4f1223e8SApple OSS Distributions bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error)
2988*4f1223e8SApple OSS Distributions {
2989*4f1223e8SApple OSS Distributions 	ifnet_destroy(bridge, fail_on_error);
2990*4f1223e8SApple OSS Distributions 	for (u_int i = 0; i < n_ports; i++) {
2991*4f1223e8SApple OSS Distributions 		char    ifname[IFNAMSIZ];
2992*4f1223e8SApple OSS Distributions 		char    member_ifname[IFNAMSIZ];
2993*4f1223e8SApple OSS Distributions 
2994*4f1223e8SApple OSS Distributions 		snprintf(ifname, sizeof(ifname), "%s%d",
2995*4f1223e8SApple OSS Distributions 		    FETH_NAME, i);
2996*4f1223e8SApple OSS Distributions 		snprintf(member_ifname, sizeof(member_ifname), "%s%d",
2997*4f1223e8SApple OSS Distributions 		    FETH_NAME, i + n_ports);
2998*4f1223e8SApple OSS Distributions 		ifnet_destroy(ifname, fail_on_error);
2999*4f1223e8SApple OSS Distributions 		ifnet_destroy(member_ifname, fail_on_error);
3000*4f1223e8SApple OSS Distributions 	}
3001*4f1223e8SApple OSS Distributions 	S_n_ports = 0;
3002*4f1223e8SApple OSS Distributions 	fake_restore_trailers_fcs();
3003*4f1223e8SApple OSS Distributions 	fake_restore_bsd_mode();
3004*4f1223e8SApple OSS Distributions 	return;
3005*4f1223e8SApple OSS Distributions }
3006*4f1223e8SApple OSS Distributions 
3007*4f1223e8SApple OSS Distributions /*
3008*4f1223e8SApple OSS Distributions  *  Basic Bridge Tests
3009*4f1223e8SApple OSS Distributions  *
3010*4f1223e8SApple OSS Distributions  *  Broadcast
3011*4f1223e8SApple OSS Distributions  *  - two cases: actual broadcast, unknown ethernet
3012*4f1223e8SApple OSS Distributions  *  - send broadcast packets
3013*4f1223e8SApple OSS Distributions  *  - verify all received
3014*4f1223e8SApple OSS Distributions  *  - check bridge rt list contains all expected MAC addresses
3015*4f1223e8SApple OSS Distributions  *  - send unicast ARP packets
3016*4f1223e8SApple OSS Distributions  *  - verify packets received only on expected port
3017*4f1223e8SApple OSS Distributions  *
3018*4f1223e8SApple OSS Distributions  *  MAC-NAT
3019*4f1223e8SApple OSS Distributions  *  - verify ARP translation
3020*4f1223e8SApple OSS Distributions  *  - verify IPv4 translation
3021*4f1223e8SApple OSS Distributions  *  - verify DHCP broadcast bit conversion
3022*4f1223e8SApple OSS Distributions  *  - verify IPv6 translation
3023*4f1223e8SApple OSS Distributions  *  - verify ND6 translation (Neighbor, Router)
3024*4f1223e8SApple OSS Distributions  *  - verify IPv4 subnet-local broadcast to MAC-NAT interface link-layer
3025*4f1223e8SApple OSS Distributions  *    address arrives on all member links
3026*4f1223e8SApple OSS Distributions  */
3027*4f1223e8SApple OSS Distributions 
3028*4f1223e8SApple OSS Distributions static void
bridge_test(packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr,uint8_t af,u_int n_ports,u_int num_addrs)3029*4f1223e8SApple OSS Distributions bridge_test(packet_validator_t validator,
3030*4f1223e8SApple OSS Distributions     void * context,
3031*4f1223e8SApple OSS Distributions     const ether_addr_t * dst_eaddr,
3032*4f1223e8SApple OSS Distributions     uint8_t af, u_int n_ports, u_int num_addrs)
3033*4f1223e8SApple OSS Distributions {
3034*4f1223e8SApple OSS Distributions #if TARGET_OS_BRIDGE
3035*4f1223e8SApple OSS Distributions 	T_SKIP("Test uses too much memory");
3036*4f1223e8SApple OSS Distributions #else /* TARGET_OS_BRIDGE */
3037*4f1223e8SApple OSS Distributions 	switch_port_list_t port_list;
3038*4f1223e8SApple OSS Distributions 
3039*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_handler);
3040*4f1223e8SApple OSS Distributions 	port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, 0);
3041*4f1223e8SApple OSS Distributions 	if (port_list == NULL) {
3042*4f1223e8SApple OSS Distributions 		T_FAIL("bridge_setup");
3043*4f1223e8SApple OSS Distributions 		return;
3044*4f1223e8SApple OSS Distributions 	}
3045*4f1223e8SApple OSS Distributions 	S_port_list = port_list;
3046*4f1223e8SApple OSS Distributions 	bridge_learning_test(port_list, af, validator, context, dst_eaddr);
3047*4f1223e8SApple OSS Distributions 
3048*4f1223e8SApple OSS Distributions 	//T_LOG("Sleeping for 5 seconds");
3049*4f1223e8SApple OSS Distributions 	//sleep(5);
3050*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, n_ports, true);
3051*4f1223e8SApple OSS Distributions 	switch_port_list_dealloc(port_list);
3052*4f1223e8SApple OSS Distributions 	return;
3053*4f1223e8SApple OSS Distributions #endif /* TARGET_OS_BRIDGE */
3054*4f1223e8SApple OSS Distributions }
3055*4f1223e8SApple OSS Distributions 
3056*4f1223e8SApple OSS Distributions static void
bridge_test_mac_nat_ipv4(u_int n_ports,u_int num_addrs)3057*4f1223e8SApple OSS Distributions bridge_test_mac_nat_ipv4(u_int n_ports, u_int num_addrs)
3058*4f1223e8SApple OSS Distributions {
3059*4f1223e8SApple OSS Distributions #if TARGET_OS_BRIDGE
3060*4f1223e8SApple OSS Distributions 	T_SKIP("Test uses too much memory");
3061*4f1223e8SApple OSS Distributions #else /* TARGET_OS_BRIDGE */
3062*4f1223e8SApple OSS Distributions 	switch_port_list_t port_list;
3063*4f1223e8SApple OSS Distributions 
3064*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_handler);
3065*4f1223e8SApple OSS Distributions 	port_list = bridge_setup(BRIDGE200, n_ports, num_addrs,
3066*4f1223e8SApple OSS Distributions 	    SETUP_FLAGS_MAC_NAT);
3067*4f1223e8SApple OSS Distributions 	if (port_list == NULL) {
3068*4f1223e8SApple OSS Distributions 		T_FAIL("bridge_setup");
3069*4f1223e8SApple OSS Distributions 		return;
3070*4f1223e8SApple OSS Distributions 	}
3071*4f1223e8SApple OSS Distributions 	S_port_list = port_list;
3072*4f1223e8SApple OSS Distributions 
3073*4f1223e8SApple OSS Distributions 	/* verify that IPv4 packets get translated when necessary */
3074*4f1223e8SApple OSS Distributions 	mac_nat_test_ip(port_list, AF_INET);
3075*4f1223e8SApple OSS Distributions 
3076*4f1223e8SApple OSS Distributions 	/* verify the DHCP broadcast bit gets set appropriately */
3077*4f1223e8SApple OSS Distributions 	mac_nat_test_dhcp(port_list, false);
3078*4f1223e8SApple OSS Distributions 
3079*4f1223e8SApple OSS Distributions 	/* verify that ARP packet gets translated when necessary */
3080*4f1223e8SApple OSS Distributions 	mac_nat_test_arp_out(port_list);
3081*4f1223e8SApple OSS Distributions 	mac_nat_test_arp_in(port_list);
3082*4f1223e8SApple OSS Distributions 
3083*4f1223e8SApple OSS Distributions 	/* verify IP broadcast to MAC-NAT interface link layer address */
3084*4f1223e8SApple OSS Distributions 	mac_nat_test_dhcp(port_list, true);
3085*4f1223e8SApple OSS Distributions 
3086*4f1223e8SApple OSS Distributions 	if (G_debug) {
3087*4f1223e8SApple OSS Distributions 		T_LOG("Sleeping for 5 seconds");
3088*4f1223e8SApple OSS Distributions 		sleep(5);
3089*4f1223e8SApple OSS Distributions 	}
3090*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, n_ports, true);
3091*4f1223e8SApple OSS Distributions 	switch_port_list_dealloc(port_list);
3092*4f1223e8SApple OSS Distributions 	return;
3093*4f1223e8SApple OSS Distributions #endif /* TARGET_OS_BRIDGE */
3094*4f1223e8SApple OSS Distributions }
3095*4f1223e8SApple OSS Distributions 
3096*4f1223e8SApple OSS Distributions static void
bridge_test_mac_nat_ipv6(u_int n_ports,u_int num_addrs,uint8_t flags)3097*4f1223e8SApple OSS Distributions bridge_test_mac_nat_ipv6(u_int n_ports, u_int num_addrs, uint8_t flags)
3098*4f1223e8SApple OSS Distributions {
3099*4f1223e8SApple OSS Distributions #if TARGET_OS_BRIDGE
3100*4f1223e8SApple OSS Distributions 	T_SKIP("Test uses too much memory");
3101*4f1223e8SApple OSS Distributions #else /* TARGET_OS_BRIDGE */
3102*4f1223e8SApple OSS Distributions 	switch_port_list_t port_list;
3103*4f1223e8SApple OSS Distributions 
3104*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_handler);
3105*4f1223e8SApple OSS Distributions 	flags |= SETUP_FLAGS_MAC_NAT;
3106*4f1223e8SApple OSS Distributions 	port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, flags);
3107*4f1223e8SApple OSS Distributions 	if (port_list == NULL) {
3108*4f1223e8SApple OSS Distributions 		T_FAIL("bridge_setup");
3109*4f1223e8SApple OSS Distributions 		return;
3110*4f1223e8SApple OSS Distributions 	}
3111*4f1223e8SApple OSS Distributions 	S_port_list = port_list;
3112*4f1223e8SApple OSS Distributions 
3113*4f1223e8SApple OSS Distributions 	/* verify that IPv6 packets get translated when necessary */
3114*4f1223e8SApple OSS Distributions 	mac_nat_test_ip(port_list, AF_INET6);
3115*4f1223e8SApple OSS Distributions 
3116*4f1223e8SApple OSS Distributions 	/* verify that ND6 packet gets translated when necessary */
3117*4f1223e8SApple OSS Distributions 	mac_nat_test_nd6_out(port_list);
3118*4f1223e8SApple OSS Distributions 	if (G_debug) {
3119*4f1223e8SApple OSS Distributions 		T_LOG("Sleeping for 5 seconds");
3120*4f1223e8SApple OSS Distributions 		sleep(5);
3121*4f1223e8SApple OSS Distributions 	}
3122*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, n_ports, true);
3123*4f1223e8SApple OSS Distributions 	switch_port_list_dealloc(port_list);
3124*4f1223e8SApple OSS Distributions 	return;
3125*4f1223e8SApple OSS Distributions #endif /* TARGET_OS_BRIDGE */
3126*4f1223e8SApple OSS Distributions }
3127*4f1223e8SApple OSS Distributions 
3128*4f1223e8SApple OSS Distributions /*
3129*4f1223e8SApple OSS Distributions  * Filter test utilities
3130*4f1223e8SApple OSS Distributions  */
3131*4f1223e8SApple OSS Distributions static void
system_cmd(const char * cmd,bool fail_on_error)3132*4f1223e8SApple OSS Distributions system_cmd(const char *cmd, bool fail_on_error)
3133*4f1223e8SApple OSS Distributions {
3134*4f1223e8SApple OSS Distributions 	pid_t pid = -1;
3135*4f1223e8SApple OSS Distributions 	int exit_status = 0;
3136*4f1223e8SApple OSS Distributions 	const char *argv[] = {
3137*4f1223e8SApple OSS Distributions 		"/usr/local/bin/bash",
3138*4f1223e8SApple OSS Distributions 		"-c",
3139*4f1223e8SApple OSS Distributions 		cmd,
3140*4f1223e8SApple OSS Distributions 		NULL
3141*4f1223e8SApple OSS Distributions 	};
3142*4f1223e8SApple OSS Distributions 
3143*4f1223e8SApple OSS Distributions 	int rc = dt_launch_tool(&pid, (char **)(void *)argv, false, NULL, NULL);
3144*4f1223e8SApple OSS Distributions 	T_QUIET;
3145*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(rc, 0, "dt_launch_tool(%s) failed", cmd);
3146*4f1223e8SApple OSS Distributions 
3147*4f1223e8SApple OSS Distributions 	if (dt_waitpid(pid, &exit_status, NULL, 30)) {
3148*4f1223e8SApple OSS Distributions 		T_QUIET;
3149*4f1223e8SApple OSS Distributions 		T_ASSERT_MACH_SUCCESS(exit_status, "command(%s)", cmd);
3150*4f1223e8SApple OSS Distributions 	} else {
3151*4f1223e8SApple OSS Distributions 		if (fail_on_error) {
3152*4f1223e8SApple OSS Distributions 			T_FAIL("dt_waitpid(%s) failed", cmd);
3153*4f1223e8SApple OSS Distributions 		}
3154*4f1223e8SApple OSS Distributions 	}
3155*4f1223e8SApple OSS Distributions }
3156*4f1223e8SApple OSS Distributions 
3157*4f1223e8SApple OSS Distributions static bool
executable_is_present(const char * path)3158*4f1223e8SApple OSS Distributions executable_is_present(const char * path)
3159*4f1223e8SApple OSS Distributions {
3160*4f1223e8SApple OSS Distributions 	struct stat statb = { 0 };
3161*4f1223e8SApple OSS Distributions 
3162*4f1223e8SApple OSS Distributions 	return stat(path, &statb) == 0 && (statb.st_mode & S_IXUSR) != 0;
3163*4f1223e8SApple OSS Distributions }
3164*4f1223e8SApple OSS Distributions 
3165*4f1223e8SApple OSS Distributions static void
cleanup_pf(void)3166*4f1223e8SApple OSS Distributions cleanup_pf(void)
3167*4f1223e8SApple OSS Distributions {
3168*4f1223e8SApple OSS Distributions 	struct ifbrparam param;
3169*4f1223e8SApple OSS Distributions 
3170*4f1223e8SApple OSS Distributions 	system_cmd("pfctl -d", false);
3171*4f1223e8SApple OSS Distributions 	system_cmd("pfctl -F all", false);
3172*4f1223e8SApple OSS Distributions 
3173*4f1223e8SApple OSS Distributions 	param.ifbrp_filter = 0;
3174*4f1223e8SApple OSS Distributions 	siocdrvspec(BRIDGE200, BRDGSFILT,
3175*4f1223e8SApple OSS Distributions 	    &param, sizeof(param), true);
3176*4f1223e8SApple OSS Distributions 	return;
3177*4f1223e8SApple OSS Distributions }
3178*4f1223e8SApple OSS Distributions 
3179*4f1223e8SApple OSS Distributions static void
block_all_traffic(bool input,const char * infname1,const char * infname2)3180*4f1223e8SApple OSS Distributions block_all_traffic(bool input, const char* infname1, const char* infname2)
3181*4f1223e8SApple OSS Distributions {
3182*4f1223e8SApple OSS Distributions 	int ret;
3183*4f1223e8SApple OSS Distributions 	struct ifbrparam param;
3184*4f1223e8SApple OSS Distributions 	char command[512];
3185*4f1223e8SApple OSS Distributions 	char *dir = input ? "in" : "out";
3186*4f1223e8SApple OSS Distributions 
3187*4f1223e8SApple OSS Distributions 	snprintf(command, sizeof(command), "echo \"block %s on %s all\nblock %s on %s all\n\" | pfctl -vvv -f -",
3188*4f1223e8SApple OSS Distributions 	    dir, infname1, dir, infname2);
3189*4f1223e8SApple OSS Distributions 	/* enable block all filter */
3190*4f1223e8SApple OSS Distributions 	param.ifbrp_filter = IFBF_FILT_MEMBER | IFBF_FILT_ONLYIP;
3191*4f1223e8SApple OSS Distributions 	ret = siocdrvspec(BRIDGE200, BRDGSFILT,
3192*4f1223e8SApple OSS Distributions 	    &param, sizeof(param), true);
3193*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret,
3194*4f1223e8SApple OSS Distributions 	    "SIOCDRVSPEC(BRDGSFILT %s, 0x%x)",
3195*4f1223e8SApple OSS Distributions 	    BRIDGE200, param.ifbrp_filter);
3196*4f1223e8SApple OSS Distributions 	// ignore errors such that not having pf.os doesn't raise any issues
3197*4f1223e8SApple OSS Distributions 	system_cmd(command, false);
3198*4f1223e8SApple OSS Distributions 	system_cmd("pfctl -e", true);
3199*4f1223e8SApple OSS Distributions 	system_cmd("pfctl -s all", true);
3200*4f1223e8SApple OSS Distributions }
3201*4f1223e8SApple OSS Distributions 
3202*4f1223e8SApple OSS Distributions /*
3203*4f1223e8SApple OSS Distributions  *  Basic bridge filter test
3204*4f1223e8SApple OSS Distributions  *
3205*4f1223e8SApple OSS Distributions  *  For both broadcast and unicast transfers ensure that data can
3206*4f1223e8SApple OSS Distributions  *  be blocked using pf on the bridge
3207*4f1223e8SApple OSS Distributions  */
3208*4f1223e8SApple OSS Distributions 
3209*4f1223e8SApple OSS Distributions static void
filter_test(uint8_t af)3210*4f1223e8SApple OSS Distributions filter_test(uint8_t af)
3211*4f1223e8SApple OSS Distributions {
3212*4f1223e8SApple OSS Distributions #if TARGET_OS_BRIDGE
3213*4f1223e8SApple OSS Distributions 	T_SKIP("pfctl isn't valid on this platform");
3214*4f1223e8SApple OSS Distributions #else /* TARGET_OS_BRIDGE */
3215*4f1223e8SApple OSS Distributions 	switch_port_list_t port_list;
3216*4f1223e8SApple OSS Distributions 	switch_port_t   port;
3217*4f1223e8SApple OSS Distributions 	const u_int n_ports = 2;
3218*4f1223e8SApple OSS Distributions 	u_int num_addrs = 1;
3219*4f1223e8SApple OSS Distributions 	u_int i;
3220*4f1223e8SApple OSS Distributions 	char ntoabuf[ETHER_NTOA_BUFSIZE];
3221*4f1223e8SApple OSS Distributions 	union ifbrip dst_ip;
3222*4f1223e8SApple OSS Distributions 	bool blocked = true;
3223*4f1223e8SApple OSS Distributions 	bool input = true;
3224*4f1223e8SApple OSS Distributions 	const char* ifnames[2];
3225*4f1223e8SApple OSS Distributions 
3226*4f1223e8SApple OSS Distributions #define PFCTL_PATH      "/sbin/pfctl"
3227*4f1223e8SApple OSS Distributions 	if (!executable_is_present(PFCTL_PATH)) {
3228*4f1223e8SApple OSS Distributions 		T_SKIP("%s not present", PFCTL_PATH);
3229*4f1223e8SApple OSS Distributions 		return;
3230*4f1223e8SApple OSS Distributions 	}
3231*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_handler);
3232*4f1223e8SApple OSS Distributions 
3233*4f1223e8SApple OSS Distributions 	T_ATEND(cleanup);
3234*4f1223e8SApple OSS Distributions 	T_ATEND(cleanup_pf);
3235*4f1223e8SApple OSS Distributions 
3236*4f1223e8SApple OSS Distributions 	port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, 0);
3237*4f1223e8SApple OSS Distributions 	if (port_list == NULL) {
3238*4f1223e8SApple OSS Distributions 		T_FAIL("bridge_setup");
3239*4f1223e8SApple OSS Distributions 		return;
3240*4f1223e8SApple OSS Distributions 	}
3241*4f1223e8SApple OSS Distributions 
3242*4f1223e8SApple OSS Distributions 	ether_ntoa_buf(&ether_broadcast, ntoabuf, sizeof(ntoabuf));
3243*4f1223e8SApple OSS Distributions 
3244*4f1223e8SApple OSS Distributions 	S_port_list = port_list;
3245*4f1223e8SApple OSS Distributions 	for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3246*4f1223e8SApple OSS Distributions 		ifnames[i] = port->member_ifname;
3247*4f1223e8SApple OSS Distributions 	}
3248*4f1223e8SApple OSS Distributions 
3249*4f1223e8SApple OSS Distributions 	get_broadcast_ip_address(af, &dst_ip);
3250*4f1223e8SApple OSS Distributions 	do {
3251*4f1223e8SApple OSS Distributions 		do {
3252*4f1223e8SApple OSS Distributions 			if (blocked) {
3253*4f1223e8SApple OSS Distributions 				block_all_traffic(input, ifnames[0], ifnames[1]);
3254*4f1223e8SApple OSS Distributions 			}
3255*4f1223e8SApple OSS Distributions 			for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3256*4f1223e8SApple OSS Distributions 				if (G_debug) {
3257*4f1223e8SApple OSS Distributions 					T_LOG("Sending on %s", port->ifname);
3258*4f1223e8SApple OSS Distributions 				}
3259*4f1223e8SApple OSS Distributions 				for (u_int j = 0; j < port->num_addrs; j++) {
3260*4f1223e8SApple OSS Distributions 					uint32_t        generation;
3261*4f1223e8SApple OSS Distributions 
3262*4f1223e8SApple OSS Distributions 					generation = next_generation();
3263*4f1223e8SApple OSS Distributions 					send_generation(port,
3264*4f1223e8SApple OSS Distributions 					    af,
3265*4f1223e8SApple OSS Distributions 					    j,
3266*4f1223e8SApple OSS Distributions 					    &ether_broadcast,
3267*4f1223e8SApple OSS Distributions 					    &dst_ip,
3268*4f1223e8SApple OSS Distributions 					    generation);
3269*4f1223e8SApple OSS Distributions 
3270*4f1223e8SApple OSS Distributions 					/* receive across all ports */
3271*4f1223e8SApple OSS Distributions 					check_receive_generation(port_list,
3272*4f1223e8SApple OSS Distributions 					    af,
3273*4f1223e8SApple OSS Distributions 					    generation,
3274*4f1223e8SApple OSS Distributions 					    validate_broadcast_dhost,
3275*4f1223e8SApple OSS Distributions 					    NULL);
3276*4f1223e8SApple OSS Distributions 
3277*4f1223e8SApple OSS Distributions 					/* ensure that every port saw the right amount of packets*/
3278*4f1223e8SApple OSS Distributions 					if (blocked) {
3279*4f1223e8SApple OSS Distributions 						check_received_count(port_list, port, 0);
3280*4f1223e8SApple OSS Distributions 					} else {
3281*4f1223e8SApple OSS Distributions 						check_received_count(port_list, port, 1);
3282*4f1223e8SApple OSS Distributions 					}
3283*4f1223e8SApple OSS Distributions 				}
3284*4f1223e8SApple OSS Distributions 			}
3285*4f1223e8SApple OSS Distributions 			T_PASS("%s broadcast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
3286*4f1223e8SApple OSS Distributions 			input = !input;
3287*4f1223e8SApple OSS Distributions 			cleanup_pf();
3288*4f1223e8SApple OSS Distributions 		} while (input == false && blocked);
3289*4f1223e8SApple OSS Distributions 		blocked = !blocked;
3290*4f1223e8SApple OSS Distributions 	} while (blocked == false);
3291*4f1223e8SApple OSS Distributions 
3292*4f1223e8SApple OSS Distributions 	do {
3293*4f1223e8SApple OSS Distributions 		do {
3294*4f1223e8SApple OSS Distributions 			if (blocked) {
3295*4f1223e8SApple OSS Distributions 				block_all_traffic(input, ifnames[0], ifnames[1]);
3296*4f1223e8SApple OSS Distributions 			}
3297*4f1223e8SApple OSS Distributions 			for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3298*4f1223e8SApple OSS Distributions 				/* send unicast packets to every other port's MAC addresses */
3299*4f1223e8SApple OSS Distributions 				unicast_send_all(port_list, af, port);
3300*4f1223e8SApple OSS Distributions 
3301*4f1223e8SApple OSS Distributions 				/* receive all of that generated traffic */
3302*4f1223e8SApple OSS Distributions 				switch_port_list_check_receive(port_list, af, NULL, 0,
3303*4f1223e8SApple OSS Distributions 				    validate_port_dhost, NULL);
3304*4f1223e8SApple OSS Distributions 
3305*4f1223e8SApple OSS Distributions 				/* ensure that every port saw the right amount of packets*/
3306*4f1223e8SApple OSS Distributions 				if (blocked) {
3307*4f1223e8SApple OSS Distributions 					check_received_count(port_list, port, 0);
3308*4f1223e8SApple OSS Distributions 				} else {
3309*4f1223e8SApple OSS Distributions 					check_received_count(port_list, port, 1);
3310*4f1223e8SApple OSS Distributions 				}
3311*4f1223e8SApple OSS Distributions 			}
3312*4f1223e8SApple OSS Distributions 			T_PASS("%s unicast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
3313*4f1223e8SApple OSS Distributions 			input = !input;
3314*4f1223e8SApple OSS Distributions 			cleanup_pf();
3315*4f1223e8SApple OSS Distributions 		} while (input == false && blocked);
3316*4f1223e8SApple OSS Distributions 		blocked = !blocked;
3317*4f1223e8SApple OSS Distributions 	} while (blocked == false);
3318*4f1223e8SApple OSS Distributions 
3319*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, n_ports, true);
3320*4f1223e8SApple OSS Distributions 	switch_port_list_dealloc(port_list);
3321*4f1223e8SApple OSS Distributions 	return;
3322*4f1223e8SApple OSS Distributions #endif /* TARGET_OS_BRIDGE */
3323*4f1223e8SApple OSS Distributions }
3324*4f1223e8SApple OSS Distributions 
3325*4f1223e8SApple OSS Distributions /*
3326*4f1223e8SApple OSS Distributions  * Bridge checksum offload tests
3327*4f1223e8SApple OSS Distributions  */
3328*4f1223e8SApple OSS Distributions 
3329*4f1223e8SApple OSS Distributions static void
test_traffic_for_af(switch_port_list_t ports,uint8_t af)3330*4f1223e8SApple OSS Distributions test_traffic_for_af(switch_port_list_t ports, uint8_t af)
3331*4f1223e8SApple OSS Distributions {
3332*4f1223e8SApple OSS Distributions 	u_int           i;
3333*4f1223e8SApple OSS Distributions 	inet_address    server;
3334*4f1223e8SApple OSS Distributions 	int             server_if_index;
3335*4f1223e8SApple OSS Distributions 	const char *    server_name;
3336*4f1223e8SApple OSS Distributions 	switch_port_t   server_port;
3337*4f1223e8SApple OSS Distributions 	switch_port_t   port;
3338*4f1223e8SApple OSS Distributions 
3339*4f1223e8SApple OSS Distributions 	/* bridge as server, each peer as client */
3340*4f1223e8SApple OSS Distributions 	server_if_index = bridge_if_index;
3341*4f1223e8SApple OSS Distributions 	server_name = BRIDGE200;
3342*4f1223e8SApple OSS Distributions 	if (af == AF_INET) {
3343*4f1223e8SApple OSS Distributions 		server.v4 = bridge_ip_addr;
3344*4f1223e8SApple OSS Distributions 	} else {
3345*4f1223e8SApple OSS Distributions 		server.v6 = bridge_ipv6_addr;
3346*4f1223e8SApple OSS Distributions 	}
3347*4f1223e8SApple OSS Distributions 	for (i = 0, port = ports->list; i < ports->count; i++, port++) {
3348*4f1223e8SApple OSS Distributions 		inet_test_traffic(af, &server, server_name,
3349*4f1223e8SApple OSS Distributions 		    server_if_index, port->ifname, port->if_index);
3350*4f1223e8SApple OSS Distributions 	}
3351*4f1223e8SApple OSS Distributions 
3352*4f1223e8SApple OSS Distributions 	/* peer 0 as server, other peers as client */
3353*4f1223e8SApple OSS Distributions 	assert(ports->count > 0);
3354*4f1223e8SApple OSS Distributions 	server_port = ports->list;
3355*4f1223e8SApple OSS Distributions 	server_name = server_port->ifname;
3356*4f1223e8SApple OSS Distributions 	server_if_index = server_port->if_index;
3357*4f1223e8SApple OSS Distributions 	if (af == AF_INET) {
3358*4f1223e8SApple OSS Distributions 		server.v4 = server_port->ip;
3359*4f1223e8SApple OSS Distributions 	} else {
3360*4f1223e8SApple OSS Distributions 		server.v6 = server_port->ip6;
3361*4f1223e8SApple OSS Distributions 	}
3362*4f1223e8SApple OSS Distributions 	for (i = 1, port = ports->list + 1; i < ports->count; i++, port++) {
3363*4f1223e8SApple OSS Distributions 		inet_test_traffic(af, &server, server_name,
3364*4f1223e8SApple OSS Distributions 		    server_if_index, port->ifname, port->if_index);
3365*4f1223e8SApple OSS Distributions 	}
3366*4f1223e8SApple OSS Distributions }
3367*4f1223e8SApple OSS Distributions 
3368*4f1223e8SApple OSS Distributions static void
bridge_test_transfer(u_int n_ports,uint8_t setup_flags)3369*4f1223e8SApple OSS Distributions bridge_test_transfer(u_int n_ports, uint8_t setup_flags)
3370*4f1223e8SApple OSS Distributions {
3371*4f1223e8SApple OSS Distributions #if TARGET_OS_BRIDGE
3372*4f1223e8SApple OSS Distributions 	T_SKIP("Test uses too much memory");
3373*4f1223e8SApple OSS Distributions #else /* TARGET_OS_BRIDGE */
3374*4f1223e8SApple OSS Distributions 	switch_port_list_t port_list;
3375*4f1223e8SApple OSS Distributions 
3376*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_handler);
3377*4f1223e8SApple OSS Distributions 	port_list = bridge_setup(BRIDGE200, n_ports, 0,
3378*4f1223e8SApple OSS Distributions 	    SETUP_FLAGS_ATTACH_STACK | setup_flags);
3379*4f1223e8SApple OSS Distributions 	if (port_list == NULL) {
3380*4f1223e8SApple OSS Distributions 		T_FAIL("bridge_setup");
3381*4f1223e8SApple OSS Distributions 		return;
3382*4f1223e8SApple OSS Distributions 	}
3383*4f1223e8SApple OSS Distributions 	test_traffic_for_af(port_list, AF_INET);
3384*4f1223e8SApple OSS Distributions 	test_traffic_for_af(port_list, AF_INET6);
3385*4f1223e8SApple OSS Distributions 	if (G_debug) {
3386*4f1223e8SApple OSS Distributions 		T_LOG("Sleeping for 5 seconds");
3387*4f1223e8SApple OSS Distributions 		sleep(5);
3388*4f1223e8SApple OSS Distributions 	}
3389*4f1223e8SApple OSS Distributions 	bridge_cleanup(BRIDGE200, n_ports, true);
3390*4f1223e8SApple OSS Distributions 	switch_port_list_dealloc(port_list);
3391*4f1223e8SApple OSS Distributions 	return;
3392*4f1223e8SApple OSS Distributions #endif /* TARGET_OS_BRIDGE */
3393*4f1223e8SApple OSS Distributions }
3394*4f1223e8SApple OSS Distributions 
3395*4f1223e8SApple OSS Distributions static void
lro_test_cleanup(void)3396*4f1223e8SApple OSS Distributions lro_test_cleanup(void)
3397*4f1223e8SApple OSS Distributions {
3398*4f1223e8SApple OSS Distributions 	ifnet_destroy(BRIDGE200, false);
3399*4f1223e8SApple OSS Distributions 	ifnet_destroy(FETH0, false);
3400*4f1223e8SApple OSS Distributions 	fake_set_lro(false);
3401*4f1223e8SApple OSS Distributions }
3402*4f1223e8SApple OSS Distributions 
3403*4f1223e8SApple OSS Distributions static void
sigint_lro_cleanup(__unused int sig)3404*4f1223e8SApple OSS Distributions sigint_lro_cleanup(__unused int sig)
3405*4f1223e8SApple OSS Distributions {
3406*4f1223e8SApple OSS Distributions 	signal(SIGINT, SIG_DFL);
3407*4f1223e8SApple OSS Distributions 	lro_test_cleanup();
3408*4f1223e8SApple OSS Distributions }
3409*4f1223e8SApple OSS Distributions 
3410*4f1223e8SApple OSS Distributions static void
verify_lro_capability(const char * if_name,bool expected)3411*4f1223e8SApple OSS Distributions verify_lro_capability(const char * if_name, bool expected)
3412*4f1223e8SApple OSS Distributions {
3413*4f1223e8SApple OSS Distributions 	struct ifreq    ifr;
3414*4f1223e8SApple OSS Distributions 	int             result;
3415*4f1223e8SApple OSS Distributions 	bool            lro_enabled;
3416*4f1223e8SApple OSS Distributions 	int             s = inet_dgram_socket_get();
3417*4f1223e8SApple OSS Distributions 
3418*4f1223e8SApple OSS Distributions 	memset(&ifr, 0, sizeof(ifr));
3419*4f1223e8SApple OSS Distributions 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
3420*4f1223e8SApple OSS Distributions 	result = ioctl(s, SIOCGIFCAP, &ifr);
3421*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(result, "SIOCGIFCAP(%s)", if_name);
3422*4f1223e8SApple OSS Distributions 	lro_enabled = (ifr.ifr_curcap & IFCAP_LRO) != 0;
3423*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(expected, lro_enabled, "%s %s expected %s",
3424*4f1223e8SApple OSS Distributions 	    __func__, if_name, expected ? "enabled" : "disabled");
3425*4f1223e8SApple OSS Distributions }
3426*4f1223e8SApple OSS Distributions 
3427*4f1223e8SApple OSS Distributions static void
bridge_test_lro_disable(void)3428*4f1223e8SApple OSS Distributions bridge_test_lro_disable(void)
3429*4f1223e8SApple OSS Distributions {
3430*4f1223e8SApple OSS Distributions 	int             err;
3431*4f1223e8SApple OSS Distributions 
3432*4f1223e8SApple OSS Distributions 	signal(SIGINT, sigint_lro_cleanup);
3433*4f1223e8SApple OSS Distributions 
3434*4f1223e8SApple OSS Distributions 	T_ATEND(lro_test_cleanup);
3435*4f1223e8SApple OSS Distributions 
3436*4f1223e8SApple OSS Distributions 	err = ifnet_create(BRIDGE200);
3437*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(err, 0, "ifnet_create(%s)", BRIDGE200);
3438*4f1223e8SApple OSS Distributions 	fake_set_lro(true);
3439*4f1223e8SApple OSS Distributions 	err = ifnet_create(FETH0);
3440*4f1223e8SApple OSS Distributions 	T_ASSERT_EQ(err, 0, "ifnet_create(%s)", FETH0);
3441*4f1223e8SApple OSS Distributions 	fake_set_lro(false);
3442*4f1223e8SApple OSS Distributions 	verify_lro_capability(FETH0, true);
3443*4f1223e8SApple OSS Distributions 	bridge_add_member(BRIDGE200, FETH0);
3444*4f1223e8SApple OSS Distributions 	verify_lro_capability(FETH0, false);
3445*4f1223e8SApple OSS Distributions 	bridge_delete_member(BRIDGE200, FETH0);
3446*4f1223e8SApple OSS Distributions 	verify_lro_capability(FETH0, true);
3447*4f1223e8SApple OSS Distributions }
3448*4f1223e8SApple OSS Distributions 
3449*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_bcast,
3450*4f1223e8SApple OSS Distributions     "bridge broadcast IPv4",
3451*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3452*4f1223e8SApple OSS Distributions {
3453*4f1223e8SApple OSS Distributions 	bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3454*4f1223e8SApple OSS Distributions 	    AF_INET, 5, 1);
3455*4f1223e8SApple OSS Distributions }
3456*4f1223e8SApple OSS Distributions 
3457*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_bcast_many,
3458*4f1223e8SApple OSS Distributions     "bridge broadcast many IPv4",
3459*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3460*4f1223e8SApple OSS Distributions {
3461*4f1223e8SApple OSS Distributions 	bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3462*4f1223e8SApple OSS Distributions 	    AF_INET, 5, 20);
3463*4f1223e8SApple OSS Distributions }
3464*4f1223e8SApple OSS Distributions 
3465*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_unknown,
3466*4f1223e8SApple OSS Distributions     "bridge unknown host IPv4",
3467*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3468*4f1223e8SApple OSS Distributions {
3469*4f1223e8SApple OSS Distributions 	bridge_test(validate_not_present_dhost, NULL, &ether_external,
3470*4f1223e8SApple OSS Distributions 	    AF_INET, 5, 1);
3471*4f1223e8SApple OSS Distributions }
3472*4f1223e8SApple OSS Distributions 
3473*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_bcast_v6,
3474*4f1223e8SApple OSS Distributions     "bridge broadcast IPv6",
3475*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3476*4f1223e8SApple OSS Distributions {
3477*4f1223e8SApple OSS Distributions 	bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3478*4f1223e8SApple OSS Distributions 	    AF_INET6, 5, 1);
3479*4f1223e8SApple OSS Distributions }
3480*4f1223e8SApple OSS Distributions 
3481*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_bcast_many_v6,
3482*4f1223e8SApple OSS Distributions     "bridge broadcast many IPv6",
3483*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3484*4f1223e8SApple OSS Distributions {
3485*4f1223e8SApple OSS Distributions 	bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3486*4f1223e8SApple OSS Distributions 	    AF_INET6, 5, 20);
3487*4f1223e8SApple OSS Distributions }
3488*4f1223e8SApple OSS Distributions 
3489*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_unknown_v6,
3490*4f1223e8SApple OSS Distributions     "bridge unknown host IPv6",
3491*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3492*4f1223e8SApple OSS Distributions {
3493*4f1223e8SApple OSS Distributions 	bridge_test(validate_not_present_dhost, NULL, &ether_external,
3494*4f1223e8SApple OSS Distributions 	    AF_INET6, 5, 1);
3495*4f1223e8SApple OSS Distributions }
3496*4f1223e8SApple OSS Distributions 
3497*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_mac_nat_ipv4,
3498*4f1223e8SApple OSS Distributions     "bridge mac nat ipv4",
3499*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3500*4f1223e8SApple OSS Distributions {
3501*4f1223e8SApple OSS Distributions 	bridge_test_mac_nat_ipv4(5, 10);
3502*4f1223e8SApple OSS Distributions }
3503*4f1223e8SApple OSS Distributions 
3504*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_mac_nat_ipv6,
3505*4f1223e8SApple OSS Distributions     "bridge mac nat ipv6",
3506*4f1223e8SApple OSS Distributions     T_META_ASROOT(true),
3507*4f1223e8SApple OSS Distributions     T_META_TAG_VM_PREFERRED,
3508*4f1223e8SApple OSS Distributions     T_META_ENABLED(false /* rdar://133955717 */))
3509*4f1223e8SApple OSS Distributions {
3510*4f1223e8SApple OSS Distributions 	bridge_test_mac_nat_ipv6(5, 10, 0);
3511*4f1223e8SApple OSS Distributions }
3512*4f1223e8SApple OSS Distributions 
3513*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_mac_nat_ipv6_trailers,
3514*4f1223e8SApple OSS Distributions     "bridge mac nat ipv6 trailers",
3515*4f1223e8SApple OSS Distributions     T_META_ASROOT(true),
3516*4f1223e8SApple OSS Distributions     T_META_TAG_VM_PREFERRED,
3517*4f1223e8SApple OSS Distributions     T_META_ENABLED(false /* rdar://133955717 */))
3518*4f1223e8SApple OSS Distributions {
3519*4f1223e8SApple OSS Distributions 	bridge_test_mac_nat_ipv6(5, 10, SETUP_FLAGS_TRAILERS);
3520*4f1223e8SApple OSS Distributions }
3521*4f1223e8SApple OSS Distributions 
3522*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_filter_ipv4,
3523*4f1223e8SApple OSS Distributions     "bridge filter ipv4",
3524*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3525*4f1223e8SApple OSS Distributions {
3526*4f1223e8SApple OSS Distributions 	filter_test(AF_INET);
3527*4f1223e8SApple OSS Distributions }
3528*4f1223e8SApple OSS Distributions 
3529*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_filter_ipv6,
3530*4f1223e8SApple OSS Distributions     "bridge filter ipv6",
3531*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3532*4f1223e8SApple OSS Distributions {
3533*4f1223e8SApple OSS Distributions 	filter_test(AF_INET6);
3534*4f1223e8SApple OSS Distributions }
3535*4f1223e8SApple OSS Distributions 
3536*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_checksum_offload,
3537*4f1223e8SApple OSS Distributions     "bridge checksum offload",
3538*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3539*4f1223e8SApple OSS Distributions {
3540*4f1223e8SApple OSS Distributions 	bridge_test_transfer(2, SETUP_FLAGS_CHECKSUM_OFFLOAD);
3541*4f1223e8SApple OSS Distributions }
3542*4f1223e8SApple OSS Distributions 
3543*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_checksum_offload_trailers,
3544*4f1223e8SApple OSS Distributions     "bridge checksum offload with trailers+fcs",
3545*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3546*4f1223e8SApple OSS Distributions {
3547*4f1223e8SApple OSS Distributions 	bridge_test_transfer(2, SETUP_FLAGS_CHECKSUM_OFFLOAD |
3548*4f1223e8SApple OSS Distributions 	    SETUP_FLAGS_TRAILERS);
3549*4f1223e8SApple OSS Distributions }
3550*4f1223e8SApple OSS Distributions 
3551*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_transfer,
3552*4f1223e8SApple OSS Distributions     "bridge transfer",
3553*4f1223e8SApple OSS Distributions     T_META_ASROOT(true))
3554*4f1223e8SApple OSS Distributions {
3555*4f1223e8SApple OSS Distributions 	bridge_test_transfer(2, 0);
3556*4f1223e8SApple OSS Distributions }
3557*4f1223e8SApple OSS Distributions 
3558*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_transfer_share_mac,
3559*4f1223e8SApple OSS Distributions     "bridge transfer share member's MAC",
3560*4f1223e8SApple OSS Distributions     T_META_ASROOT(true))
3561*4f1223e8SApple OSS Distributions {
3562*4f1223e8SApple OSS Distributions 	bridge_test_transfer(2, SETUP_FLAGS_SHARE_MEMBER_MAC);
3563*4f1223e8SApple OSS Distributions }
3564*4f1223e8SApple OSS Distributions 
3565*4f1223e8SApple OSS Distributions T_DECL(net_if_bridge_lro_disable,
3566*4f1223e8SApple OSS Distributions     "bridge LRO disable",
3567*4f1223e8SApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
3568*4f1223e8SApple OSS Distributions {
3569*4f1223e8SApple OSS Distributions 	bridge_test_lro_disable();
3570*4f1223e8SApple OSS Distributions }
3571