if_arcsubr.c revision 127260
189099Sfjoe/*	$NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $	*/
289099Sfjoe/*	$FreeBSD: head/sys/net/if_arcsubr.c 127260 2004-03-21 06:34:34Z mdodd $ */
389099Sfjoe
489099Sfjoe/*
589099Sfjoe * Copyright (c) 1994, 1995 Ignatios Souvatzis
689099Sfjoe * Copyright (c) 1982, 1989, 1993
789099Sfjoe *	The Regents of the University of California.  All rights reserved.
889099Sfjoe *
989099Sfjoe * Redistribution and use in source and binary forms, with or without
1089099Sfjoe * modification, are permitted provided that the following conditions
1189099Sfjoe * are met:
1289099Sfjoe * 1. Redistributions of source code must retain the above copyright
1389099Sfjoe *    notice, this list of conditions and the following disclaimer.
1489099Sfjoe * 2. Redistributions in binary form must reproduce the above copyright
1589099Sfjoe *    notice, this list of conditions and the following disclaimer in the
1689099Sfjoe *    documentation and/or other materials provided with the distribution.
1789099Sfjoe * 3. All advertising materials mentioning features or use of this software
1889099Sfjoe *    must display the following acknowledgement:
1989099Sfjoe *	This product includes software developed by the University of
2089099Sfjoe *	California, Berkeley and its contributors.
2189099Sfjoe * 4. Neither the name of the University nor the names of its contributors
2289099Sfjoe *    may be used to endorse or promote products derived from this software
2389099Sfjoe *    without specific prior written permission.
2489099Sfjoe *
2589099Sfjoe * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2689099Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2789099Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2889099Sfjoe * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2989099Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3089099Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3189099Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3289099Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3389099Sfjoe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3489099Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3589099Sfjoe * SUCH DAMAGE.
3689099Sfjoe *
3789099Sfjoe * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
3889099Sfjoe *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
3989099Sfjoe *
4089099Sfjoe */
4189099Sfjoe#include "opt_inet.h"
4289099Sfjoe#include "opt_inet6.h"
43109771Sfjoe#include "opt_ipx.h"
4489099Sfjoe
4589099Sfjoe#include <sys/param.h>
4689099Sfjoe#include <sys/systm.h>
4789099Sfjoe#include <sys/kernel.h>
4889099Sfjoe#include <sys/malloc.h>
4989099Sfjoe#include <sys/mbuf.h>
5089099Sfjoe#include <sys/protosw.h>
5189099Sfjoe#include <sys/socket.h>
5289099Sfjoe#include <sys/sockio.h>
5389099Sfjoe#include <sys/errno.h>
5489099Sfjoe#include <sys/syslog.h>
5589099Sfjoe
5689099Sfjoe#include <machine/cpu.h>
5789099Sfjoe
5889099Sfjoe#include <net/if.h>
5989099Sfjoe#include <net/netisr.h>
6089099Sfjoe#include <net/route.h>
6189099Sfjoe#include <net/if_dl.h>
6289099Sfjoe#include <net/if_types.h>
6389099Sfjoe#include <net/if_arc.h>
6489099Sfjoe#include <net/if_arp.h>
6589099Sfjoe#include <net/bpf.h>
6689099Sfjoe
6789099Sfjoe#if defined(INET) || defined(INET6)
6889099Sfjoe#include <netinet/in.h>
6989099Sfjoe#include <netinet/in_var.h>
7089099Sfjoe#include <netinet/if_ether.h>
7189099Sfjoe#endif
7289099Sfjoe
7389099Sfjoe#ifdef INET6
7489099Sfjoe#include <netinet6/nd6.h>
7589099Sfjoe#endif
7689099Sfjoe
77109771Sfjoe#ifdef IPX
78109771Sfjoe#include <netipx/ipx.h>
79109771Sfjoe#include <netipx/ipx_if.h>
80109771Sfjoe#endif
81109771Sfjoe
8289099SfjoeMODULE_VERSION(arcnet, 1);
8389099Sfjoe
8489099Sfjoe#define ARCNET_ALLOW_BROKEN_ARP
8589099Sfjoe
8692725Salfredstatic struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
87109771Sfjoestatic int arc_resolvemulti(struct ifnet *, struct sockaddr **,
88109771Sfjoe			    struct sockaddr *);
8989099Sfjoe
9089099Sfjoeu_int8_t  arcbroadcastaddr = 0;
9189099Sfjoe
92110106Sfjoe#define ARC_LLADDR(ifp)	(*(u_int8_t *)IF_LLADDR(ifp))
93110106Sfjoe
9489099Sfjoe#define senderr(e) { error = (e); goto bad;}
95109771Sfjoe#define SIN(s)	((struct sockaddr_in *)s)
96109771Sfjoe#define SIPX(s)	((struct sockaddr_ipx *)s)
9789099Sfjoe
9889099Sfjoe/*
9989099Sfjoe * ARCnet output routine.
10089099Sfjoe * Encapsulate a packet of type family for the local net.
10189099Sfjoe * Assumes that ifp is actually pointer to arccom structure.
10289099Sfjoe */
10389099Sfjoeint
10489099Sfjoearc_output(ifp, m, dst, rt0)
10589099Sfjoe	struct ifnet *ifp;
10689099Sfjoe	struct mbuf *m;
10789099Sfjoe	struct sockaddr *dst;
10889099Sfjoe	struct rtentry *rt0;
10989099Sfjoe{
11089099Sfjoe	struct rtentry		*rt;
11189099Sfjoe	struct arccom		*ac;
11289099Sfjoe	struct arc_header	*ah;
11389099Sfjoe	int			error;
11489099Sfjoe	u_int8_t		atype, adst;
115109771Sfjoe	int			loop_copy = 0;
116110106Sfjoe	int			isphds;
11789099Sfjoe
11889099Sfjoe	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
11989099Sfjoe		return(ENETDOWN); /* m, m1 aren't initialized yet */
12089099Sfjoe
12189099Sfjoe	error = 0;
12289099Sfjoe	ac = (struct arccom *)ifp;
12389099Sfjoe
124111767Smdodd	error = rt_check(&rt, &rt0, dst);
125111767Smdodd	if (error)
126111767Smdodd		goto bad;
12789099Sfjoe
12889099Sfjoe	switch (dst->sa_family) {
12989099Sfjoe#ifdef INET
13089099Sfjoe	case AF_INET:
13189099Sfjoe
13289099Sfjoe		/*
13389099Sfjoe		 * For now, use the simple IP addr -> ARCnet addr mapping
13489099Sfjoe		 */
13589099Sfjoe		if (m->m_flags & (M_BCAST|M_MCAST))
13689099Sfjoe			adst = arcbroadcastaddr; /* ARCnet broadcast address */
13789099Sfjoe		else if (ifp->if_flags & IFF_NOARP)
13889099Sfjoe			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
13989099Sfjoe		else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
14089099Sfjoe			return 0;	/* not resolved yet */
14189099Sfjoe
14289099Sfjoe		atype = (ifp->if_flags & IFF_LINK0) ?
14389099Sfjoe			ARCTYPE_IP_OLD : ARCTYPE_IP;
14489099Sfjoe		break;
145127260Smdodd	case AF_ARP:
146127260Smdodd	{
147127260Smdodd		struct arphdr *ah;
148127260Smdodd		ah = mtod(m, struct arphdr *);
149127260Smdodd		ah->ar_hrd = htons(ARPHRD_ARCNET);
150127260Smdodd
151127260Smdodd		loop_copy = -1; /* if this is for us, don't do it */
152127260Smdodd
153127260Smdodd		switch(ntohs(ah->ar_op)) {
154127260Smdodd		case ARPOP_REVREQUEST:
155127260Smdodd		case ARPOP_REVREPLY:
156127260Smdodd			type = htons(ARCTYPE_REVARP);
157127260Smdodd			break;
158127260Smdodd		case ARPOP_REQUEST:
159127260Smdodd		case ARPOP_REPLY:
160127260Smdodd		default:
161127260Smdodd			type = htons(ARCTYPE_ARP);
162127260Smdodd			break;
163127260Smdodd		}
164127260Smdodd
165127260Smdodd		if (m->m_flags & M_BCAST)
166127260Smdodd			bcopy(ifp->if_broadcastaddr, adst, ARC_ADDR_LEN);
167127260Smdodd		else
168127260Smdodd			bcopy(ar_tha(ah), adst, ARC_ADDR_LEN);
169127260Smdodd
170127260Smdodd	}
171127260Smdodd	break;
17289099Sfjoe#endif
17389099Sfjoe#ifdef INET6
17489099Sfjoe	case AF_INET6:
17589099Sfjoe#ifdef OLDIP6OUTPUT
17689099Sfjoe		if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
17789099Sfjoe			return(0);	/* if not yet resolves */
17889099Sfjoe#else
17989099Sfjoe		if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
18089099Sfjoe			return(0); /* it must be impossible, but... */
18189099Sfjoe#endif /* OLDIP6OUTPUT */
18289099Sfjoe		atype = ARCTYPE_INET6;
18389099Sfjoe		break;
18489099Sfjoe#endif
185109771Sfjoe#ifdef IPX
186109771Sfjoe	case AF_IPX:
187109771Sfjoe		adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
188109771Sfjoe		atype = ARCTYPE_IPX;
189109771Sfjoe		if (adst == 0xff)
190109771Sfjoe			adst = arcbroadcastaddr;
191109771Sfjoe		break;
192109771Sfjoe#endif
19389099Sfjoe
19489099Sfjoe	case AF_UNSPEC:
195109771Sfjoe		loop_copy = -1;
19689099Sfjoe		ah = (struct arc_header *)dst->sa_data;
19789099Sfjoe		adst = ah->arc_dhost;
19889099Sfjoe		atype = ah->arc_type;
19989099Sfjoe
20089099Sfjoe		if (atype == ARCTYPE_ARP) {
20189099Sfjoe			atype = (ifp->if_flags & IFF_LINK0) ?
20289099Sfjoe			    ARCTYPE_ARP_OLD: ARCTYPE_ARP;
20389099Sfjoe
20489099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP
20589099Sfjoe			/*
20689099Sfjoe			 * XXX It's not clear per RFC826 if this is needed, but
20789099Sfjoe			 * "assigned numbers" say this is wrong.
20889099Sfjoe			 * However, e.g., AmiTCP 3.0Beta used it... we make this
20989099Sfjoe			 * switchable for emergency cases. Not perfect, but...
21089099Sfjoe			 */
21189099Sfjoe			if (ifp->if_flags & IFF_LINK2)
212109771Sfjoe				mtod(m, struct arphdr *)->ar_pro = atype - 1;
21389099Sfjoe#endif
21489099Sfjoe		}
21589099Sfjoe		break;
21689099Sfjoe
21789099Sfjoe	default:
218105598Sbrooks		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
21989099Sfjoe		senderr(EAFNOSUPPORT);
22089099Sfjoe	}
22189099Sfjoe
222110106Sfjoe	isphds = arc_isphds(atype);
223111119Simp	M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT);
22489099Sfjoe	if (m == 0)
22589099Sfjoe		senderr(ENOBUFS);
22689099Sfjoe	ah = mtod(m, struct arc_header *);
22789099Sfjoe	ah->arc_type = atype;
22889099Sfjoe	ah->arc_dhost = adst;
229110106Sfjoe	ah->arc_shost = ARC_LLADDR(ifp);
230110106Sfjoe	if (isphds) {
231110106Sfjoe		ah->arc_flag = 0;
232110106Sfjoe		ah->arc_seqid = 0;
233110106Sfjoe	}
23489099Sfjoe
235109771Sfjoe	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
236109771Sfjoe		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
237109771Sfjoe			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
238109771Sfjoe
239109771Sfjoe			(void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
240109771Sfjoe		} else if (ah->arc_dhost == ah->arc_shost) {
241109771Sfjoe			(void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
242109771Sfjoe			return (0);     /* XXX */
243109771Sfjoe		}
244109771Sfjoe	}
245109771Sfjoe
246106939Ssam	BPF_MTAP(ifp, m);
24789099Sfjoe
24889099Sfjoe	if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
24989099Sfjoe		m = 0;
25089099Sfjoe		senderr(ENOBUFS);
25189099Sfjoe	}
25289099Sfjoe
25389099Sfjoe	return (error);
25489099Sfjoe
25589099Sfjoebad:
25689099Sfjoe	if (m)
25789099Sfjoe		m_freem(m);
25889099Sfjoe	return (error);
25989099Sfjoe}
26089099Sfjoe
26189099Sfjoevoid
26289099Sfjoearc_frag_init(ifp)
26389099Sfjoe	struct ifnet *ifp;
26489099Sfjoe{
26589099Sfjoe	struct arccom *ac;
26689099Sfjoe
26789099Sfjoe	ac = (struct arccom *)ifp;
26889099Sfjoe	ac->curr_frag = 0;
26989099Sfjoe}
27089099Sfjoe
27189099Sfjoestruct mbuf *
27289099Sfjoearc_frag_next(ifp)
27389099Sfjoe	struct ifnet *ifp;
27489099Sfjoe{
27589099Sfjoe	struct arccom *ac;
27689099Sfjoe	struct mbuf *m;
27789099Sfjoe	struct arc_header *ah;
27889099Sfjoe
27989099Sfjoe	ac = (struct arccom *)ifp;
28089099Sfjoe	if ((m = ac->curr_frag) == 0) {
28189099Sfjoe		int tfrags;
28289099Sfjoe
28389099Sfjoe		/* dequeue new packet */
28489099Sfjoe		IF_DEQUEUE(&ifp->if_snd, m);
28589099Sfjoe		if (m == 0)
28689099Sfjoe			return 0;
28789099Sfjoe
28889099Sfjoe		ah = mtod(m, struct arc_header *);
28989099Sfjoe		if (!arc_isphds(ah->arc_type))
29089099Sfjoe			return m;
29189099Sfjoe
29289099Sfjoe		++ac->ac_seqid;		/* make the seqid unique */
293109771Sfjoe		tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
29489099Sfjoe		ac->fsflag = 2 * tfrags - 3;
29589099Sfjoe		ac->sflag = 0;
29689099Sfjoe		ac->rsflag = ac->fsflag;
29789099Sfjoe		ac->arc_dhost = ah->arc_dhost;
29889099Sfjoe		ac->arc_shost = ah->arc_shost;
29989099Sfjoe		ac->arc_type = ah->arc_type;
30089099Sfjoe
301110106Sfjoe		m_adj(m, ARC_HDRNEWLEN);
30289099Sfjoe		ac->curr_frag = m;
30389099Sfjoe	}
30489099Sfjoe
30589099Sfjoe	/* split out next fragment and return it */
30689099Sfjoe	if (ac->sflag < ac->fsflag) {
30789099Sfjoe		/* we CAN'T have short packets here */
308111119Simp		ac->curr_frag = m_split(m, ARC_MAX_DATA, M_DONTWAIT);
30989099Sfjoe		if (ac->curr_frag == 0) {
31093750Sluigi			m_freem(m);
31189099Sfjoe			return 0;
31289099Sfjoe		}
31389099Sfjoe
314111119Simp		M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
31589099Sfjoe		if (m == 0) {
31693750Sluigi			m_freem(ac->curr_frag);
31789099Sfjoe			ac->curr_frag = 0;
31889099Sfjoe			return 0;
31989099Sfjoe		}
32089099Sfjoe
32189099Sfjoe		ah = mtod(m, struct arc_header *);
32289099Sfjoe		ah->arc_flag = ac->rsflag;
32389099Sfjoe		ah->arc_seqid = ac->ac_seqid;
32489099Sfjoe
32589099Sfjoe		ac->sflag += 2;
32689099Sfjoe		ac->rsflag = ac->sflag;
32789099Sfjoe	} else if ((m->m_pkthdr.len >=
32889099Sfjoe	    ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
32989099Sfjoe	    (m->m_pkthdr.len <=
33089099Sfjoe	    ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
33189099Sfjoe		ac->curr_frag = 0;
33289099Sfjoe
333111119Simp		M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
33489099Sfjoe		if (m == 0)
33589099Sfjoe			return 0;
33689099Sfjoe
33789099Sfjoe		ah = mtod(m, struct arc_header *);
33889099Sfjoe		ah->arc_flag = 0xFF;
33989099Sfjoe		ah->arc_seqid = 0xFFFF;
34089099Sfjoe		ah->arc_type2 = ac->arc_type;
34189099Sfjoe		ah->arc_flag2 = ac->sflag;
34289099Sfjoe		ah->arc_seqid2 = ac->ac_seqid;
34389099Sfjoe	} else {
34489099Sfjoe		ac->curr_frag = 0;
34589099Sfjoe
346111119Simp		M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
34789099Sfjoe		if (m == 0)
34889099Sfjoe			return 0;
34989099Sfjoe
35089099Sfjoe		ah = mtod(m, struct arc_header *);
35189099Sfjoe		ah->arc_flag = ac->sflag;
35289099Sfjoe		ah->arc_seqid = ac->ac_seqid;
35389099Sfjoe	}
35489099Sfjoe
35589099Sfjoe	ah->arc_dhost = ac->arc_dhost;
35689099Sfjoe	ah->arc_shost = ac->arc_shost;
35789099Sfjoe	ah->arc_type = ac->arc_type;
35889099Sfjoe
35989099Sfjoe	return m;
36089099Sfjoe}
36189099Sfjoe
36289099Sfjoe/*
36389099Sfjoe * Defragmenter. Returns mbuf if last packet found, else
36489099Sfjoe * NULL. frees imcoming mbuf as necessary.
36589099Sfjoe */
36689099Sfjoe
367105228Sphkstatic __inline struct mbuf *
36889099Sfjoearc_defrag(ifp, m)
36989099Sfjoe	struct ifnet *ifp;
37089099Sfjoe	struct mbuf *m;
37189099Sfjoe{
37289099Sfjoe	struct arc_header *ah, *ah1;
37389099Sfjoe	struct arccom *ac;
37489099Sfjoe	struct ac_frag *af;
37589099Sfjoe	struct mbuf *m1;
37689099Sfjoe	char *s;
37789099Sfjoe	int newflen;
37889099Sfjoe	u_char src,dst,typ;
37989099Sfjoe
38089099Sfjoe	ac = (struct arccom *)ifp;
38189099Sfjoe
38289099Sfjoe	if (m->m_len < ARC_HDRNEWLEN) {
38389099Sfjoe		m = m_pullup(m, ARC_HDRNEWLEN);
38489099Sfjoe		if (m == NULL) {
38589099Sfjoe			++ifp->if_ierrors;
38689099Sfjoe			return NULL;
38789099Sfjoe		}
38889099Sfjoe	}
38989099Sfjoe
39089099Sfjoe	ah = mtod(m, struct arc_header *);
39189099Sfjoe	typ = ah->arc_type;
39289099Sfjoe
39389099Sfjoe	if (!arc_isphds(typ))
39489099Sfjoe		return m;
39589099Sfjoe
39689099Sfjoe	src = ah->arc_shost;
39789099Sfjoe	dst = ah->arc_dhost;
39889099Sfjoe
39989099Sfjoe	if (ah->arc_flag == 0xff) {
40089099Sfjoe		m_adj(m, 4);
40189099Sfjoe
40289099Sfjoe		if (m->m_len < ARC_HDRNEWLEN) {
40389099Sfjoe			m = m_pullup(m, ARC_HDRNEWLEN);
40489099Sfjoe			if (m == NULL) {
40589099Sfjoe				++ifp->if_ierrors;
40689099Sfjoe				return NULL;
40789099Sfjoe			}
40889099Sfjoe		}
40989099Sfjoe
41089099Sfjoe		ah = mtod(m, struct arc_header *);
41189099Sfjoe	}
41289099Sfjoe
41389099Sfjoe	af = &ac->ac_fragtab[src];
41489099Sfjoe	m1 = af->af_packet;
41589099Sfjoe	s = "debug code error";
41689099Sfjoe
41789099Sfjoe	if (ah->arc_flag & 1) {
41889099Sfjoe		/*
41989099Sfjoe		 * first fragment. We always initialize, which is
42089099Sfjoe		 * about the right thing to do, as we only want to
42189099Sfjoe		 * accept one fragmented packet per src at a time.
42289099Sfjoe		 */
42389099Sfjoe		if (m1 != NULL)
42489099Sfjoe			m_freem(m1);
42589099Sfjoe
42689099Sfjoe		af->af_packet = m;
42789099Sfjoe		m1 = m;
42889099Sfjoe		af->af_maxflag = ah->arc_flag;
42989099Sfjoe		af->af_lastseen = 0;
43089099Sfjoe		af->af_seqid = ah->arc_seqid;
43189099Sfjoe
43289099Sfjoe		return NULL;
43389099Sfjoe		/* notreached */
43489099Sfjoe	} else {
43589099Sfjoe		/* check for unfragmented packet */
43689099Sfjoe		if (ah->arc_flag == 0)
43789099Sfjoe			return m;
43889099Sfjoe
43989099Sfjoe		/* do we have a first packet from that src? */
44089099Sfjoe		if (m1 == NULL) {
44189099Sfjoe			s = "no first frag";
44289099Sfjoe			goto outofseq;
44389099Sfjoe		}
44489099Sfjoe
44589099Sfjoe		ah1 = mtod(m1, struct arc_header *);
44689099Sfjoe
44789099Sfjoe		if (ah->arc_seqid != ah1->arc_seqid) {
44889099Sfjoe			s = "seqid differs";
44989099Sfjoe			goto outofseq;
45089099Sfjoe		}
45189099Sfjoe
45289099Sfjoe		if (typ != ah1->arc_type) {
45389099Sfjoe			s = "type differs";
45489099Sfjoe			goto outofseq;
45589099Sfjoe		}
45689099Sfjoe
45789099Sfjoe		if (dst != ah1->arc_dhost) {
45889099Sfjoe			s = "dest host differs";
45989099Sfjoe			goto outofseq;
46089099Sfjoe		}
46189099Sfjoe
46289099Sfjoe		/* typ, seqid and dst are ok here. */
46389099Sfjoe
46489099Sfjoe		if (ah->arc_flag == af->af_lastseen) {
46589099Sfjoe			m_freem(m);
46689099Sfjoe			return NULL;
46789099Sfjoe		}
46889099Sfjoe
46989099Sfjoe		if (ah->arc_flag == af->af_lastseen + 2) {
47089099Sfjoe			/* ok, this is next fragment */
47189099Sfjoe			af->af_lastseen = ah->arc_flag;
47289099Sfjoe			m_adj(m,ARC_HDRNEWLEN);
47389099Sfjoe
47489099Sfjoe			/*
47589099Sfjoe			 * m_cat might free the first mbuf (with pkthdr)
47689099Sfjoe			 * in 2nd chain; therefore:
47789099Sfjoe			 */
47889099Sfjoe
47989099Sfjoe			newflen = m->m_pkthdr.len;
48089099Sfjoe
48189099Sfjoe			m_cat(m1,m);
48289099Sfjoe
48389099Sfjoe			m1->m_pkthdr.len += newflen;
48489099Sfjoe
48589099Sfjoe			/* is it the last one? */
48689099Sfjoe			if (af->af_lastseen > af->af_maxflag) {
48789099Sfjoe				af->af_packet = NULL;
48889099Sfjoe				return(m1);
48989099Sfjoe			} else
49089099Sfjoe				return NULL;
49189099Sfjoe		}
49289099Sfjoe		s = "other reason";
49389099Sfjoe		/* if all else fails, it is out of sequence, too */
49489099Sfjoe	}
49589099Sfjoeoutofseq:
49689099Sfjoe	if (m1) {
49789099Sfjoe		m_freem(m1);
49889099Sfjoe		af->af_packet = NULL;
49989099Sfjoe	}
50089099Sfjoe
50189099Sfjoe	if (m)
50289099Sfjoe		m_freem(m);
50389099Sfjoe
504121816Sbrooks	log(LOG_INFO,"%s: got out of seq. packet: %s\n",
505121816Sbrooks	    ifp->if_xname, s);
50689099Sfjoe
50789099Sfjoe	return NULL;
50889099Sfjoe}
50989099Sfjoe
51089099Sfjoe/*
51189099Sfjoe * return 1 if Packet Header Definition Standard, else 0.
51289099Sfjoe * For now: old IP, old ARP aren't obviously. Lacking correct information,
51389099Sfjoe * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
51489099Sfjoe * (Apple and Novell corporations were involved, among others, in PHDS work).
51589099Sfjoe * Easiest is to assume that everybody else uses that, too.
51689099Sfjoe */
51789099Sfjoeint
51889099Sfjoearc_isphds(type)
51989099Sfjoe	u_int8_t type;
52089099Sfjoe{
52189099Sfjoe	return (type != ARCTYPE_IP_OLD &&
52289099Sfjoe		type != ARCTYPE_ARP_OLD &&
52389099Sfjoe		type != ARCTYPE_DIAGNOSE);
52489099Sfjoe}
52589099Sfjoe
52689099Sfjoe/*
52789099Sfjoe * Process a received Arcnet packet;
52889099Sfjoe * the packet is in the mbuf chain m with
52989099Sfjoe * the ARCnet header.
53089099Sfjoe */
53189099Sfjoevoid
53289099Sfjoearc_input(ifp, m)
53389099Sfjoe	struct ifnet *ifp;
53489099Sfjoe	struct mbuf *m;
53589099Sfjoe{
53689099Sfjoe	struct arc_header *ah;
537111888Sjlemon	int isr;
53889099Sfjoe	u_int8_t atype;
53989099Sfjoe
54089099Sfjoe	if ((ifp->if_flags & IFF_UP) == 0) {
54189099Sfjoe		m_freem(m);
54289099Sfjoe		return;
54389099Sfjoe	}
54489099Sfjoe
54589099Sfjoe	/* possibly defragment: */
54689099Sfjoe	m = arc_defrag(ifp, m);
54789099Sfjoe	if (m == NULL)
54889099Sfjoe		return;
54989099Sfjoe
550106939Ssam	BPF_MTAP(ifp, m);
55189099Sfjoe
55289099Sfjoe	ah = mtod(m, struct arc_header *);
553109771Sfjoe	/* does this belong to us? */
554110106Sfjoe	if ((ifp->if_flags & IFF_PROMISC) == 0
555109771Sfjoe	    && ah->arc_dhost != arcbroadcastaddr
556110106Sfjoe	    && ah->arc_dhost != ARC_LLADDR(ifp)) {
557109771Sfjoe		m_freem(m);
558109771Sfjoe		return;
559109771Sfjoe	}
56089099Sfjoe
56189099Sfjoe	ifp->if_ibytes += m->m_pkthdr.len;
56289099Sfjoe
563109771Sfjoe	if (ah->arc_dhost == arcbroadcastaddr) {
56489099Sfjoe		m->m_flags |= M_BCAST|M_MCAST;
56589099Sfjoe		ifp->if_imcasts++;
56689099Sfjoe	}
56789099Sfjoe
56889099Sfjoe	atype = ah->arc_type;
56989099Sfjoe	switch (atype) {
57089099Sfjoe#ifdef INET
57189099Sfjoe	case ARCTYPE_IP:
57289099Sfjoe		m_adj(m, ARC_HDRNEWLEN);
573122702Sandre		if (ip_fastforward(m))
574109771Sfjoe			return;
575111888Sjlemon		isr = NETISR_IP;
57689099Sfjoe		break;
57789099Sfjoe
57889099Sfjoe	case ARCTYPE_IP_OLD:
57989099Sfjoe		m_adj(m, ARC_HDRLEN);
580122702Sandre		if (ip_fastforward(m))
581109771Sfjoe			return;
582111888Sjlemon		isr = NETISR_IP;
58389099Sfjoe		break;
58489099Sfjoe
58589099Sfjoe	case ARCTYPE_ARP:
58689099Sfjoe		if (ifp->if_flags & IFF_NOARP) {
58789099Sfjoe			/* Discard packet if ARP is disabled on interface */
58889099Sfjoe			m_freem(m);
58989099Sfjoe			return;
59089099Sfjoe		}
59189099Sfjoe		m_adj(m, ARC_HDRNEWLEN);
592111888Sjlemon		isr = NETISR_ARP;
59389099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP
59489099Sfjoe		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
59589099Sfjoe#endif
59689099Sfjoe		break;
59789099Sfjoe
59889099Sfjoe	case ARCTYPE_ARP_OLD:
59989099Sfjoe		if (ifp->if_flags & IFF_NOARP) {
60089099Sfjoe			/* Discard packet if ARP is disabled on interface */
60189099Sfjoe			m_freem(m);
60289099Sfjoe			return;
60389099Sfjoe		}
60489099Sfjoe		m_adj(m, ARC_HDRLEN);
605111888Sjlemon		isr = NETISR_ARP;
60689099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP
60789099Sfjoe		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
60889099Sfjoe#endif
60989099Sfjoe		break;
61089099Sfjoe#endif
61189099Sfjoe#ifdef INET6
61289099Sfjoe	case ARCTYPE_INET6:
61389099Sfjoe		m_adj(m, ARC_HDRNEWLEN);
614111888Sjlemon		isr = NETISR_IPV6;
61589099Sfjoe		break;
61689099Sfjoe#endif
617109771Sfjoe#ifdef IPX
618109771Sfjoe	case ARCTYPE_IPX:
619109771Sfjoe		m_adj(m, ARC_HDRNEWLEN);
620111888Sjlemon		isr = NETISR_IPX;
621109771Sfjoe		break;
622109771Sfjoe#endif
62389099Sfjoe	default:
62489099Sfjoe		m_freem(m);
62589099Sfjoe		return;
62689099Sfjoe	}
627111888Sjlemon	netisr_dispatch(isr, m);
62889099Sfjoe}
62989099Sfjoe
63089099Sfjoe/*
63189099Sfjoe * Register (new) link level address.
63289099Sfjoe */
63389099Sfjoevoid
63489099Sfjoearc_storelladdr(ifp, lla)
63589099Sfjoe	struct ifnet *ifp;
63689099Sfjoe	u_int8_t lla;
63789099Sfjoe{
638110106Sfjoe	ARC_LLADDR(ifp) = lla;
63989099Sfjoe}
64089099Sfjoe
64189099Sfjoe/*
64289099Sfjoe * Perform common duties while attaching to interface list
64389099Sfjoe */
64489099Sfjoevoid
64589099Sfjoearc_ifattach(ifp, lla)
64689099Sfjoe	struct ifnet *ifp;
64789099Sfjoe	u_int8_t lla;
64889099Sfjoe{
64989099Sfjoe	struct ifaddr *ifa;
65089099Sfjoe	struct sockaddr_dl *sdl;
65189099Sfjoe	struct arccom *ac;
65289099Sfjoe
65389099Sfjoe	if_attach(ifp);
65489099Sfjoe	ifp->if_type = IFT_ARCNET;
65589099Sfjoe	ifp->if_addrlen = 1;
65689099Sfjoe	ifp->if_hdrlen = ARC_HDRLEN;
65789099Sfjoe	ifp->if_mtu = 1500;
658109771Sfjoe	ifp->if_resolvemulti = arc_resolvemulti;
65989099Sfjoe	if (ifp->if_baudrate == 0)
66089099Sfjoe		ifp->if_baudrate = 2500000;
66189099Sfjoe#if __FreeBSD_version < 500000
66289099Sfjoe	ifa = ifnet_addrs[ifp->if_index - 1];
66389099Sfjoe#else
66489099Sfjoe	ifa = ifaddr_byindex(ifp->if_index);
66589099Sfjoe#endif
66689099Sfjoe	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
66789099Sfjoe	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
66889099Sfjoe	sdl->sdl_type = IFT_ARCNET;
66989099Sfjoe	sdl->sdl_alen = ifp->if_addrlen;
67089099Sfjoe
67189099Sfjoe	if (ifp->if_flags & IFF_BROADCAST)
67289099Sfjoe		ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
67389099Sfjoe
67489099Sfjoe	ac = (struct arccom *)ifp;
67589099Sfjoe	ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
67689099Sfjoe	if (lla == 0) {
67789099Sfjoe		/* XXX this message isn't entirely clear, to me -- cgd */
678121816Sbrooks		log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
679121816Sbrooks		   ifp->if_xname, ifp->if_xname);
68089099Sfjoe	}
68189099Sfjoe	arc_storelladdr(ifp, lla);
68289099Sfjoe
68389099Sfjoe	ifp->if_broadcastaddr = &arcbroadcastaddr;
68489099Sfjoe
68589099Sfjoe	bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
68689099Sfjoe}
68789099Sfjoe
68889099Sfjoevoid
68989099Sfjoearc_ifdetach(ifp)
69089099Sfjoe	struct ifnet *ifp;
69189099Sfjoe{
69289099Sfjoe	bpfdetach(ifp);
69389099Sfjoe	if_detach(ifp);
69489099Sfjoe}
69589099Sfjoe
69689099Sfjoeint
69789099Sfjoearc_ioctl(ifp, command, data)
69889099Sfjoe	struct ifnet *ifp;
69989099Sfjoe	int command;
70089099Sfjoe	caddr_t data;
70189099Sfjoe{
70289099Sfjoe	struct ifaddr *ifa = (struct ifaddr *) data;
70389099Sfjoe	struct ifreq *ifr = (struct ifreq *) data;
70489099Sfjoe	int error = 0;
70589099Sfjoe
70689099Sfjoe	switch (command) {
70789099Sfjoe	case SIOCSIFADDR:
70889099Sfjoe		ifp->if_flags |= IFF_UP;
70989099Sfjoe		switch (ifa->ifa_addr->sa_family) {
71089099Sfjoe#ifdef INET
71189099Sfjoe		case AF_INET:
71289099Sfjoe			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
71389099Sfjoe			arp_ifinit(ifp, ifa);
71489099Sfjoe			break;
71589099Sfjoe#endif
716109771Sfjoe#ifdef IPX
717109771Sfjoe		/*
718109771Sfjoe		 * XXX This code is probably wrong
719109771Sfjoe		 */
720109771Sfjoe		case AF_IPX:
721109771Sfjoe		{
722109771Sfjoe			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
723109771Sfjoe
724109771Sfjoe			if (ipx_nullhost(*ina))
725110106Sfjoe				ina->x_host.c_host[5] = ARC_LLADDR(ifp);
726109771Sfjoe			else
727109771Sfjoe				arc_storelladdr(ifp, ina->x_host.c_host[5]);
728109771Sfjoe
729109771Sfjoe			/*
730109771Sfjoe			 * Set new address
731109771Sfjoe			 */
732109771Sfjoe			ifp->if_init(ifp->if_softc);
733109771Sfjoe			break;
734109771Sfjoe		}
735109771Sfjoe#endif
73689099Sfjoe		default:
73789099Sfjoe			ifp->if_init(ifp->if_softc);
73889099Sfjoe			break;
73989099Sfjoe		}
74089099Sfjoe		break;
74189099Sfjoe
742109771Sfjoe	case SIOCGIFADDR:
743109771Sfjoe		{
744109771Sfjoe			struct sockaddr *sa;
745109771Sfjoe
746109771Sfjoe			sa = (struct sockaddr *) &ifr->ifr_data;
747110106Sfjoe			*(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
748109771Sfjoe		}
749109771Sfjoe		break;
750109771Sfjoe
75189099Sfjoe	case SIOCADDMULTI:
75289099Sfjoe	case SIOCDELMULTI:
75389099Sfjoe		if (ifr == NULL)
75489099Sfjoe			error = EAFNOSUPPORT;
75589099Sfjoe		else {
75689099Sfjoe			switch (ifr->ifr_addr.sa_family) {
75789099Sfjoe			case AF_INET:
75889099Sfjoe			case AF_INET6:
75989099Sfjoe				error = 0;
76089099Sfjoe				break;
76189099Sfjoe			default:
76289099Sfjoe				error = EAFNOSUPPORT;
76389099Sfjoe				break;
76489099Sfjoe			}
76589099Sfjoe		}
76689099Sfjoe		break;
76789099Sfjoe
76889099Sfjoe	case SIOCSIFMTU:
76989099Sfjoe		/*
77089099Sfjoe		 * Set the interface MTU.
77189099Sfjoe		 * mtu can't be larger than ARCMTU for RFC1051
77289099Sfjoe		 * and can't be larger than ARC_PHDS_MTU
77389099Sfjoe		 */
77489099Sfjoe		if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
77589099Sfjoe		    ifr->ifr_mtu > ARC_PHDS_MAXMTU)
77689099Sfjoe			error = EINVAL;
77789099Sfjoe		else
77889099Sfjoe			ifp->if_mtu = ifr->ifr_mtu;
77989099Sfjoe		break;
780109771Sfjoe	}
78189099Sfjoe
782109771Sfjoe	return (error);
783109771Sfjoe}
78489099Sfjoe
785109771Sfjoe/* based on ether_resolvemulti() */
786109771Sfjoeint
787109771Sfjoearc_resolvemulti(ifp, llsa, sa)
788109771Sfjoe	struct ifnet *ifp;
789109771Sfjoe	struct sockaddr **llsa;
790109771Sfjoe	struct sockaddr *sa;
791109771Sfjoe{
792109771Sfjoe	struct sockaddr_dl *sdl;
793109771Sfjoe	struct sockaddr_in *sin;
794109771Sfjoe#ifdef INET6
795109771Sfjoe	struct sockaddr_in6 *sin6;
796109771Sfjoe#endif
797109771Sfjoe
798109771Sfjoe	switch(sa->sa_family) {
799109771Sfjoe	case AF_LINK:
800109771Sfjoe		/*
801109771Sfjoe		* No mapping needed. Just check that it's a valid MC address.
802109771Sfjoe		*/
803109771Sfjoe		sdl = (struct sockaddr_dl *)sa;
804109771Sfjoe		if (*LLADDR(sdl) != arcbroadcastaddr)
805109771Sfjoe			return EADDRNOTAVAIL;
806109771Sfjoe		*llsa = 0;
807109771Sfjoe		return 0;
808109771Sfjoe#ifdef INET
809109771Sfjoe	case AF_INET:
810109771Sfjoe		sin = (struct sockaddr_in *)sa;
811109771Sfjoe		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
812109771Sfjoe			return EADDRNOTAVAIL;
813109771Sfjoe		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
814109771Sfjoe		       M_ZERO);
815109771Sfjoe		sdl->sdl_len = sizeof *sdl;
816109771Sfjoe		sdl->sdl_family = AF_LINK;
817109771Sfjoe		sdl->sdl_index = ifp->if_index;
818109771Sfjoe		sdl->sdl_type = IFT_ARCNET;
819109771Sfjoe		sdl->sdl_alen = ARC_ADDR_LEN;
820109771Sfjoe		*LLADDR(sdl) = 0;
821109771Sfjoe		*llsa = (struct sockaddr *)sdl;
822109771Sfjoe		return 0;
823109771Sfjoe#endif
824109771Sfjoe#ifdef INET6
825109771Sfjoe	case AF_INET6:
826109771Sfjoe		sin6 = (struct sockaddr_in6 *)sa;
827109771Sfjoe		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
828109771Sfjoe			/*
829109771Sfjoe			 * An IP6 address of 0 means listen to all
830109771Sfjoe			 * of the Ethernet multicast address used for IP6.
831109771Sfjoe			 * (This is used for multicast routers.)
832109771Sfjoe			 */
833109771Sfjoe			ifp->if_flags |= IFF_ALLMULTI;
834109771Sfjoe			*llsa = 0;
835109771Sfjoe			return 0;
83689099Sfjoe		}
837109771Sfjoe		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
838109771Sfjoe			return EADDRNOTAVAIL;
839109771Sfjoe		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
840109771Sfjoe		       M_ZERO);
841109771Sfjoe		sdl->sdl_len = sizeof *sdl;
842109771Sfjoe		sdl->sdl_family = AF_LINK;
843109771Sfjoe		sdl->sdl_index = ifp->if_index;
844109771Sfjoe		sdl->sdl_type = IFT_ARCNET;
845109771Sfjoe		sdl->sdl_alen = ARC_ADDR_LEN;
846109771Sfjoe		*LLADDR(sdl) = 0;
847109771Sfjoe		*llsa = (struct sockaddr *)sdl;
848109771Sfjoe		return 0;
84989099Sfjoe#endif
850109771Sfjoe
851109771Sfjoe	default:
852109771Sfjoe		/*
853109771Sfjoe		 * Well, the text isn't quite right, but it's the name
854109771Sfjoe		 * that counts...
855109771Sfjoe		 */
856109771Sfjoe		return EAFNOSUPPORT;
85789099Sfjoe	}
85889099Sfjoe}
859