if_arcsubr.c revision 109771
1139804Simp/*	$NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $	*/
213675Sdyson/*	$FreeBSD: head/sys/net/if_arcsubr.c 109771 2003-01-24 01:32:20Z fjoe $ */
3232055Skmacy
413675Sdyson/*
513675Sdyson * Copyright (c) 1994, 1995 Ignatios Souvatzis
613675Sdyson * Copyright (c) 1982, 1989, 1993
713675Sdyson *	The Regents of the University of California.  All rights reserved.
813675Sdyson *
913675Sdyson * Redistribution and use in source and binary forms, with or without
1013675Sdyson * modification, are permitted provided that the following conditions
1113675Sdyson * are met:
1213675Sdyson * 1. Redistributions of source code must retain the above copyright
1313675Sdyson *    notice, this list of conditions and the following disclaimer.
1413675Sdyson * 2. Redistributions in binary form must reproduce the above copyright
1513675Sdyson *    notice, this list of conditions and the following disclaimer in the
1613675Sdyson *    documentation and/or other materials provided with the distribution.
1714037Sdyson * 3. All advertising materials mentioning features or use of this software
1813675Sdyson *    must display the following acknowledgement:
1913675Sdyson *	This product includes software developed by the University of
2013675Sdyson *	California, Berkeley and its contributors.
2113675Sdyson * 4. Neither the name of the University nor the names of its contributors
2213675Sdyson *    may be used to endorse or promote products derived from this software
2313675Sdyson *    without specific prior written permission.
2413675Sdyson *
2513675Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2613675Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2713675Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2813907Sdyson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2913907Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3013907Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3113907Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3213907Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33219801Salc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34219801Salc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35219801Salc * SUCH DAMAGE.
3613907Sdyson *
3713907Sdyson * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
3813913Sdyson *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
3913907Sdyson *
4013907Sdyson */
4113907Sdyson#include "opt_inet.h"
4213907Sdyson#include "opt_inet6.h"
4313907Sdyson#include "opt_ipx.h"
4413907Sdyson
4513907Sdyson#include <sys/param.h>
4613907Sdyson#include <sys/systm.h>
47118764Ssilby#include <sys/kernel.h>
48117325Ssilby#include <sys/malloc.h>
49118764Ssilby#include <sys/mbuf.h>
50117325Ssilby#include <sys/protosw.h>
51118764Ssilby#include <sys/socket.h>
52133790Ssilby#include <sys/sockio.h>
53133790Ssilby#include <sys/errno.h>
54117325Ssilby#include <sys/syslog.h>
55133790Ssilby
56133790Ssilby#include <machine/cpu.h>
57117325Ssilby
58133790Ssilby#include <net/if.h>
59133790Ssilby#include <net/netisr.h>
60117325Ssilby#include <net/route.h>
61133790Ssilby#include <net/if_dl.h>
62133790Ssilby#include <net/if_types.h>
63133790Ssilby#include <net/if_arc.h>
64133790Ssilby#include <net/if_arp.h>
65133790Ssilby#include <net/bpf.h>
66133790Ssilby
67133790Ssilby#if defined(INET) || defined(INET6)
68133790Ssilby#include <netinet/in.h>
69133790Ssilby#include <netinet/in_var.h>
70133049Ssilby#include <netinet/if_ether.h>
71133790Ssilby#endif
72133790Ssilby
73133790Ssilby#ifdef INET6
74133790Ssilby#include <netinet6/nd6.h>
75133790Ssilby#endif
76133790Ssilby
77133790Ssilby#ifdef IPX
78133790Ssilby#include <netipx/ipx.h>
79133790Ssilby#include <netipx/ipx_if.h>
80133049Ssilby#endif
81133049Ssilby
82133049SsilbyMODULE_VERSION(arcnet, 1);
83133049Ssilby
84133790Ssilby#define ARCNET_ALLOW_BROKEN_ARP
85133790Ssilby
86133049Ssilbystatic struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
87133049Ssilbystatic int arc_resolvemulti(struct ifnet *, struct sockaddr **,
88133049Ssilby			    struct sockaddr *);
89133049Ssilby
9013907Sdysonu_int8_t  arcbroadcastaddr = 0;
9113907Sdyson
92116182Sobrien#define senderr(e) { error = (e); goto bad;}
93116182Sobrien#define SIN(s)	((struct sockaddr_in *)s)
94116182Sobrien#define SIPX(s)	((struct sockaddr_ipx *)s)
9513675Sdyson
9613675Sdyson/*
97226042Skib * ARCnet output routine.
9824131Sbde * Encapsulate a packet of type family for the local net.
9913675Sdyson * Assumes that ifp is actually pointer to arccom structure.
10013675Sdyson */
10124206Sbdeint
10291372Salfredarc_output(ifp, m, dst, rt0)
10376166Smarkm	struct ifnet *ifp;
10476827Salfred	struct mbuf *m;
10524206Sbde	struct sockaddr *dst;
10613675Sdyson	struct rtentry *rt0;
10791968Salfred{
10829356Speter	struct rtentry		*rt;
10970834Swollman	struct arccom		*ac;
11013675Sdyson	struct arc_header	*ah;
111184849Sed	int			error;
112117325Ssilby	u_int8_t		atype, adst;
11313675Sdyson	int			loop_copy = 0;
11413675Sdyson
11576166Smarkm	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
11655112Sbde		return(ENETDOWN); /* m, m1 aren't initialized yet */
11734924Sbde
11859288Sjlemon	error = 0;
11913675Sdyson	ac = (struct arccom *)ifp;
120163606Srwatson
121163606Srwatson	if ((rt = rt0)) {
12213675Sdyson		if ((rt->rt_flags & RTF_UP) == 0) {
12313675Sdyson			if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
12413675Sdyson				rt->rt_refcnt--;
12513675Sdyson			else
12613675Sdyson				senderr(EHOSTUNREACH);
12713675Sdyson		}
12813675Sdyson		if (rt->rt_flags & RTF_GATEWAY) {
12913907Sdyson			if (rt->rt_gwroute == 0)
13092751Sjeff				goto lookup;
13113675Sdyson			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
132232055Skmacy				rtfree(rt); rt = rt0;
133232055Skmacy			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
13414037Sdyson				if ((rt = rt->rt_gwroute) == 0)
13514037Sdyson					senderr(EHOSTUNREACH);
13614037Sdyson			}
13714037Sdyson		}
13814037Sdyson		if (rt->rt_flags & RTF_REJECT)
13914037Sdyson			if (rt->rt_rmx.rmx_expire == 0 ||
14014037Sdyson			    time_second < rt->rt_rmx.rmx_expire)
141232055Skmacy				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
142232055Skmacy	}
143232055Skmacy
14414037Sdyson	switch (dst->sa_family) {
14514037Sdyson#ifdef INET
14614037Sdyson	case AF_INET:
147108255Sphk
148108255Sphk		/*
149175140Sjhb		 * For now, use the simple IP addr -> ARCnet addr mapping
150108255Sphk		 */
151108255Sphk		if (m->m_flags & (M_BCAST|M_MCAST))
152108255Sphk			adst = arcbroadcastaddr; /* ARCnet broadcast address */
153108255Sphk		else if (ifp->if_flags & IFF_NOARP)
154108255Sphk			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
155232183Sjilles		else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
156232183Sjilles			return 0;	/* not resolved yet */
15713675Sdyson
158232055Skmacy		atype = (ifp->if_flags & IFF_LINK0) ?
159116546Sphk			ARCTYPE_IP_OLD : ARCTYPE_IP;
160116546Sphk		break;
161175140Sjhb#endif
162116546Sphk#ifdef INET6
163116546Sphk	case AF_INET6:
164116546Sphk#ifdef OLDIP6OUTPUT
165116546Sphk		if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
166116546Sphk			return(0);	/* if not yet resolves */
167232183Sjilles#else
168232183Sjilles		if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
169116546Sphk			return(0); /* it must be impossible, but... */
17072521Sjlemon#endif /* OLDIP6OUTPUT */
17113675Sdyson		atype = ARCTYPE_INET6;
17259288Sjlemon		break;
173232055Skmacy#endif
174232055Skmacy#ifdef IPX
17559288Sjlemon	case AF_IPX:
17659288Sjlemon		adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
17759288Sjlemon		atype = ARCTYPE_IPX;
178232055Skmacy		if (adst == 0xff)
179232055Skmacy			adst = arcbroadcastaddr;
180232055Skmacy		break;
181232055Skmacy#endif
182232055Skmacy
183197134Srwatson	case AF_UNSPEC:
184197134Srwatson		loop_copy = -1;
185197134Srwatson		ah = (struct arc_header *)dst->sa_data;
186197134Srwatson		adst = ah->arc_dhost;
187197134Srwatson		atype = ah->arc_type;
188197134Srwatson
189197134Srwatson		if (atype == ARCTYPE_ARP) {
190197134Srwatson			atype = (ifp->if_flags & IFF_LINK0) ?
191197134Srwatson			    ARCTYPE_ARP_OLD: ARCTYPE_ARP;
192197134Srwatson
19359288Sjlemon#ifdef ARCNET_ALLOW_BROKEN_ARP
19413675Sdyson			/*
19513675Sdyson			 * XXX It's not clear per RFC826 if this is needed, but
19613675Sdyson			 * "assigned numbers" say this is wrong.
19713675Sdyson			 * However, e.g., AmiTCP 3.0Beta used it... we make this
19813675Sdyson			 * switchable for emergency cases. Not perfect, but...
19913675Sdyson			 */
20013907Sdyson			if (ifp->if_flags & IFF_LINK2)
20113907Sdyson				mtod(m, struct arphdr *)->ar_pro = atype - 1;
20213675Sdyson#endif
203189649Sjhb		}
204133790Ssilby		break;
205133790Ssilby
206133790Ssilby	default:
207133790Ssilby		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
20813907Sdyson		senderr(EAFNOSUPPORT);
209189649Sjhb	}
210117325Ssilby
211189649Sjhb	M_PREPEND(m, ARC_HDRLEN, M_NOWAIT);
212117325Ssilby	if (m == 0)
213133790Ssilby		senderr(ENOBUFS);
214133790Ssilby	ah = mtod(m, struct arc_header *);
215133790Ssilby	ah->arc_type = atype;
216133790Ssilby	ah->arc_dhost = adst;
217133790Ssilby	ah->arc_shost = *IF_LLADDR(ifp);
218133790Ssilby
219133790Ssilby	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
220133790Ssilby		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
221117325Ssilby			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
22291413Salfred
22391413Salfred			(void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
22491413Salfred		} else if (ah->arc_dhost == ah->arc_shost) {
225133790Ssilby			(void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
226232055Skmacy			return (0);     /* XXX */
22791413Salfred		}
22891413Salfred	}
22991413Salfred
23014037Sdyson	BPF_MTAP(ifp, m);
23191413Salfred
23291413Salfred	if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
23391413Salfred		m = 0;
23491413Salfred		senderr(ENOBUFS);
23514037Sdyson	}
23691413Salfred
237132579Srwatson	return (error);
23813675Sdyson
239132987Sgreenbad:
240132987Sgreen	if (m)
241125293Srwatson		m_freem(m);
242125293Srwatson	return (error);
24392751Sjeff}
244226042Skib
245226042Skibvoid
24627899Sdysonarc_frag_init(ifp)
24791372Salfred	struct ifnet *ifp;
24891372Salfred{
24991372Salfred	struct arccom *ac;
25091372Salfred
25191372Salfred	ac = (struct arccom *)ifp;
252118880Salc	ac->curr_frag = 0;
253170022Srwatson}
254170022Srwatson
255125293Srwatsonstruct mbuf *
256118880Salcarc_frag_next(ifp)
257226042Skib	struct ifnet *ifp;
258226042Skib{
259226042Skib	struct arccom *ac;
260226042Skib	struct mbuf *m;
26191372Salfred	struct arc_header *ah;
26291372Salfred
263132987Sgreen	ac = (struct arccom *)ifp;
264132987Sgreen	if ((m = ac->curr_frag) == 0) {
265125293Srwatson		int tfrags;
266125293Srwatson
267125293Srwatson		/* dequeue new packet */
268125293Srwatson		IF_DEQUEUE(&ifp->if_snd, m);
269125293Srwatson		if (m == 0)
270125293Srwatson			return 0;
271125293Srwatson
272125293Srwatson		ah = mtod(m, struct arc_header *);
273125293Srwatson		if (!arc_isphds(ah->arc_type))
274125293Srwatson			return m;
275125293Srwatson
276125293Srwatson		++ac->ac_seqid;		/* make the seqid unique */
277125293Srwatson		tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
278125293Srwatson		ac->fsflag = 2 * tfrags - 3;
279125293Srwatson		ac->sflag = 0;
280125293Srwatson		ac->rsflag = ac->fsflag;
281125293Srwatson		ac->arc_dhost = ah->arc_dhost;
282125293Srwatson		ac->arc_shost = ah->arc_shost;
283125293Srwatson		ac->arc_type = ah->arc_type;
284125293Srwatson
285125293Srwatson		m_adj(m, ARC_HDRLEN);
286125293Srwatson		ac->curr_frag = m;
287125293Srwatson	}
288125293Srwatson
289125293Srwatson	/* split out next fragment and return it */
290125293Srwatson	if (ac->sflag < ac->fsflag) {
291125293Srwatson		/* we CAN'T have short packets here */
292125293Srwatson		ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
293125293Srwatson		if (ac->curr_frag == 0) {
294125293Srwatson			m_freem(m);
295125293Srwatson			return 0;
296125293Srwatson		}
297125293Srwatson
298179243Skib		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
299179243Skib		if (m == 0) {
300125293Srwatson			m_freem(ac->curr_frag);
301125293Srwatson			ac->curr_frag = 0;
302125293Srwatson			return 0;
303125293Srwatson		}
304125293Srwatson
305125293Srwatson		ah = mtod(m, struct arc_header *);
306125293Srwatson		ah->arc_flag = ac->rsflag;
307125293Srwatson		ah->arc_seqid = ac->ac_seqid;
308132987Sgreen
309125293Srwatson		ac->sflag += 2;
310125293Srwatson		ac->rsflag = ac->sflag;
311132987Sgreen	} else if ((m->m_pkthdr.len >=
312132987Sgreen	    ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
313125293Srwatson	    (m->m_pkthdr.len <=
314125293Srwatson	    ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
315125293Srwatson		ac->curr_frag = 0;
316125293Srwatson
317125293Srwatson		M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
318125293Srwatson		if (m == 0)
319125293Srwatson			return 0;
320125293Srwatson
321132987Sgreen		ah = mtod(m, struct arc_header *);
322125293Srwatson		ah->arc_flag = 0xFF;
323125293Srwatson		ah->arc_seqid = 0xFFFF;
324125293Srwatson		ah->arc_type2 = ac->arc_type;
325125293Srwatson		ah->arc_flag2 = ac->sflag;
326125293Srwatson		ah->arc_seqid2 = ac->ac_seqid;
327125293Srwatson	} else {
328125293Srwatson		ac->curr_frag = 0;
329125293Srwatson
330125293Srwatson		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
331125293Srwatson		if (m == 0)
332125293Srwatson			return 0;
333125293Srwatson
334125293Srwatson		ah = mtod(m, struct arc_header *);
335125293Srwatson		ah->arc_flag = ac->sflag;
336232055Skmacy		ah->arc_seqid = ac->ac_seqid;
337232055Skmacy	}
33813675Sdyson
339125293Srwatson	ah->arc_dhost = ac->arc_dhost;
34013675Sdyson	ah->arc_shost = ac->arc_shost;
341232055Skmacy	ah->arc_type = ac->arc_type;
34227899Sdyson
343232055Skmacy	return m;
344125293Srwatson}
345125293Srwatson
346126249Srwatson/*
347172930Srwatson * Defragmenter. Returns mbuf if last packet found, else
348126249Srwatson * NULL. frees imcoming mbuf as necessary.
349125293Srwatson */
350172930Srwatson
351172930Srwatsonstatic __inline struct mbuf *
352125293Srwatsonarc_defrag(ifp, m)
353125293Srwatson	struct ifnet *ifp;
354125293Srwatson	struct mbuf *m;
355125293Srwatson{
356193951Skib	struct arc_header *ah, *ah1;
357193951Skib	struct arccom *ac;
358140369Ssilby	struct ac_frag *af;
359133790Ssilby	struct mbuf *m1;
360155035Sglebius	char *s;
361155035Sglebius	int newflen;
362124394Sdes	u_char src,dst,typ;
363124394Sdes
364155035Sglebius	ac = (struct arccom *)ifp;
36576364Salfred
366124394Sdes	if (m->m_len < ARC_HDRNEWLEN) {
36713907Sdyson		m = m_pullup(m, ARC_HDRNEWLEN);
36813907Sdyson		if (m == NULL) {
369232055Skmacy			++ifp->if_ierrors;
370232055Skmacy			return NULL;
37113675Sdyson		}
372232055Skmacy	}
373232055Skmacy
374232055Skmacy	ah = mtod(m, struct arc_header *);
375232055Skmacy	typ = ah->arc_type;
376232055Skmacy
377232055Skmacy	if (!arc_isphds(typ))
378232055Skmacy		return m;
379232055Skmacy
380232055Skmacy	src = ah->arc_shost;
381232055Skmacy	dst = ah->arc_dhost;
382232055Skmacy
383232055Skmacy	if (ah->arc_flag == 0xff) {
384232055Skmacy		m_adj(m, 4);
385232055Skmacy
386232055Skmacy		if (m->m_len < ARC_HDRNEWLEN) {
387232055Skmacy			m = m_pullup(m, ARC_HDRNEWLEN);
388232055Skmacy			if (m == NULL) {
389232055Skmacy				++ifp->if_ierrors;
390232055Skmacy				return NULL;
391232055Skmacy			}
392232055Skmacy		}
393232055Skmacy
394232055Skmacy		ah = mtod(m, struct arc_header *);
395232055Skmacy	}
396232055Skmacy
397232055Skmacy	af = &ac->ac_fragtab[src];
398232055Skmacy	m1 = af->af_packet;
399232055Skmacy	s = "debug code error";
400232055Skmacy
401232055Skmacy	if (ah->arc_flag & 1) {
402232055Skmacy		/*
403232055Skmacy		 * first fragment. We always initialize, which is
404232055Skmacy		 * about the right thing to do, as we only want to
405232055Skmacy		 * accept one fragmented packet per src at a time.
406232055Skmacy		 */
407232055Skmacy		if (m1 != NULL)
408232055Skmacy			m_freem(m1);
409232055Skmacy
410232055Skmacy		af->af_packet = m;
411232055Skmacy		m1 = m;
412232055Skmacy		af->af_maxflag = ah->arc_flag;
413232055Skmacy		af->af_lastseen = 0;
414232055Skmacy		af->af_seqid = ah->arc_seqid;
415232055Skmacy
416232055Skmacy		return NULL;
417232055Skmacy		/* notreached */
418232055Skmacy	} else {
419232055Skmacy		/* check for unfragmented packet */
420232055Skmacy		if (ah->arc_flag == 0)
421232055Skmacy			return m;
422220245Skib
42370915Sdwmalone		/* do we have a first packet from that src? */
42470915Sdwmalone		if (m1 == NULL) {
42570915Sdwmalone			s = "no first frag";
42670915Sdwmalone			goto outofseq;
42770915Sdwmalone		}
428121256Sdwmalone
429184849Sed		ah1 = mtod(m1, struct arc_header *);
43070915Sdwmalone
43170803Sdwmalone		if (ah->arc_seqid != ah1->arc_seqid) {
43270803Sdwmalone			s = "seqid differs";
43370803Sdwmalone			goto outofseq;
43470803Sdwmalone		}
43570803Sdwmalone
43670803Sdwmalone		if (typ != ah1->arc_type) {
437174988Sjeff			s = "type differs";
438220245Skib			goto outofseq;
43970915Sdwmalone		}
440184849Sed
44183366Sjulian		if (dst != ah1->arc_dhost) {
44270915Sdwmalone			s = "dest host differs";
44370915Sdwmalone			goto outofseq;
44470915Sdwmalone		}
44570915Sdwmalone
446121256Sdwmalone		/* typ, seqid and dst are ok here. */
447174988Sjeff
448121256Sdwmalone		if (ah->arc_flag == af->af_lastseen) {
449184849Sed			m_freem(m);
45083366Sjulian			return NULL;
45113675Sdyson		}
45213675Sdyson
45313675Sdyson		if (ah->arc_flag == af->af_lastseen + 2) {
45413675Sdyson			/* ok, this is next fragment */
455184849Sed			af->af_lastseen = ah->arc_flag;
456184849Sed			m_adj(m,ARC_HDRNEWLEN);
457225617Skmacy
458184849Sed			/*
459184849Sed			 * m_cat might free the first mbuf (with pkthdr)
460184849Sed			 * in 2nd chain; therefore:
461184849Sed			 */
462184849Sed
463184849Sed			newflen = m->m_pkthdr.len;
464184849Sed
465184849Sed			m_cat(m1,m);
466184849Sed
467184849Sed			m1->m_pkthdr.len += newflen;
468184849Sed
469184849Sed			/* is it the last one? */
470184849Sed			if (af->af_lastseen > af->af_maxflag) {
471184849Sed				af->af_packet = NULL;
47213909Sdyson				return(m1);
47313909Sdyson			} else
47476364Salfred				return NULL;
47576364Salfred		}
47676364Salfred		s = "other reason";
47713909Sdyson		/* if all else fails, it is out of sequence, too */
47876364Salfred	}
479132579Srwatsonoutofseq:
48013675Sdyson	if (m1) {
48176364Salfred		m_freem(m1);
48213675Sdyson		af->af_packet = NULL;
48376364Salfred	}
484133790Ssilby
485117325Ssilby	if (m)
486117325Ssilby		m_freem(m);
48713675Sdyson
488125293Srwatson	log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
489133790Ssilby	    ifp->if_name, ifp->if_unit, s);
490133790Ssilby
491133790Ssilby	return NULL;
492133790Ssilby}
493133790Ssilby
494133790Ssilby/*
49579224Sdillon * return 1 if Packet Header Definition Standard, else 0.
496118764Ssilby * For now: old IP, old ARP aren't obviously. Lacking correct information,
497118764Ssilby * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
49813675Sdyson * (Apple and Novell corporations were involved, among others, in PHDS work).
499122163Salc * Easiest is to assume that everybody else uses that, too.
50076364Salfred */
50113688Sdysonint
50276364Salfredarc_isphds(type)
503133790Ssilby	u_int8_t type;
504133790Ssilby{
505133790Ssilby	return (type != ARCTYPE_IP_OLD &&
506133790Ssilby		type != ARCTYPE_ARP_OLD &&
507133790Ssilby		type != ARCTYPE_DIAGNOSE);
508133790Ssilby}
509133790Ssilby
510133790Ssilby/*
511133790Ssilby * Process a received Arcnet packet;
512133790Ssilby * the packet is in the mbuf chain m with
513133790Ssilby * the ARCnet header.
514133790Ssilby */
515133790Ssilbyvoid
51676364Salfredarc_input(ifp, m)
51776364Salfred	struct ifnet *ifp;
51876364Salfred	struct mbuf *m;
519133790Ssilby{
520133790Ssilby	struct arc_header *ah;
521133790Ssilby	struct ifqueue *inq;
522133790Ssilby	u_int8_t atype;
523133790Ssilby
524133790Ssilby	if ((ifp->if_flags & IFF_UP) == 0) {
525133790Ssilby		m_freem(m);
526133790Ssilby		return;
527133790Ssilby	}
528133790Ssilby
529133790Ssilby	/* possibly defragment: */
530133790Ssilby	m = arc_defrag(ifp, m);
531133790Ssilby	if (m == NULL)
532133790Ssilby		return;
53376364Salfred
53476364Salfred	BPF_MTAP(ifp, m);
53576364Salfred
536133790Ssilby	ah = mtod(m, struct arc_header *);
53776364Salfred	/* does this belong to us? */
538133790Ssilby	if ((ifp->if_flags & IFF_PROMISC) != 0
539189649Sjhb	    && ah->arc_dhost != arcbroadcastaddr
54076364Salfred	    && ah->arc_dhost != *IF_LLADDR(ifp)) {
54113907Sdyson		m_freem(m);
54213688Sdyson		return;
54313907Sdyson	}
544132579Srwatson
545132579Srwatson	ifp->if_ibytes += m->m_pkthdr.len;
546132579Srwatson
547132579Srwatson	if (ah->arc_dhost == arcbroadcastaddr) {
548132579Srwatson		m->m_flags |= M_BCAST|M_MCAST;
549132579Srwatson		ifp->if_imcasts++;
550132579Srwatson	}
551132579Srwatson
552133049Ssilby	atype = ah->arc_type;
553133049Ssilby	switch (atype) {
554132579Srwatson#ifdef INET
555132579Srwatson	case ARCTYPE_IP:
556132579Srwatson		m_adj(m, ARC_HDRNEWLEN);
557132579Srwatson		if (ipflow_fastforward(m))
55813675Sdyson			return;
55913675Sdyson		schednetisr(NETISR_IP);
56013675Sdyson		inq = &ipintrq;
56113907Sdyson		break;
56213675Sdyson
56313907Sdyson	case ARCTYPE_IP_OLD:
56413675Sdyson		m_adj(m, ARC_HDRLEN);
56513776Sdyson		if (ipflow_fastforward(m))
56676364Salfred			return;
56791362Salfred		schednetisr(NETISR_IP);
56891362Salfred		inq = &ipintrq;
56913675Sdyson		break;
57091362Salfred
57191362Salfred	case ARCTYPE_ARP:
57276760Salfred		if (ifp->if_flags & IFF_NOARP) {
573124394Sdes			/* Discard packet if ARP is disabled on interface */
57476760Salfred			m_freem(m);
57513675Sdyson			return;
57691362Salfred		}
57776760Salfred		m_adj(m, ARC_HDRNEWLEN);
57813675Sdyson		schednetisr(NETISR_ARP);
57913675Sdyson		inq = &arpintrq;
58013675Sdyson#ifdef ARCNET_ALLOW_BROKEN_ARP
58113675Sdyson		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
58213675Sdyson#endif
58313675Sdyson		break;
58413675Sdyson
58513675Sdyson	case ARCTYPE_ARP_OLD:
58613675Sdyson		if (ifp->if_flags & IFF_NOARP) {
58776364Salfred			/* Discard packet if ARP is disabled on interface */
58891362Salfred			m_freem(m);
589133049Ssilby			return;
590133049Ssilby		}
59191362Salfred		m_adj(m, ARC_HDRLEN);
59213675Sdyson		schednetisr(NETISR_ARP);
59313675Sdyson		inq = &arpintrq;
59414177Sdyson#ifdef ARCNET_ALLOW_BROKEN_ARP
59513675Sdyson		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
59613675Sdyson#endif
59713675Sdyson		break;
59814037Sdyson#endif
59914037Sdyson#ifdef INET6
60014037Sdyson	case ARCTYPE_INET6:
60114037Sdyson		m_adj(m, ARC_HDRNEWLEN);
60276364Salfred		schednetisr(NETISR_IPV6);
603126252Srwatson		inq = &ip6intrq;
60414037Sdyson		break;
605122352Stanimura#endif
606174647Sjeff#ifdef IPX
607174647Sjeff	case ARCTYPE_IPX:
60814037Sdyson		m_adj(m, ARC_HDRNEWLEN);
60941086Struckman		schednetisr(NETISR_IPX);
61095883Salfred		inq = &ipxintrq;
611133741Sjmg		break;
61214037Sdyson#endif
61314037Sdyson	default:
614126131Sgreen		m_freem(m);
615126131Sgreen		return;
616126131Sgreen	}
617126131Sgreen
618126131Sgreen	IF_HANDOFF(inq, m, NULL);
619133790Ssilby}
620126131Sgreen
621133790Ssilby/*
622126131Sgreen * Register (new) link level address.
623126131Sgreen */
624126131Sgreenvoid
625133790Ssilbyarc_storelladdr(ifp, lla)
626133790Ssilby	struct ifnet *ifp;
627133790Ssilby	u_int8_t lla;
628133790Ssilby{
629133790Ssilby	*IF_LLADDR(ifp) = lla;
630133790Ssilby}
631133790Ssilby
632133790Ssilby/*
633133790Ssilby * Perform common duties while attaching to interface list
634228306Skib */
635132579Srwatsonvoid
636126131Sgreenarc_ifattach(ifp, lla)
637126131Sgreen	struct ifnet *ifp;
63813675Sdyson	u_int8_t lla;
63913675Sdyson{
640101941Srwatson	struct ifaddr *ifa;
64113675Sdyson	struct sockaddr_dl *sdl;
64213675Sdyson	struct arccom *ac;
643101941Srwatson
64483366Sjulian	if_attach(ifp);
64545311Sdt	ifp->if_type = IFT_ARCNET;
64613675Sdyson	ifp->if_addrlen = 1;
647232055Skmacy	ifp->if_hdrlen = ARC_HDRLEN;
64847748Salc	ifp->if_mtu = 1500;
64913675Sdyson	ifp->if_resolvemulti = arc_resolvemulti;
65018863Sdyson	if (ifp->if_baudrate == 0)
65113675Sdyson		ifp->if_baudrate = 2500000;
652232055Skmacy#if __FreeBSD_version < 500000
65391362Salfred	ifa = ifnet_addrs[ifp->if_index - 1];
65413675Sdyson#else
65547748Salc	ifa = ifaddr_byindex(ifp->if_index);
65647748Salc#endif
65747748Salc	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
65847748Salc	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
659101768Srwatson	sdl->sdl_type = IFT_ARCNET;
660172930Srwatson	sdl->sdl_alen = ifp->if_addrlen;
661101768Srwatson
662101768Srwatson	if (ifp->if_flags & IFF_BROADCAST)
663101768Srwatson		ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
664133790Ssilby
665133790Ssilby	ac = (struct arccom *)ifp;
666133790Ssilby	ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
667133790Ssilby	if (lla == 0) {
668133790Ssilby		/* XXX this message isn't entirely clear, to me -- cgd */
669133790Ssilby		log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts.  Please change it and ifconfig %s%d down up\n",
670133790Ssilby		   ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
671133790Ssilby	}
672133790Ssilby	arc_storelladdr(ifp, lla);
673133790Ssilby
674101768Srwatson	ifp->if_broadcastaddr = &arcbroadcastaddr;
67513675Sdyson
67613907Sdyson	bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
67713907Sdyson}
67813907Sdyson
67913675Sdysonvoid
68018863Sdysonarc_ifdetach(ifp)
68113675Sdyson	struct ifnet *ifp;
68213675Sdyson{
683231949Skib	bpfdetach(ifp);
68418863Sdyson	if_detach(ifp);
68547748Salc}
68691362Salfred
687116127Smuxint
688116127Smuxarc_ioctl(ifp, command, data)
689116127Smux	struct ifnet *ifp;
69091362Salfred	int command;
69176760Salfred	caddr_t data;
69213675Sdyson{
69376760Salfred	struct ifaddr *ifa = (struct ifaddr *) data;
69413675Sdyson	struct ifreq *ifr = (struct ifreq *) data;
69513675Sdyson	int error = 0;
69613675Sdyson
69713675Sdyson	switch (command) {
69813675Sdyson	case SIOCSIFADDR:
69947748Salc		ifp->if_flags |= IFF_UP;
70047748Salc		switch (ifa->ifa_addr->sa_family) {
70147748Salc#ifdef INET
70247748Salc		case AF_INET:
70347748Salc			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
70447748Salc			arp_ifinit(ifp, ifa);
70547748Salc			break;
70647748Salc#endif
70747748Salc#ifdef IPX
70847748Salc		/*
70913675Sdyson		 * XXX This code is probably wrong
71014037Sdyson		 */
71113907Sdyson		case AF_IPX:
71213907Sdyson		{
71313907Sdyson			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
71413907Sdyson
71547748Salc			if (ipx_nullhost(*ina))
716231949Skib				ina->x_host.c_host[5] = *IF_LLADDR(ifp);
71718863Sdyson			else
71847748Salc				arc_storelladdr(ifp, ina->x_host.c_host[5]);
71991362Salfred
720127501Salc			/*
721127501Salc			 * Set new address
72291362Salfred			 */
72313907Sdyson			ifp->if_init(ifp->if_softc);
72413907Sdyson			break;
72513907Sdyson		}
72613907Sdyson#endif
72713907Sdyson		default:
72813907Sdyson			ifp->if_init(ifp->if_softc);
72913907Sdyson			break;
73013907Sdyson		}
73113907Sdyson		break;
73214037Sdyson
73313675Sdyson	case SIOCGIFADDR:
73413675Sdyson		{
73513675Sdyson			struct sockaddr *sa;
73676760Salfred
73713675Sdyson			sa = (struct sockaddr *) &ifr->ifr_data;
73876760Salfred			bcopy(IF_LLADDR(ifp),
73913675Sdyson			    (caddr_t) sa->sa_data, ARC_ADDR_LEN);
74043623Sdillon		}
74113675Sdyson		break;
74213675Sdyson
74313675Sdyson	case SIOCADDMULTI:
74413675Sdyson	case SIOCDELMULTI:
74513675Sdyson		if (ifr == NULL)
74613675Sdyson			error = EAFNOSUPPORT;
74713675Sdyson		else {
74843623Sdillon			switch (ifr->ifr_addr.sa_family) {
74943623Sdillon			case AF_INET:
75047748Salc			case AF_INET6:
75143623Sdillon				error = 0;
75247748Salc				break;
75313675Sdyson			default:
75416960Sdyson				error = EAFNOSUPPORT;
75543623Sdillon				break;
756124394Sdes			}
757116127Smux		}
758116127Smux		break;
75943623Sdillon
76047748Salc	case SIOCSIFMTU:
76143623Sdillon		/*
76213675Sdyson		 * Set the interface MTU.
76347748Salc		 * mtu can't be larger than ARCMTU for RFC1051
76447748Salc		 * and can't be larger than ARC_PHDS_MTU
76513675Sdyson		 */
76676760Salfred		if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
76747748Salc		    ifr->ifr_mtu > ARC_PHDS_MAXMTU)
76876760Salfred			error = EINVAL;
76947748Salc		else
77091362Salfred			ifp->if_mtu = ifr->ifr_mtu;
77191362Salfred		break;
77277140Salfred	}
77347748Salc
77413675Sdyson	return (error);
77547748Salc}
77647748Salc
77713675Sdyson/* based on ether_resolvemulti() */
77813675Sdysonint
779101768Srwatsonarc_resolvemulti(ifp, llsa, sa)
780101768Srwatson	struct ifnet *ifp;
781101768Srwatson	struct sockaddr **llsa;
78247748Salc	struct sockaddr *sa;
78313675Sdyson{
78491362Salfred	struct sockaddr_dl *sdl;
78524101Sbde	struct sockaddr_in *sin;
78655112Sbde#ifdef INET6
78747748Salc	struct sockaddr_in6 *sin6;
78847748Salc#endif
78913913Sdyson
79047748Salc	switch(sa->sa_family) {
79147748Salc	case AF_LINK:
79247748Salc		/*
79313675Sdyson		* No mapping needed. Just check that it's a valid MC address.
79413675Sdyson		*/
79513675Sdyson		sdl = (struct sockaddr_dl *)sa;
79613675Sdyson		if (*LLADDR(sdl) != arcbroadcastaddr)
79713675Sdyson			return EADDRNOTAVAIL;
79847748Salc		*llsa = 0;
79913675Sdyson		return 0;
80013675Sdyson#ifdef INET
80113675Sdyson	case AF_INET:
80213675Sdyson		sin = (struct sockaddr_in *)sa;
80313675Sdyson		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
80413675Sdyson			return EADDRNOTAVAIL;
80514037Sdyson		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
80614802Sdyson		       M_ZERO);
80714037Sdyson		sdl->sdl_len = sizeof *sdl;
80814037Sdyson		sdl->sdl_family = AF_LINK;
80991362Salfred		sdl->sdl_index = ifp->if_index;
81076760Salfred		sdl->sdl_type = IFT_ARCNET;
81113675Sdyson		sdl->sdl_alen = ARC_ADDR_LEN;
81213675Sdyson		*LLADDR(sdl) = 0;
81314037Sdyson		*llsa = (struct sockaddr *)sdl;
81413907Sdyson		return 0;
81513907Sdyson#endif
81613907Sdyson#ifdef INET6
81713907Sdyson	case AF_INET6:
81813675Sdyson		sin6 = (struct sockaddr_in6 *)sa;
81913907Sdyson		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
82013907Sdyson			/*
82113675Sdyson			 * An IP6 address of 0 means listen to all
82213675Sdyson			 * of the Ethernet multicast address used for IP6.
82318863Sdyson			 * (This is used for multicast routers.)
824216511Salc			 */
82513907Sdyson			ifp->if_flags |= IFF_ALLMULTI;
82691412Salfred			*llsa = 0;
827133790Ssilby			return 0;
828133790Ssilby		}
82979224Sdillon		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
830231949Skib			return EADDRNOTAVAIL;
831231949Skib		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
832231949Skib		       M_ZERO);
833231949Skib		sdl->sdl_len = sizeof *sdl;
83413907Sdyson		sdl->sdl_family = AF_LINK;
835216699Salc		sdl->sdl_index = ifp->if_index;
836216699Salc		sdl->sdl_type = IFT_ARCNET;
837216699Salc		sdl->sdl_alen = ARC_ADDR_LEN;
838193893Scperciva		*LLADDR(sdl) = 0;
83913907Sdyson		*llsa = (struct sockaddr *)sdl;
84013907Sdyson		return 0;
84113907Sdyson#endif
84213907Sdyson
84313907Sdyson	default:
84476760Salfred		/*
84576760Salfred		 * Well, the text isn't quite right, but it's the name
84613907Sdyson		 * that counts...
84713907Sdyson		 */
84813907Sdyson		return EAFNOSUPPORT;
84913907Sdyson	}
85013907Sdyson}
85113907Sdyson