xref: /netbsd-src/sys/net/if_arcsubr.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: if_arcsubr.c,v 1.86 2024/07/05 04:31:53 rin Exp $	*/
2aad01611Sagc 
3aad01611Sagc /*
46de8cab7Sis  * Copyright (c) 1994, 1995 Ignatios Souvatzis
5aad01611Sagc  * Copyright (c) 1982, 1989, 1993
6aad01611Sagc  *	The Regents of the University of California.  All rights reserved.
7aad01611Sagc  *
8aad01611Sagc  * Redistribution and use in source and binary forms, with or without
9aad01611Sagc  * modification, are permitted provided that the following conditions
10aad01611Sagc  * are met:
11aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
12aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
13aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
14aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
15aad01611Sagc  *    documentation and/or other materials provided with the distribution.
16aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
17aad01611Sagc  *    may be used to endorse or promote products derived from this software
18aad01611Sagc  *    without specific prior written permission.
19aad01611Sagc  *
20aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30aad01611Sagc  * SUCH DAMAGE.
31aad01611Sagc  *
32aad01611Sagc  * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
33aad01611Sagc  *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
34aad01611Sagc  *
35aad01611Sagc  */
36f634dc19Sglass 
3734d65a34Slukem #include <sys/cdefs.h>
38*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: if_arcsubr.c,v 1.86 2024/07/05 04:31:53 rin Exp $");
3934d65a34Slukem 
401c4a50f1Spooka #ifdef _KERNEL_OPT
413751946bSjonathan #include "opt_inet.h"
421c4a50f1Spooka #endif
43c5293456Sthorpej 
44f634dc19Sglass #include <sys/param.h>
45f634dc19Sglass #include <sys/systm.h>
46f634dc19Sglass #include <sys/kernel.h>
47f634dc19Sglass #include <sys/malloc.h>
48f634dc19Sglass #include <sys/mbuf.h>
49206addf6Smycroft #include <sys/ioctl.h>
50f634dc19Sglass #include <sys/errno.h>
51206addf6Smycroft #include <sys/syslog.h>
52f634dc19Sglass 
53a2a38285Sad #include <sys/cpu.h>
54f634dc19Sglass 
55f634dc19Sglass #include <net/if.h>
56f634dc19Sglass #include <net/route.h>
57f634dc19Sglass #include <net/if_dl.h>
58f634dc19Sglass #include <net/if_types.h>
5957f2f47eSis #include <net/if_arc.h>
6007b064e0Sis #include <net/if_arp.h>
6107b064e0Sis #include <net/if_ether.h>
62f634dc19Sglass 
63c5293456Sthorpej #include <net/bpf.h>
64c5293456Sthorpej 
65f634dc19Sglass #ifdef INET
66f634dc19Sglass #include <netinet/in.h>
67f634dc19Sglass #include <netinet/in_var.h>
687e9704bbSis #include <netinet/if_inarp.h>
69f634dc19Sglass #endif
70f634dc19Sglass 
716a793d8aSis #ifdef INET6
726a793d8aSis #ifndef INET
736a793d8aSis #include <netinet/in.h>
746a793d8aSis #endif
756a793d8aSis #include <netinet6/in6_var.h>
766a793d8aSis #include <netinet6/nd6.h>
776a793d8aSis #endif
786a793d8aSis 
7907b064e0Sis #define ARCNET_ALLOW_BROKEN_ARP
8007b064e0Sis 
81f546d949Sis #ifndef ARC_IPMTU
82f546d949Sis #define ARC_IPMTU	1500
83d4f62dcbScgd #endif
84d4f62dcbScgd 
8563eac52bSthorpej static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
86d4f62dcbScgd 
87d4f62dcbScgd /*
88d4f62dcbScgd  * RC1201 requires us to have this configurable. We have it only per
89d4f62dcbScgd  * machine at the moment... there is no generic "set mtu" ioctl, AFAICS.
90d4f62dcbScgd  * Anyway, it is possible to binpatch this or set it per kernel config
91d4f62dcbScgd  * option.
92d4f62dcbScgd  */
93f546d949Sis #if ARC_IPMTU > 60480
94f546d949Sis ERROR: The arc_ipmtu is ARC_IPMTU, but must not exceed 60480.
95d4f62dcbScgd #endif
96f546d949Sis int arc_ipmtu = ARC_IPMTU;
972b028087Smatt uint8_t  arcbroadcastaddr = 0;
98f634dc19Sglass 
99f634dc19Sglass #define senderr(e) { error = (e); goto bad;}
100f634dc19Sglass 
10163eac52bSthorpej static	int arc_output(struct ifnet *, struct mbuf *,
102a931ad27Sozaki-r 	    const struct sockaddr *, const struct rtentry *);
10363eac52bSthorpej static	void arc_input(struct ifnet *, struct mbuf *);
104f98d358aSthorpej 
105f634dc19Sglass /*
106f634dc19Sglass  * ARCnet output routine.
107f634dc19Sglass  * Encapsulate a packet of type family for the local net.
108f634dc19Sglass  * Assumes that ifp is actually pointer to arccom structure.
109f634dc19Sglass  */
110f98d358aSthorpej static int
arc_output(struct ifnet * ifp,struct mbuf * m0,const struct sockaddr * dst,const struct rtentry * rt)111ba2aee81Sdyoung arc_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
112a931ad27Sozaki-r     const struct rtentry *rt)
113f634dc19Sglass {
114d4f62dcbScgd 	struct mbuf		*m, *m1, *mcopy;
115d4f62dcbScgd 	struct arccom		*ac;
116ba2aee81Sdyoung 	const struct arc_header	*cah;
1177e9704bbSis 	struct arc_header	*ah;
1187e9704bbSis 	struct arphdr		*arph;
119d7ec95d3Schristos 	int			error, newencoding;
1202b028087Smatt 	uint8_t			atype, adst, myself;
121d4f62dcbScgd 	int			tfrags, sflag, fsflag, rsflag;
122f634dc19Sglass 
123f634dc19Sglass 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
124a5ba4721Sis 		return (ENETDOWN); /* m, m1 aren't initialized yet */
125d4f62dcbScgd 
126d4f62dcbScgd 	error = newencoding = 0;
127d4f62dcbScgd 	ac = (struct arccom *)ifp;
128d4f62dcbScgd 	m = m0;
129d4f62dcbScgd 	mcopy = m1 = NULL;
130d4f62dcbScgd 
131b3fc2963Sdyoung 	myself = *CLLADDR(ifp->if_sadl);
13207b064e0Sis 
133ac36f7cbSitojun 	/*
134ac36f7cbSitojun 	 * if the queueing discipline needs packet classification,
135ac36f7cbSitojun 	 * do it before prepending link headers.
136ac36f7cbSitojun 	 */
137b76ec0b0Sknakahara 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
138ac36f7cbSitojun 
139d4f62dcbScgd 	switch (dst->sa_family) {
140f634dc19Sglass #ifdef INET
141f634dc19Sglass 	case AF_INET:
142f634dc19Sglass 
143f634dc19Sglass 		/*
144f634dc19Sglass 		 * For now, use the simple IP addr -> ARCnet addr mapping
145f634dc19Sglass 		 */
146905db383Sis 		if (m->m_flags & (M_BCAST|M_MCAST))
147f634dc19Sglass 			adst = arcbroadcastaddr; /* ARCnet broadcast address */
14807b064e0Sis 		else if (ifp->if_flags & IFF_NOARP)
149ba2aee81Sdyoung 			adst = ntohl(satocsin(dst)->sin_addr.s_addr) & 0xFF;
150b988d754Schristos 		else if ((error = arpresolve(ifp, rt, m, dst, &adst,
151b988d754Schristos 		    sizeof(adst))) != 0)
152222d6fabSroy 			return error == EWOULDBLOCK ? 0 : error;
153f634dc19Sglass 
154f634dc19Sglass 		/* If broadcasting on a simplex interface, loopback a copy */
155905db383Sis 		if ((m->m_flags & (M_BCAST|M_MCAST)) &&
156905db383Sis 		    (ifp->if_flags & IFF_SIMPLEX))
1570be2ad1aSmaxv 			mcopy = m_copypacket(m, M_DONTWAIT);
158d4f62dcbScgd 		if (ifp->if_flags & IFF_LINK0) {
159d4f62dcbScgd 			atype = ARCTYPE_IP;
160d4f62dcbScgd 			newencoding = 1;
161d4f62dcbScgd 		} else {
162f634dc19Sglass 			atype = ARCTYPE_IP_OLD;
163d4f62dcbScgd 			newencoding = 0;
164d4f62dcbScgd 		}
165f634dc19Sglass 		break;
16607b064e0Sis 
16707b064e0Sis 	case AF_ARP:
1687e9704bbSis 		arph = mtod(m, struct arphdr *);
16907b064e0Sis 		if (m->m_flags & M_BCAST)
17007b064e0Sis 			adst = arcbroadcastaddr;
171dd8534acSchristos 		else {
172dd8534acSchristos 			uint8_t *tha = ar_tha(arph);
173a2073096Smaxv 			if (tha == NULL) {
174a2073096Smaxv 				m_freem(m);
175dd8534acSchristos 				return 0;
176a2073096Smaxv 			}
177dd8534acSchristos 			adst = *tha;
178dd8534acSchristos 		}
17907b064e0Sis 
1804555777cSis 		arph->ar_hrd = htons(ARPHRD_ARCNET);
1814555777cSis 
1827e9704bbSis 		switch (ntohs(arph->ar_op)) {
18307b064e0Sis 		case ARPOP_REVREQUEST:
18407b064e0Sis 		case ARPOP_REVREPLY:
18507b064e0Sis 			if (!(ifp->if_flags & IFF_LINK0)) {
18607b064e0Sis 				printf("%s: can't handle af%d\n",
18707b064e0Sis 				    ifp->if_xname, dst->sa_family);
18807b064e0Sis 				senderr(EAFNOSUPPORT);
18907b064e0Sis 			}
19007b064e0Sis 
19107b064e0Sis 			atype = htons(ARCTYPE_REVARP);
19207b064e0Sis 			newencoding = 1;
19307b064e0Sis 			break;
19407b064e0Sis 
19507b064e0Sis 		case ARPOP_REQUEST:
19607b064e0Sis 		case ARPOP_REPLY:
19707b064e0Sis 		default:
19807b064e0Sis 			if (ifp->if_flags & IFF_LINK0) {
19907b064e0Sis 				atype = htons(ARCTYPE_ARP);
20007b064e0Sis 				newencoding = 1;
20107b064e0Sis 			} else {
20207b064e0Sis 				atype = htons(ARCTYPE_ARP_OLD);
20307b064e0Sis 				newencoding = 0;
20407b064e0Sis 			}
20507b064e0Sis 		}
20607b064e0Sis #ifdef ARCNET_ALLOW_BROKEN_ARP
20707b064e0Sis 		/*
20807b064e0Sis 		 * XXX It's not clear per RFC826 if this is needed, but
20907b064e0Sis 		 * "assigned numbers" say this is wrong.
21007b064e0Sis 		 * However, e.g., AmiTCP 3.0Beta used it... we make this
21107b064e0Sis 		 * switchable for emergency cases. Not perfect, but...
21207b064e0Sis 		 */
2134555777cSis 		if (ifp->if_flags & IFF_LINK2)
2144555777cSis 			arph->ar_pro = atype - 1;
21507b064e0Sis #endif
21607b064e0Sis 		break;
217f634dc19Sglass #endif
2186a793d8aSis #ifdef INET6
2196a793d8aSis 	case AF_INET6:
2203f909d17Sozaki-r 		if (m->m_flags & M_MCAST) {
2213f909d17Sozaki-r 			adst = 0;
2223f909d17Sozaki-r 		} else {
2233f909d17Sozaki-r 			error = nd6_resolve(ifp, rt, m, dst, &adst,
2243f909d17Sozaki-r 			    sizeof(adst));
2253f909d17Sozaki-r 			if (error != 0)
2263f909d17Sozaki-r 				return error == EWOULDBLOCK ? 0 : error;
2273f909d17Sozaki-r 		}
2286a793d8aSis 		atype = htons(ARCTYPE_INET6);
2296a793d8aSis 		newencoding = 1;
2306a793d8aSis 		break;
2316a793d8aSis #endif
232d4f62dcbScgd 
233f634dc19Sglass 	case AF_UNSPEC:
234ba2aee81Sdyoung 		cah = (const struct arc_header *)dst->sa_data;
235ba2aee81Sdyoung  		adst = cah->arc_dhost;
236ba2aee81Sdyoung 		atype = cah->arc_type;
237f634dc19Sglass 		break;
238f634dc19Sglass 
239f634dc19Sglass 	default:
240a1dcf4b0Schristos 		printf("%s: can't handle af%d\n", ifp->if_xname,
241f634dc19Sglass 		    dst->sa_family);
242f634dc19Sglass 		senderr(EAFNOSUPPORT);
243f634dc19Sglass 	}
244f634dc19Sglass 
245f634dc19Sglass 	if (mcopy)
246f634dc19Sglass 		(void) looutput(ifp, mcopy, dst, rt);
247d4f62dcbScgd 
248f634dc19Sglass 	/*
249f634dc19Sglass 	 * Add local net header.  If no space in first mbuf,
250f634dc19Sglass 	 * allocate another.
251f634dc19Sglass 	 *
252f634dc19Sglass 	 * For ARCnet, this is just symbolic. The header changes
253f634dc19Sglass 	 * form and position on its way into the hardware and out of
254f634dc19Sglass 	 * the wire.  At this point, it contains source, destination and
255f634dc19Sglass 	 * packet type.
256f634dc19Sglass 	 */
257d4f62dcbScgd 	if (newencoding) {
258d4f62dcbScgd 		++ac->ac_seqid; /* make the seqid unique */
259d4f62dcbScgd 
260206addf6Smycroft 		tfrags = (m->m_pkthdr.len + 503) / 504;
261d4f62dcbScgd 		fsflag = 2 * tfrags - 3;
262d4f62dcbScgd 		sflag = 0;
263d4f62dcbScgd 		rsflag = fsflag;
264d4f62dcbScgd 
265d4f62dcbScgd 		while (sflag < fsflag) {
266d4f62dcbScgd 			/* we CAN'T have short packets here */
267d4f62dcbScgd 			m1 = m_split(m, 504, M_DONTWAIT);
268d4f62dcbScgd 			if (m1 == 0)
269d4f62dcbScgd 				senderr(ENOBUFS);
270d4f62dcbScgd 
271d4f62dcbScgd 			M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
272d4f62dcbScgd 			if (m == 0)
273d4f62dcbScgd 				senderr(ENOBUFS);
274d4f62dcbScgd 			ah = mtod(m, struct arc_header *);
275d4f62dcbScgd 			ah->arc_type = atype;
276d4f62dcbScgd 			ah->arc_dhost = adst;
27707b064e0Sis 			ah->arc_shost = myself;
278d4f62dcbScgd 			ah->arc_flag = rsflag;
279d4f62dcbScgd 			ah->arc_seqid = ac->ac_seqid;
280d4f62dcbScgd 
281b76ec0b0Sknakahara 			if ((error = ifq_enqueue(ifp, m)) != 0)
282ac36f7cbSitojun 				return (error);
283d4f62dcbScgd 
284d4f62dcbScgd 			m = m1;
285d4f62dcbScgd 			sflag += 2;
286d4f62dcbScgd 			rsflag = sflag;
287d4f62dcbScgd 		}
288d4f62dcbScgd 		m1 = NULL;
289d4f62dcbScgd 
290f77decf6Sis 
291f77decf6Sis 		/* here we can have small, especially forbidden packets */
292f77decf6Sis 
293f77decf6Sis 		if ((m->m_pkthdr.len >=
294f77decf6Sis 		    ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
295f77decf6Sis 		    (m->m_pkthdr.len <=
296f77decf6Sis 		    ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
297f77decf6Sis 
29806420a5aSis 			M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
299f77decf6Sis 			if (m == 0)
300f77decf6Sis 				senderr(ENOBUFS);
301f77decf6Sis 			ah = mtod(m, struct arc_header *);
302f77decf6Sis 			ah->arc_flag = 0xFF;
303f77decf6Sis 			ah->arc_seqid = 0xFFFF;
304f77decf6Sis 			ah->arc_type2 = atype;
305f77decf6Sis 			ah->arc_flag2 = sflag;
306f77decf6Sis 			ah->arc_seqid2 = ac->ac_seqid;
307f77decf6Sis 		} else {
308d4f62dcbScgd 			M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
309d4f62dcbScgd 			if (m == 0)
310d4f62dcbScgd 				senderr(ENOBUFS);
311d4f62dcbScgd 			ah = mtod(m, struct arc_header *);
312d4f62dcbScgd 			ah->arc_flag = sflag;
313d4f62dcbScgd 			ah->arc_seqid = ac->ac_seqid;
314d4f62dcbScgd 		}
315d4f62dcbScgd 
316d4f62dcbScgd 		ah->arc_dhost = adst;
31707b064e0Sis 		ah->arc_shost = myself;
318f77decf6Sis 		ah->arc_type = atype;
319d4f62dcbScgd 	} else {
320f634dc19Sglass 		M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
321f634dc19Sglass 		if (m == 0)
322f634dc19Sglass 			senderr(ENOBUFS);
323f634dc19Sglass 		ah = mtod(m, struct arc_header *);
324f634dc19Sglass 		ah->arc_type = atype;
325f634dc19Sglass 		ah->arc_dhost = adst;
32607b064e0Sis 		ah->arc_shost = myself;
327206addf6Smycroft 	}
328ac36f7cbSitojun 
329b76ec0b0Sknakahara 	return ifq_enqueue(ifp, m);
330f634dc19Sglass 
331f634dc19Sglass bad:
332d4f62dcbScgd 	m_freem(m1);
333f634dc19Sglass 	m_freem(m);
334f634dc19Sglass 	return (error);
335f634dc19Sglass }
336f634dc19Sglass 
337f634dc19Sglass /*
338d4f62dcbScgd  * Defragmenter. Returns mbuf if last packet found, else
339d4f62dcbScgd  * NULL. frees imcoming mbuf as necessary.
340d4f62dcbScgd  */
341d4f62dcbScgd 
34263eac52bSthorpej static struct mbuf *
arc_defrag(struct ifnet * ifp,struct mbuf * m)34363eac52bSthorpej arc_defrag(struct ifnet *ifp, struct mbuf *m)
344d4f62dcbScgd {
345d4f62dcbScgd 	struct arc_header *ah, *ah1;
346d4f62dcbScgd 	struct arccom *ac;
347d4f62dcbScgd 	struct ac_frag *af;
348d4f62dcbScgd 	struct mbuf *m1;
349eae41d37She 	const char *s;
350d4f62dcbScgd 	int newflen;
351d4f62dcbScgd 	u_char src, dst, typ;
352d4f62dcbScgd 
353d4f62dcbScgd 	ac = (struct arccom *)ifp;
354d4f62dcbScgd 
3556a793d8aSis 	if (m->m_len < ARC_HDRNEWLEN) {
356d4f62dcbScgd 		m = m_pullup(m, ARC_HDRNEWLEN);
357d4f62dcbScgd 		if (m == NULL) {
35870b554e6Sthorpej 			if_statinc(ifp, if_ierrors);
359d4f62dcbScgd 			return NULL;
360d4f62dcbScgd 		}
3616a793d8aSis 	}
362d4f62dcbScgd 
363d4f62dcbScgd 	ah = mtod(m, struct arc_header *);
364d4f62dcbScgd 	typ = ah->arc_type;
365d4f62dcbScgd 
366d4f62dcbScgd 	if (!arc_isphds(typ))
367d4f62dcbScgd 		return m;
368d4f62dcbScgd 
369d4f62dcbScgd 	src = ah->arc_shost;
370d4f62dcbScgd 	dst = ah->arc_dhost;
371d4f62dcbScgd 
372d4f62dcbScgd 	if (ah->arc_flag == 0xff) {
373d4f62dcbScgd 		m_adj(m, 4);
374d4f62dcbScgd 
3756a793d8aSis 		if (m->m_len < ARC_HDRNEWLEN) {
376d4f62dcbScgd 			m = m_pullup(m, ARC_HDRNEWLEN);
377d4f62dcbScgd 			if (m == NULL) {
37870b554e6Sthorpej 				if_statinc(ifp, if_ierrors);
379d4f62dcbScgd 				return NULL;
380d4f62dcbScgd 			}
3816a793d8aSis 		}
382d4f62dcbScgd 
383d4f62dcbScgd 		ah = mtod(m, struct arc_header *);
384d4f62dcbScgd 	}
385d4f62dcbScgd 
386d4f62dcbScgd 	af = &ac->ac_fragtab[src];
387d4f62dcbScgd 	m1 = af->af_packet;
388d4f62dcbScgd 	s = "debug code error";
389d4f62dcbScgd 
390d4f62dcbScgd 	if (ah->arc_flag & 1) {
391d4f62dcbScgd 		/*
392d4f62dcbScgd 		 * first fragment. We always initialize, which is
393d4f62dcbScgd 		 * about the right thing to do, as we only want to
394d4f62dcbScgd 		 * accept one fragmented packet per src at a time.
395d4f62dcbScgd 		 */
396d4f62dcbScgd 		m_freem(m1);
397d4f62dcbScgd 
398d4f62dcbScgd 		af->af_packet = m;
399d4f62dcbScgd 		m1 = m;
400d4f62dcbScgd 		af->af_maxflag = ah->arc_flag;
401d4f62dcbScgd 		af->af_lastseen = 0;
402d4f62dcbScgd 		af->af_seqid = ah->arc_seqid;
403d4f62dcbScgd 
404d4f62dcbScgd 		return NULL;
405d4f62dcbScgd 		/* notreached */
406d4f62dcbScgd 	} else {
407d4f62dcbScgd 		/* check for unfragmented packet */
408d4f62dcbScgd 		if (ah->arc_flag == 0)
409d4f62dcbScgd 			return m;
410d4f62dcbScgd 
411d4f62dcbScgd 		/* do we have a first packet from that src? */
412d4f62dcbScgd 		if (m1 == NULL) {
413d4f62dcbScgd 			s = "no first frag";
414d4f62dcbScgd 			goto outofseq;
415d4f62dcbScgd 		}
416d4f62dcbScgd 
417d4f62dcbScgd 		ah1 = mtod(m1, struct arc_header *);
418d4f62dcbScgd 
419d4f62dcbScgd 		if (ah->arc_seqid != ah1->arc_seqid) {
420d4f62dcbScgd 			s = "seqid differs";
421d4f62dcbScgd 			goto outofseq;
422d4f62dcbScgd 		}
423d4f62dcbScgd 
4245854b4eaSis 		if (typ != ah1->arc_type) {
425d4f62dcbScgd 			s = "type differs";
426d4f62dcbScgd 			goto outofseq;
427d4f62dcbScgd 		}
428d4f62dcbScgd 
4295854b4eaSis 		if (dst != ah1->arc_dhost) {
430d4f62dcbScgd 			s = "dest host differs";
431d4f62dcbScgd 			goto outofseq;
432d4f62dcbScgd 		}
433d4f62dcbScgd 
434d4f62dcbScgd 		/* typ, seqid and dst are ok here. */
435d4f62dcbScgd 
436d4f62dcbScgd 		if (ah->arc_flag == af->af_lastseen) {
437d4f62dcbScgd 			m_freem(m);
438d4f62dcbScgd 			return NULL;
439d4f62dcbScgd 		}
440d4f62dcbScgd 
441d4f62dcbScgd 		if (ah->arc_flag == af->af_lastseen + 2) {
442d4f62dcbScgd 			/* ok, this is next fragment */
443d4f62dcbScgd 			af->af_lastseen = ah->arc_flag;
444d4f62dcbScgd 			m_adj(m, ARC_HDRNEWLEN);
445d4f62dcbScgd 
446d4f62dcbScgd 			/*
447d4f62dcbScgd 			 * m_cat might free the first mbuf (with pkthdr)
448d4f62dcbScgd 			 * in 2nd chain; therefore:
449d4f62dcbScgd 			 */
450d4f62dcbScgd 
451d4f62dcbScgd 			newflen = m->m_pkthdr.len;
452d4f62dcbScgd 
453d4f62dcbScgd 			m_cat(m1, m);
454d4f62dcbScgd 
455d4f62dcbScgd 			m1->m_pkthdr.len += newflen;
456d4f62dcbScgd 
457d4f62dcbScgd 			/* is it the last one? */
458d4f62dcbScgd 			if (af->af_lastseen > af->af_maxflag) {
459d4f62dcbScgd 				af->af_packet = NULL;
460d4f62dcbScgd 				return (m1);
461d4f62dcbScgd 			} else
462d4f62dcbScgd 				return NULL;
463d4f62dcbScgd 		}
464d4f62dcbScgd 		s = "other reason";
465d4f62dcbScgd 		/* if all else fails, it is out of sequence, too */
466d4f62dcbScgd 	}
467d4f62dcbScgd outofseq:
468d4f62dcbScgd 	if (m1) {
469d4f62dcbScgd 		m_freem(m1);
470d4f62dcbScgd 		af->af_packet = NULL;
471d4f62dcbScgd 	}
472d4f62dcbScgd 
473d4f62dcbScgd 	m_freem(m);
474d4f62dcbScgd 
4754edabe25Sthorpej 	log(LOG_INFO,"%s: got out of seq. packet: %s\n",
4764edabe25Sthorpej 	    ifp->if_xname, s);
477d4f62dcbScgd 
478d4f62dcbScgd 	return NULL;
479d4f62dcbScgd }
480d4f62dcbScgd 
481d4f62dcbScgd /*
482d4f62dcbScgd  * return 1 if Packet Header Definition Standard, else 0.
483d4f62dcbScgd  * For now: old IP, old ARP aren't obviously. Lacking correct information,
484d4f62dcbScgd  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
485d4f62dcbScgd  * (Apple and Novell corporations were involved, among others, in PHDS work).
486d4f62dcbScgd  * Easiest is to assume that everybody else uses that, too.
487d4f62dcbScgd  */
488d4f62dcbScgd int
arc_isphds(uint8_t type)48963eac52bSthorpej arc_isphds(uint8_t type)
490d4f62dcbScgd {
4916a793d8aSis 	return (type != ARCTYPE_IP_OLD &&
4926a793d8aSis 		type != ARCTYPE_ARP_OLD &&
4936a793d8aSis 		type != ARCTYPE_DIAGNOSE);
494d4f62dcbScgd }
495d4f62dcbScgd 
496d4f62dcbScgd /*
497f634dc19Sglass  * Process a received Arcnet packet;
4985f90c172Schopps  * the packet is in the mbuf chain m with
4995f90c172Schopps  * the ARCnet header.
500f634dc19Sglass  */
501f98d358aSthorpej static void
arc_input(struct ifnet * ifp,struct mbuf * m)50263eac52bSthorpej arc_input(struct ifnet *ifp, struct mbuf *m)
503f634dc19Sglass {
50460d350cfSrmind 	pktqueue_t *pktq = NULL;
505c1ebd192Saugustss 	struct arc_header *ah;
5062b028087Smatt 	uint8_t atype;
507f634dc19Sglass 
508f634dc19Sglass 	if ((ifp->if_flags & IFF_UP) == 0) {
509f634dc19Sglass 		m_freem(m);
510f634dc19Sglass 		return;
511f634dc19Sglass 	}
512d4f62dcbScgd 
513d4f62dcbScgd 	/* possibly defragment: */
514d4f62dcbScgd 	m = arc_defrag(ifp, m);
515d4f62dcbScgd 	if (m == NULL)
516d4f62dcbScgd 		return;
517d4f62dcbScgd 
5185f90c172Schopps 	ah = mtod(m, struct arc_header *);
5195f90c172Schopps 
52070b554e6Sthorpej 	if_statadd(ifp, if_ibytes, m->m_pkthdr.len);
521f634dc19Sglass 
522f634dc19Sglass 	if (arcbroadcastaddr == ah->arc_dhost) {
523905db383Sis 		m->m_flags |= M_BCAST|M_MCAST;
52470b554e6Sthorpej 		if_statinc(ifp, if_imcasts);
525f634dc19Sglass 	}
526f634dc19Sglass 
527f634dc19Sglass 	atype = ah->arc_type;
528f634dc19Sglass 	switch (atype) {
529f634dc19Sglass #ifdef INET
530d4f62dcbScgd 	case ARCTYPE_IP:
531d4f62dcbScgd 		m_adj(m, ARC_HDRNEWLEN);
53260d350cfSrmind 		pktq = ip_pktq;
533d4f62dcbScgd 		break;
534d4f62dcbScgd 
535f634dc19Sglass 	case ARCTYPE_IP_OLD:
5365f90c172Schopps 		m_adj(m, ARC_HDRLEN);
53760d350cfSrmind 		pktq = ip_pktq;
538f634dc19Sglass 		break;
53907b064e0Sis 
54007b064e0Sis 	case ARCTYPE_ARP:
54107b064e0Sis 		m_adj(m, ARC_HDRNEWLEN);
54263ae4dd2Sthorpej 		pktq = arp_pktq;
54307b064e0Sis #ifdef ARCNET_ALLOW_BROKEN_ARP
5444555777cSis 		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
54507b064e0Sis #endif
54607b064e0Sis 		break;
54707b064e0Sis 
54807b064e0Sis 	case ARCTYPE_ARP_OLD:
54907b064e0Sis 		m_adj(m, ARC_HDRLEN);
55063ae4dd2Sthorpej 		pktq = arp_pktq;
55107b064e0Sis #ifdef ARCNET_ALLOW_BROKEN_ARP
5524555777cSis 		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
55307b064e0Sis #endif
55407b064e0Sis 		break;
555f634dc19Sglass #endif
5566a793d8aSis #ifdef INET6
5576a793d8aSis 	case ARCTYPE_INET6:
5586a793d8aSis 		m_adj(m, ARC_HDRNEWLEN);
55960d350cfSrmind 		pktq = ip6_pktq;
5606a793d8aSis 		break;
5616a793d8aSis #endif
562f634dc19Sglass 	default:
563f634dc19Sglass 		m_freem(m);
564f634dc19Sglass 		return;
565f634dc19Sglass 	}
566f634dc19Sglass 
56763ae4dd2Sthorpej 	KASSERT(pktq != NULL);
56860d350cfSrmind 	if (__predict_false(!pktq_enqueue(pktq, m, 0))) {
56960d350cfSrmind 		m_freem(m);
57060d350cfSrmind 	}
571f634dc19Sglass }
572f634dc19Sglass 
573f634dc19Sglass /*
574f634dc19Sglass  * Convert Arcnet address to printable (loggable) representation.
575f634dc19Sglass  */
576f634dc19Sglass char *
arc_sprintf(uint8_t * ap)57763eac52bSthorpej arc_sprintf(uint8_t *ap)
578f634dc19Sglass {
579f634dc19Sglass 	static char arcbuf[3];
580c1ebd192Saugustss 	char *cp = arcbuf;
581f634dc19Sglass 
582362a4a0bSchristos 	*cp++ = hexdigits[*ap >> 4];
583362a4a0bSchristos 	*cp++ = hexdigits[*ap++ & 0xf];
584f634dc19Sglass 	*cp   = 0;
585f634dc19Sglass 	return (arcbuf);
586f634dc19Sglass }
587f634dc19Sglass 
588f634dc19Sglass /*
589f634dc19Sglass  * Perform common duties while attaching to interface list
590f634dc19Sglass  */
591cb49e3c2Smsaitoh int
arc_ifattach(struct ifnet * ifp,uint8_t lla)59263eac52bSthorpej arc_ifattach(struct ifnet *ifp, uint8_t lla)
593f634dc19Sglass {
594c1ebd192Saugustss 	struct arccom *ac;
595f634dc19Sglass 
596f634dc19Sglass 	ifp->if_type = IFT_ARCNET;
597f634dc19Sglass 	ifp->if_addrlen = 1;
598f634dc19Sglass 	ifp->if_hdrlen = ARC_HDRLEN;
599ed7695a7Sthorpej 	ifp->if_dlt = DLT_ARCNET;
600905db383Sis 	if (ifp->if_flags & IFF_BROADCAST)
601905db383Sis 		ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
602f546d949Sis 	if (ifp->if_flags & IFF_LINK0 && arc_ipmtu > ARC_PHDS_MAXMTU)
603d4f62dcbScgd 		log(LOG_ERR,
604c23ac422Smsaitoh 		    "%s: arc_ipmtu is %d, but must not exceed %d\n",
605f546d949Sis 		    ifp->if_xname, arc_ipmtu, ARC_PHDS_MAXMTU);
606d4f62dcbScgd 
607f98d358aSthorpej 	ifp->if_output = arc_output;
60828e7d22eSozaki-r 	ifp->_if_input = arc_input;
609d4f62dcbScgd 	ac = (struct arccom *)ifp;
610de4337abSkardel 	ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
61107b064e0Sis 	if (lla == 0) {
612d4f62dcbScgd 		/* XXX this message isn't entirely clear, to me -- cgd */
6134edabe25Sthorpej 		log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
6144edabe25Sthorpej 		   ifp->if_xname, ifp->if_xname);
6155f90c172Schopps 	}
616076e3579Sriastradh 	if_attach(ifp);
617cb49e3c2Smsaitoh 
618de87fe67Sdyoung 	if_set_sadl(ifp, &lla, sizeof(lla), true);
619d8c7407aSis 
620fabb3343Sis 	ifp->if_broadcastaddr = &arcbroadcastaddr;
621c5293456Sthorpej 
62258e86755Sjoerg 	bpf_attach(ifp, DLT_ARCNET, ARC_HDRLEN);
623cb49e3c2Smsaitoh 
624cb49e3c2Smsaitoh 	return 0;
625f634dc19Sglass }
626