xref: /freebsd/sys/net/debugnet_inet.c (revision 7790c8c1996ad89a22b8bd194a230cf23ee67f4b)
1*7790c8c1SConrad Meyer /*-
2*7790c8c1SConrad Meyer  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*7790c8c1SConrad Meyer  *
4*7790c8c1SConrad Meyer  * Copyright (c) 2019 Isilon Systems, LLC.
5*7790c8c1SConrad Meyer  * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
6*7790c8c1SConrad Meyer  * Copyright (c) 2000 Darrell Anderson
7*7790c8c1SConrad Meyer  * All rights reserved.
8*7790c8c1SConrad Meyer  *
9*7790c8c1SConrad Meyer  * Redistribution and use in source and binary forms, with or without
10*7790c8c1SConrad Meyer  * modification, are permitted provided that the following conditions
11*7790c8c1SConrad Meyer  * are met:
12*7790c8c1SConrad Meyer  * 1. Redistributions of source code must retain the above copyright
13*7790c8c1SConrad Meyer  *    notice, this list of conditions and the following disclaimer.
14*7790c8c1SConrad Meyer  * 2. Redistributions in binary form must reproduce the above copyright
15*7790c8c1SConrad Meyer  *    notice, this list of conditions and the following disclaimer in the
16*7790c8c1SConrad Meyer  *    documentation and/or other materials provided with the distribution.
17*7790c8c1SConrad Meyer  *
18*7790c8c1SConrad Meyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*7790c8c1SConrad Meyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*7790c8c1SConrad Meyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*7790c8c1SConrad Meyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*7790c8c1SConrad Meyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*7790c8c1SConrad Meyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*7790c8c1SConrad Meyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*7790c8c1SConrad Meyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*7790c8c1SConrad Meyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*7790c8c1SConrad Meyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*7790c8c1SConrad Meyer  * SUCH DAMAGE.
29*7790c8c1SConrad Meyer  */
30*7790c8c1SConrad Meyer 
31*7790c8c1SConrad Meyer #include <sys/cdefs.h>
32*7790c8c1SConrad Meyer __FBSDID("$FreeBSD$");
33*7790c8c1SConrad Meyer 
34*7790c8c1SConrad Meyer #include "opt_inet.h"
35*7790c8c1SConrad Meyer 
36*7790c8c1SConrad Meyer #include <sys/param.h>
37*7790c8c1SConrad Meyer #include <sys/systm.h>
38*7790c8c1SConrad Meyer #include <sys/errno.h>
39*7790c8c1SConrad Meyer #include <sys/socket.h>
40*7790c8c1SConrad Meyer #include <sys/sysctl.h>
41*7790c8c1SConrad Meyer 
42*7790c8c1SConrad Meyer #include <net/ethernet.h>
43*7790c8c1SConrad Meyer #include <net/if.h>
44*7790c8c1SConrad Meyer #include <net/if_arp.h>
45*7790c8c1SConrad Meyer #include <net/if_dl.h>
46*7790c8c1SConrad Meyer #include <net/if_types.h>
47*7790c8c1SConrad Meyer #include <net/if_var.h>
48*7790c8c1SConrad Meyer 
49*7790c8c1SConrad Meyer #include <netinet/in.h>
50*7790c8c1SConrad Meyer #include <netinet/in_systm.h>
51*7790c8c1SConrad Meyer #include <netinet/in_var.h>
52*7790c8c1SConrad Meyer #include <netinet/ip.h>
53*7790c8c1SConrad Meyer #include <netinet/ip_var.h>
54*7790c8c1SConrad Meyer #include <netinet/ip_options.h>
55*7790c8c1SConrad Meyer #include <netinet/udp.h>
56*7790c8c1SConrad Meyer #include <netinet/udp_var.h>
57*7790c8c1SConrad Meyer 
58*7790c8c1SConrad Meyer #include <machine/in_cksum.h>
59*7790c8c1SConrad Meyer #include <machine/pcb.h>
60*7790c8c1SConrad Meyer 
61*7790c8c1SConrad Meyer #include <net/debugnet.h>
62*7790c8c1SConrad Meyer #define	DEBUGNET_INTERNAL
63*7790c8c1SConrad Meyer #include <net/debugnet_int.h>
64*7790c8c1SConrad Meyer 
65*7790c8c1SConrad Meyer int debugnet_arp_nretries = 3;
66*7790c8c1SConrad Meyer SYSCTL_INT(_net_debugnet, OID_AUTO, arp_nretries, CTLFLAG_RWTUN,
67*7790c8c1SConrad Meyer     &debugnet_arp_nretries, 0,
68*7790c8c1SConrad Meyer     "Number of ARP attempts before giving up");
69*7790c8c1SConrad Meyer 
70*7790c8c1SConrad Meyer /*
71*7790c8c1SConrad Meyer  * Handler for IP packets: checks their sanity and then processes any debugnet
72*7790c8c1SConrad Meyer  * ACK packets it finds.
73*7790c8c1SConrad Meyer  *
74*7790c8c1SConrad Meyer  * It needs to partially replicate the behaviour of ip_input() and udp_input().
75*7790c8c1SConrad Meyer  *
76*7790c8c1SConrad Meyer  * Parameters:
77*7790c8c1SConrad Meyer  *	pcb	a pointer to the live debugnet PCB
78*7790c8c1SConrad Meyer  *	mb	a pointer to an mbuf * containing the packet received
79*7790c8c1SConrad Meyer  *		Updates *mb if m_pullup et al change the pointer
80*7790c8c1SConrad Meyer  *		Assumes the calling function will take care of freeing the mbuf
81*7790c8c1SConrad Meyer  */
82*7790c8c1SConrad Meyer void
83*7790c8c1SConrad Meyer debugnet_handle_ip(struct debugnet_pcb *pcb, struct mbuf **mb)
84*7790c8c1SConrad Meyer {
85*7790c8c1SConrad Meyer 	struct ip *ip;
86*7790c8c1SConrad Meyer 	struct mbuf *m;
87*7790c8c1SConrad Meyer 	unsigned short hlen;
88*7790c8c1SConrad Meyer 
89*7790c8c1SConrad Meyer 	/* IP processing. */
90*7790c8c1SConrad Meyer 	m = *mb;
91*7790c8c1SConrad Meyer 	if (m->m_pkthdr.len < sizeof(struct ip)) {
92*7790c8c1SConrad Meyer 		DNETDEBUG("dropping packet too small for IP header\n");
93*7790c8c1SConrad Meyer 		return;
94*7790c8c1SConrad Meyer 	}
95*7790c8c1SConrad Meyer 	if (m->m_len < sizeof(struct ip)) {
96*7790c8c1SConrad Meyer 		m = m_pullup(m, sizeof(struct ip));
97*7790c8c1SConrad Meyer 		*mb = m;
98*7790c8c1SConrad Meyer 		if (m == NULL) {
99*7790c8c1SConrad Meyer 			DNETDEBUG("m_pullup failed\n");
100*7790c8c1SConrad Meyer 			return;
101*7790c8c1SConrad Meyer 		}
102*7790c8c1SConrad Meyer 	}
103*7790c8c1SConrad Meyer 	ip = mtod(m, struct ip *);
104*7790c8c1SConrad Meyer 
105*7790c8c1SConrad Meyer 	/* IP version. */
106*7790c8c1SConrad Meyer 	if (ip->ip_v != IPVERSION) {
107*7790c8c1SConrad Meyer 		DNETDEBUG("bad IP version %d\n", ip->ip_v);
108*7790c8c1SConrad Meyer 		return;
109*7790c8c1SConrad Meyer 	}
110*7790c8c1SConrad Meyer 
111*7790c8c1SConrad Meyer 	/* Header length. */
112*7790c8c1SConrad Meyer 	hlen = ip->ip_hl << 2;
113*7790c8c1SConrad Meyer 	if (hlen < sizeof(struct ip)) {
114*7790c8c1SConrad Meyer 		DNETDEBUG("bad IP header length (%hu)\n", hlen);
115*7790c8c1SConrad Meyer 		return;
116*7790c8c1SConrad Meyer 	}
117*7790c8c1SConrad Meyer 	if (hlen > m->m_len) {
118*7790c8c1SConrad Meyer 		m = m_pullup(m, hlen);
119*7790c8c1SConrad Meyer 		*mb = m;
120*7790c8c1SConrad Meyer 		if (m == NULL) {
121*7790c8c1SConrad Meyer 			DNETDEBUG("m_pullup failed\n");
122*7790c8c1SConrad Meyer 			return;
123*7790c8c1SConrad Meyer 		}
124*7790c8c1SConrad Meyer 		ip = mtod(m, struct ip *);
125*7790c8c1SConrad Meyer 	}
126*7790c8c1SConrad Meyer 	/* Ignore packets with IP options. */
127*7790c8c1SConrad Meyer 	if (hlen > sizeof(struct ip)) {
128*7790c8c1SConrad Meyer 		DNETDEBUG("drop packet with IP options\n");
129*7790c8c1SConrad Meyer 		return;
130*7790c8c1SConrad Meyer 	}
131*7790c8c1SConrad Meyer 
132*7790c8c1SConrad Meyer #ifdef INVARIANTS
133*7790c8c1SConrad Meyer 	if ((IN_LOOPBACK(ntohl(ip->ip_dst.s_addr)) ||
134*7790c8c1SConrad Meyer 	    IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) &&
135*7790c8c1SConrad Meyer 	    (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
136*7790c8c1SConrad Meyer 		DNETDEBUG("Bad IP header (RFC1122)\n");
137*7790c8c1SConrad Meyer 		return;
138*7790c8c1SConrad Meyer 	}
139*7790c8c1SConrad Meyer #endif
140*7790c8c1SConrad Meyer 
141*7790c8c1SConrad Meyer 	/* Checksum. */
142*7790c8c1SConrad Meyer 	if ((m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) != 0) {
143*7790c8c1SConrad Meyer 		if ((m->m_pkthdr.csum_flags & CSUM_IP_VALID) == 0) {
144*7790c8c1SConrad Meyer 			DNETDEBUG("bad IP checksum\n");
145*7790c8c1SConrad Meyer 			return;
146*7790c8c1SConrad Meyer 		}
147*7790c8c1SConrad Meyer 	} else {
148*7790c8c1SConrad Meyer 		/* XXX */ ;
149*7790c8c1SConrad Meyer 	}
150*7790c8c1SConrad Meyer 
151*7790c8c1SConrad Meyer 	/* Convert fields to host byte order. */
152*7790c8c1SConrad Meyer 	ip->ip_len = ntohs(ip->ip_len);
153*7790c8c1SConrad Meyer 	if (ip->ip_len < hlen) {
154*7790c8c1SConrad Meyer 		DNETDEBUG("IP packet smaller (%hu) than header (%hu)\n",
155*7790c8c1SConrad Meyer 		    ip->ip_len, hlen);
156*7790c8c1SConrad Meyer 		return;
157*7790c8c1SConrad Meyer 	}
158*7790c8c1SConrad Meyer 	if (m->m_pkthdr.len < ip->ip_len) {
159*7790c8c1SConrad Meyer 		DNETDEBUG("IP packet bigger (%hu) than ethernet packet (%d)\n",
160*7790c8c1SConrad Meyer 		    ip->ip_len, m->m_pkthdr.len);
161*7790c8c1SConrad Meyer 		return;
162*7790c8c1SConrad Meyer 	}
163*7790c8c1SConrad Meyer 	if (m->m_pkthdr.len > ip->ip_len) {
164*7790c8c1SConrad Meyer 
165*7790c8c1SConrad Meyer 		/* Truncate the packet to the IP length. */
166*7790c8c1SConrad Meyer 		if (m->m_len == m->m_pkthdr.len) {
167*7790c8c1SConrad Meyer 			m->m_len = ip->ip_len;
168*7790c8c1SConrad Meyer 			m->m_pkthdr.len = ip->ip_len;
169*7790c8c1SConrad Meyer 		} else
170*7790c8c1SConrad Meyer 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
171*7790c8c1SConrad Meyer 	}
172*7790c8c1SConrad Meyer 
173*7790c8c1SConrad Meyer 	ip->ip_off = ntohs(ip->ip_off);
174*7790c8c1SConrad Meyer 
175*7790c8c1SConrad Meyer 	/* Check that the source is the server's IP. */
176*7790c8c1SConrad Meyer 	if (ip->ip_src.s_addr != pcb->dp_server) {
177*7790c8c1SConrad Meyer 		DNETDEBUG("drop packet not from server (from 0x%x)\n",
178*7790c8c1SConrad Meyer 		    ip->ip_src.s_addr);
179*7790c8c1SConrad Meyer 		return;
180*7790c8c1SConrad Meyer 	}
181*7790c8c1SConrad Meyer 
182*7790c8c1SConrad Meyer 	/* Check if the destination IP is ours. */
183*7790c8c1SConrad Meyer 	if (ip->ip_dst.s_addr != pcb->dp_client) {
184*7790c8c1SConrad Meyer 		DNETDEBUGV("drop packet not to our IP\n");
185*7790c8c1SConrad Meyer 		return;
186*7790c8c1SConrad Meyer 	}
187*7790c8c1SConrad Meyer 
188*7790c8c1SConrad Meyer 	if (ip->ip_p != IPPROTO_UDP) {
189*7790c8c1SConrad Meyer 		DNETDEBUG("drop non-UDP packet\n");
190*7790c8c1SConrad Meyer 		return;
191*7790c8c1SConrad Meyer 	}
192*7790c8c1SConrad Meyer 
193*7790c8c1SConrad Meyer 	/* Do not deal with fragments. */
194*7790c8c1SConrad Meyer 	if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) {
195*7790c8c1SConrad Meyer 		DNETDEBUG("drop fragmented packet\n");
196*7790c8c1SConrad Meyer 		return;
197*7790c8c1SConrad Meyer 	}
198*7790c8c1SConrad Meyer 
199*7790c8c1SConrad Meyer 	/* UDP custom is to have packet length not include IP header. */
200*7790c8c1SConrad Meyer 	ip->ip_len -= hlen;
201*7790c8c1SConrad Meyer 
202*7790c8c1SConrad Meyer 	/* Checked above before decoding IP header. */
203*7790c8c1SConrad Meyer 	MPASS(m->m_pkthdr.len >= sizeof(struct ipovly));
204*7790c8c1SConrad Meyer 
205*7790c8c1SConrad Meyer 	/* Put the UDP header at start of chain. */
206*7790c8c1SConrad Meyer 	m_adj(m, sizeof(struct ipovly));
207*7790c8c1SConrad Meyer 	debugnet_handle_udp(pcb, mb);
208*7790c8c1SConrad Meyer }
209*7790c8c1SConrad Meyer 
210*7790c8c1SConrad Meyer /*
211*7790c8c1SConrad Meyer  * Builds and sends a single ARP request to locate the L2 address for a given
212*7790c8c1SConrad Meyer  * INET address.
213*7790c8c1SConrad Meyer  *
214*7790c8c1SConrad Meyer  * Return value:
215*7790c8c1SConrad Meyer  *	0 on success
216*7790c8c1SConrad Meyer  *	errno on error
217*7790c8c1SConrad Meyer  */
218*7790c8c1SConrad Meyer static int
219*7790c8c1SConrad Meyer debugnet_send_arp(struct debugnet_pcb *pcb, in_addr_t dst)
220*7790c8c1SConrad Meyer {
221*7790c8c1SConrad Meyer 	struct ether_addr bcast;
222*7790c8c1SConrad Meyer 	struct arphdr *ah;
223*7790c8c1SConrad Meyer 	struct ifnet *ifp;
224*7790c8c1SConrad Meyer 	struct mbuf *m;
225*7790c8c1SConrad Meyer 	int pktlen;
226*7790c8c1SConrad Meyer 
227*7790c8c1SConrad Meyer 	ifp = pcb->dp_ifp;
228*7790c8c1SConrad Meyer 
229*7790c8c1SConrad Meyer 	/* Fill-up a broadcast address. */
230*7790c8c1SConrad Meyer 	memset(&bcast, 0xFF, ETHER_ADDR_LEN);
231*7790c8c1SConrad Meyer 	m = m_gethdr(M_NOWAIT, MT_DATA);
232*7790c8c1SConrad Meyer 	if (m == NULL) {
233*7790c8c1SConrad Meyer 		printf("%s: Out of mbufs\n", __func__);
234*7790c8c1SConrad Meyer 		return (ENOBUFS);
235*7790c8c1SConrad Meyer 	}
236*7790c8c1SConrad Meyer 	pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr));
237*7790c8c1SConrad Meyer 	m->m_len = pktlen;
238*7790c8c1SConrad Meyer 	m->m_pkthdr.len = pktlen;
239*7790c8c1SConrad Meyer 	MH_ALIGN(m, pktlen);
240*7790c8c1SConrad Meyer 	ah = mtod(m, struct arphdr *);
241*7790c8c1SConrad Meyer 	ah->ar_hrd = htons(ARPHRD_ETHER);
242*7790c8c1SConrad Meyer 	ah->ar_pro = htons(ETHERTYPE_IP);
243*7790c8c1SConrad Meyer 	ah->ar_hln = ETHER_ADDR_LEN;
244*7790c8c1SConrad Meyer 	ah->ar_pln = sizeof(struct in_addr);
245*7790c8c1SConrad Meyer 	ah->ar_op = htons(ARPOP_REQUEST);
246*7790c8c1SConrad Meyer 	memcpy(ar_sha(ah), IF_LLADDR(ifp), ETHER_ADDR_LEN);
247*7790c8c1SConrad Meyer 	((struct in_addr *)ar_spa(ah))->s_addr = pcb->dp_client;
248*7790c8c1SConrad Meyer 	bzero(ar_tha(ah), ETHER_ADDR_LEN);
249*7790c8c1SConrad Meyer 	((struct in_addr *)ar_tpa(ah))->s_addr = dst;
250*7790c8c1SConrad Meyer 	return (debugnet_ether_output(m, ifp, bcast, ETHERTYPE_ARP));
251*7790c8c1SConrad Meyer }
252*7790c8c1SConrad Meyer 
253*7790c8c1SConrad Meyer /*
254*7790c8c1SConrad Meyer  * Handler for ARP packets: checks their sanity and then
255*7790c8c1SConrad Meyer  * 1. If the ARP is a request for our IP, respond with our MAC address
256*7790c8c1SConrad Meyer  * 2. If the ARP is a response from our server, record its MAC address
257*7790c8c1SConrad Meyer  *
258*7790c8c1SConrad Meyer  * It needs to replicate partially the behaviour of arpintr() and
259*7790c8c1SConrad Meyer  * in_arpinput().
260*7790c8c1SConrad Meyer  *
261*7790c8c1SConrad Meyer  * Parameters:
262*7790c8c1SConrad Meyer  *	pcb	a pointer to the live debugnet PCB
263*7790c8c1SConrad Meyer  *	mb	a pointer to an mbuf * containing the packet received
264*7790c8c1SConrad Meyer  *		Updates *mb if m_pullup et al change the pointer
265*7790c8c1SConrad Meyer  *		Assumes the calling function will take care of freeing the mbuf
266*7790c8c1SConrad Meyer  */
267*7790c8c1SConrad Meyer void
268*7790c8c1SConrad Meyer debugnet_handle_arp(struct debugnet_pcb *pcb, struct mbuf **mb)
269*7790c8c1SConrad Meyer {
270*7790c8c1SConrad Meyer 	char buf[INET_ADDRSTRLEN];
271*7790c8c1SConrad Meyer 	struct in_addr isaddr, itaddr;
272*7790c8c1SConrad Meyer 	struct ether_addr dst;
273*7790c8c1SConrad Meyer 	struct mbuf *m;
274*7790c8c1SConrad Meyer 	struct arphdr *ah;
275*7790c8c1SConrad Meyer 	struct ifnet *ifp;
276*7790c8c1SConrad Meyer 	uint8_t *enaddr;
277*7790c8c1SConrad Meyer 	int req_len, op;
278*7790c8c1SConrad Meyer 
279*7790c8c1SConrad Meyer 	m = *mb;
280*7790c8c1SConrad Meyer 	ifp = m->m_pkthdr.rcvif;
281*7790c8c1SConrad Meyer 	if (m->m_len < sizeof(struct arphdr)) {
282*7790c8c1SConrad Meyer 		m = m_pullup(m, sizeof(struct arphdr));
283*7790c8c1SConrad Meyer 		*mb = m;
284*7790c8c1SConrad Meyer 		if (m == NULL) {
285*7790c8c1SConrad Meyer 			DNETDEBUG("runt packet: m_pullup failed\n");
286*7790c8c1SConrad Meyer 			return;
287*7790c8c1SConrad Meyer 		}
288*7790c8c1SConrad Meyer 	}
289*7790c8c1SConrad Meyer 
290*7790c8c1SConrad Meyer 	ah = mtod(m, struct arphdr *);
291*7790c8c1SConrad Meyer 	if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) {
292*7790c8c1SConrad Meyer 		DNETDEBUG("unknown hardware address 0x%2D)\n",
293*7790c8c1SConrad Meyer 		    (unsigned char *)&ah->ar_hrd, "");
294*7790c8c1SConrad Meyer 		return;
295*7790c8c1SConrad Meyer 	}
296*7790c8c1SConrad Meyer 	if (ntohs(ah->ar_pro) != ETHERTYPE_IP) {
297*7790c8c1SConrad Meyer 		DNETDEBUG("drop ARP for unknown protocol %d\n",
298*7790c8c1SConrad Meyer 		    ntohs(ah->ar_pro));
299*7790c8c1SConrad Meyer 		return;
300*7790c8c1SConrad Meyer 	}
301*7790c8c1SConrad Meyer 	req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
302*7790c8c1SConrad Meyer 	if (m->m_len < req_len) {
303*7790c8c1SConrad Meyer 		m = m_pullup(m, req_len);
304*7790c8c1SConrad Meyer 		*mb = m;
305*7790c8c1SConrad Meyer 		if (m == NULL) {
306*7790c8c1SConrad Meyer 			DNETDEBUG("runt packet: m_pullup failed\n");
307*7790c8c1SConrad Meyer 			return;
308*7790c8c1SConrad Meyer 		}
309*7790c8c1SConrad Meyer 	}
310*7790c8c1SConrad Meyer 	ah = mtod(m, struct arphdr *);
311*7790c8c1SConrad Meyer 
312*7790c8c1SConrad Meyer 	op = ntohs(ah->ar_op);
313*7790c8c1SConrad Meyer 	memcpy(&isaddr, ar_spa(ah), sizeof(isaddr));
314*7790c8c1SConrad Meyer 	memcpy(&itaddr, ar_tpa(ah), sizeof(itaddr));
315*7790c8c1SConrad Meyer 	enaddr = (uint8_t *)IF_LLADDR(ifp);
316*7790c8c1SConrad Meyer 
317*7790c8c1SConrad Meyer 	if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) {
318*7790c8c1SConrad Meyer 		DNETDEBUG("ignoring ARP from myself\n");
319*7790c8c1SConrad Meyer 		return;
320*7790c8c1SConrad Meyer 	}
321*7790c8c1SConrad Meyer 
322*7790c8c1SConrad Meyer 	if (isaddr.s_addr == pcb->dp_client) {
323*7790c8c1SConrad Meyer 		printf("%s: %*D is using my IP address %s!\n", __func__,
324*7790c8c1SConrad Meyer 		    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
325*7790c8c1SConrad Meyer 		    inet_ntoa_r(isaddr, buf));
326*7790c8c1SConrad Meyer 		return;
327*7790c8c1SConrad Meyer 	}
328*7790c8c1SConrad Meyer 
329*7790c8c1SConrad Meyer 	if (memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen) == 0) {
330*7790c8c1SConrad Meyer 		DNETDEBUG("ignoring ARP from broadcast address\n");
331*7790c8c1SConrad Meyer 		return;
332*7790c8c1SConrad Meyer 	}
333*7790c8c1SConrad Meyer 
334*7790c8c1SConrad Meyer 	if (op == ARPOP_REPLY) {
335*7790c8c1SConrad Meyer 		if (isaddr.s_addr != pcb->dp_gateway &&
336*7790c8c1SConrad Meyer 		    isaddr.s_addr != pcb->dp_server) {
337*7790c8c1SConrad Meyer 			inet_ntoa_r(isaddr, buf);
338*7790c8c1SConrad Meyer 			DNETDEBUG("ignoring ARP reply from %s (not configured"
339*7790c8c1SConrad Meyer 			    " server or gateway)\n", buf);
340*7790c8c1SConrad Meyer 			return;
341*7790c8c1SConrad Meyer 		}
342*7790c8c1SConrad Meyer 		memcpy(pcb->dp_gw_mac.octet, ar_sha(ah),
343*7790c8c1SConrad Meyer 		    min(ah->ar_hln, ETHER_ADDR_LEN));
344*7790c8c1SConrad Meyer 
345*7790c8c1SConrad Meyer 		DNETDEBUG("got server MAC address %6D\n",
346*7790c8c1SConrad Meyer 		    pcb->dp_gw_mac.octet, ":");
347*7790c8c1SConrad Meyer 
348*7790c8c1SConrad Meyer 		MPASS(pcb->dp_state == DN_STATE_INIT);
349*7790c8c1SConrad Meyer 		pcb->dp_state = DN_STATE_HAVE_GW_MAC;
350*7790c8c1SConrad Meyer 		return;
351*7790c8c1SConrad Meyer 	}
352*7790c8c1SConrad Meyer 
353*7790c8c1SConrad Meyer 	if (op != ARPOP_REQUEST) {
354*7790c8c1SConrad Meyer 		DNETDEBUG("ignoring ARP non-request/reply\n");
355*7790c8c1SConrad Meyer 		return;
356*7790c8c1SConrad Meyer 	}
357*7790c8c1SConrad Meyer 
358*7790c8c1SConrad Meyer 	if (itaddr.s_addr != pcb->dp_client) {
359*7790c8c1SConrad Meyer 		DNETDEBUG("ignoring ARP not to our IP\n");
360*7790c8c1SConrad Meyer 		return;
361*7790c8c1SConrad Meyer 	}
362*7790c8c1SConrad Meyer 
363*7790c8c1SConrad Meyer 	memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
364*7790c8c1SConrad Meyer 	memcpy(ar_sha(ah), enaddr, ah->ar_hln);
365*7790c8c1SConrad Meyer 	memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
366*7790c8c1SConrad Meyer 	memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
367*7790c8c1SConrad Meyer 	ah->ar_op = htons(ARPOP_REPLY);
368*7790c8c1SConrad Meyer 	ah->ar_pro = htons(ETHERTYPE_IP);
369*7790c8c1SConrad Meyer 	m->m_flags &= ~(M_BCAST|M_MCAST);
370*7790c8c1SConrad Meyer 	m->m_len = arphdr_len(ah);
371*7790c8c1SConrad Meyer 	m->m_pkthdr.len = m->m_len;
372*7790c8c1SConrad Meyer 
373*7790c8c1SConrad Meyer 	memcpy(dst.octet, ar_tha(ah), ETHER_ADDR_LEN);
374*7790c8c1SConrad Meyer 	debugnet_ether_output(m, ifp, dst, ETHERTYPE_ARP);
375*7790c8c1SConrad Meyer 	*mb = NULL;
376*7790c8c1SConrad Meyer }
377*7790c8c1SConrad Meyer 
378*7790c8c1SConrad Meyer /*
379*7790c8c1SConrad Meyer  * Sends ARP requests to locate the server and waits for a response.
380*7790c8c1SConrad Meyer  * We first try to ARP the server itself, and fall back to the provided
381*7790c8c1SConrad Meyer  * gateway if the server appears to be off-link.
382*7790c8c1SConrad Meyer  *
383*7790c8c1SConrad Meyer  * Return value:
384*7790c8c1SConrad Meyer  *	0 on success
385*7790c8c1SConrad Meyer  *	errno on error
386*7790c8c1SConrad Meyer  */
387*7790c8c1SConrad Meyer int
388*7790c8c1SConrad Meyer debugnet_arp_gw(struct debugnet_pcb *pcb)
389*7790c8c1SConrad Meyer {
390*7790c8c1SConrad Meyer 	in_addr_t dst;
391*7790c8c1SConrad Meyer 	int error, polls, retries;
392*7790c8c1SConrad Meyer 
393*7790c8c1SConrad Meyer 	dst = pcb->dp_server;
394*7790c8c1SConrad Meyer restart:
395*7790c8c1SConrad Meyer 	for (retries = 0; retries < debugnet_arp_nretries; retries++) {
396*7790c8c1SConrad Meyer 		error = debugnet_send_arp(pcb, dst);
397*7790c8c1SConrad Meyer 		if (error != 0)
398*7790c8c1SConrad Meyer 			return (error);
399*7790c8c1SConrad Meyer 		for (polls = 0; polls < debugnet_npolls &&
400*7790c8c1SConrad Meyer 		    pcb->dp_state < DN_STATE_HAVE_GW_MAC; polls++) {
401*7790c8c1SConrad Meyer 			debugnet_network_poll(pcb->dp_ifp);
402*7790c8c1SConrad Meyer 			DELAY(500);
403*7790c8c1SConrad Meyer 		}
404*7790c8c1SConrad Meyer 		if (pcb->dp_state >= DN_STATE_HAVE_GW_MAC)
405*7790c8c1SConrad Meyer 			break;
406*7790c8c1SConrad Meyer 		printf("(ARP retry)");
407*7790c8c1SConrad Meyer 	}
408*7790c8c1SConrad Meyer 	if (pcb->dp_state >= DN_STATE_HAVE_GW_MAC)
409*7790c8c1SConrad Meyer 		return (0);
410*7790c8c1SConrad Meyer 	if (dst == pcb->dp_server) {
411*7790c8c1SConrad Meyer 		printf("\nFailed to ARP server");
412*7790c8c1SConrad Meyer 		if (pcb->dp_gateway != INADDR_ANY) {
413*7790c8c1SConrad Meyer 			printf(", trying to reach gateway...\n");
414*7790c8c1SConrad Meyer 			dst = pcb->dp_gateway;
415*7790c8c1SConrad Meyer 			goto restart;
416*7790c8c1SConrad Meyer 		} else
417*7790c8c1SConrad Meyer 			printf(".\n");
418*7790c8c1SConrad Meyer 	} else
419*7790c8c1SConrad Meyer 		printf("\nFailed to ARP gateway.\n");
420*7790c8c1SConrad Meyer 
421*7790c8c1SConrad Meyer 	return (ETIMEDOUT);
422*7790c8c1SConrad Meyer }
423*7790c8c1SConrad Meyer 
424*7790c8c1SConrad Meyer /*
425*7790c8c1SConrad Meyer  * Unreliable IPv4 transmission of an mbuf chain to the debugnet server
426*7790c8c1SConrad Meyer  * Note: can't handle fragmentation; fails if the packet is larger than
427*7790c8c1SConrad Meyer  *	 ifp->if_mtu after adding the UDP/IP headers
428*7790c8c1SConrad Meyer  *
429*7790c8c1SConrad Meyer  * Parameters:
430*7790c8c1SConrad Meyer  *	pcb	The debugnet context block
431*7790c8c1SConrad Meyer  *	m	mbuf chain
432*7790c8c1SConrad Meyer  *
433*7790c8c1SConrad Meyer  * Returns:
434*7790c8c1SConrad Meyer  *	int	see errno.h, 0 for success
435*7790c8c1SConrad Meyer  */
436*7790c8c1SConrad Meyer int
437*7790c8c1SConrad Meyer debugnet_ip_output(struct debugnet_pcb *pcb, struct mbuf *m)
438*7790c8c1SConrad Meyer {
439*7790c8c1SConrad Meyer 	struct udphdr *udp;
440*7790c8c1SConrad Meyer 	struct ifnet *ifp;
441*7790c8c1SConrad Meyer 	struct ip *ip;
442*7790c8c1SConrad Meyer 
443*7790c8c1SConrad Meyer 	MPASS(pcb->dp_state >= DN_STATE_HAVE_GW_MAC);
444*7790c8c1SConrad Meyer 
445*7790c8c1SConrad Meyer 	ifp = pcb->dp_ifp;
446*7790c8c1SConrad Meyer 
447*7790c8c1SConrad Meyer 	M_PREPEND(m, sizeof(*ip), M_NOWAIT);
448*7790c8c1SConrad Meyer 	if (m == NULL) {
449*7790c8c1SConrad Meyer 		printf("%s: out of mbufs\n", __func__);
450*7790c8c1SConrad Meyer 		return (ENOBUFS);
451*7790c8c1SConrad Meyer 	}
452*7790c8c1SConrad Meyer 
453*7790c8c1SConrad Meyer 	if (m->m_pkthdr.len > ifp->if_mtu) {
454*7790c8c1SConrad Meyer 		printf("%s: Packet is too big: %d > MTU %u\n", __func__,
455*7790c8c1SConrad Meyer 		    m->m_pkthdr.len, ifp->if_mtu);
456*7790c8c1SConrad Meyer 		m_freem(m);
457*7790c8c1SConrad Meyer 		return (ENOBUFS);
458*7790c8c1SConrad Meyer 	}
459*7790c8c1SConrad Meyer 
460*7790c8c1SConrad Meyer 	ip = mtod(m, void *);
461*7790c8c1SConrad Meyer 	udp = (void *)(ip + 1);
462*7790c8c1SConrad Meyer 
463*7790c8c1SConrad Meyer 	memset(ip, 0, offsetof(struct ip, ip_p));
464*7790c8c1SConrad Meyer 	ip->ip_p = IPPROTO_UDP;
465*7790c8c1SConrad Meyer 	ip->ip_sum = udp->uh_ulen;
466*7790c8c1SConrad Meyer 	ip->ip_src = (struct in_addr) { pcb->dp_client };
467*7790c8c1SConrad Meyer 	ip->ip_dst = (struct in_addr) { pcb->dp_server };
468*7790c8c1SConrad Meyer 
469*7790c8c1SConrad Meyer 	/* Compute UDP-IPv4 checksum. */
470*7790c8c1SConrad Meyer 	udp->uh_sum = in_cksum(m, m->m_pkthdr.len);
471*7790c8c1SConrad Meyer 	if (udp->uh_sum == 0)
472*7790c8c1SConrad Meyer 		udp->uh_sum = 0xffff;
473*7790c8c1SConrad Meyer 
474*7790c8c1SConrad Meyer 	ip->ip_v = IPVERSION;
475*7790c8c1SConrad Meyer 	ip->ip_hl = sizeof(*ip) >> 2;
476*7790c8c1SConrad Meyer 	ip->ip_tos = 0;
477*7790c8c1SConrad Meyer 	ip->ip_len = htons(m->m_pkthdr.len);
478*7790c8c1SConrad Meyer 	ip->ip_id = 0;
479*7790c8c1SConrad Meyer 	ip->ip_off = htons(IP_DF);
480*7790c8c1SConrad Meyer 	ip->ip_ttl = 255;
481*7790c8c1SConrad Meyer 	ip->ip_sum = 0;
482*7790c8c1SConrad Meyer 	ip->ip_sum = in_cksum(m, sizeof(struct ip));
483*7790c8c1SConrad Meyer 
484*7790c8c1SConrad Meyer 	return (debugnet_ether_output(m, ifp, pcb->dp_gw_mac, ETHERTYPE_IP));
485*7790c8c1SConrad Meyer }
486