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