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