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