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