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