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