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