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