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