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