11638Srgrimes/*	$NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $	*/
21638Srgrimes/*	$FreeBSD: stable/11/sys/net/if_arcsubr.c 332159 2018-04-06 23:31:47Z brooks $ */
31638Srgrimes
41638Srgrimes/*-
51638Srgrimes * Copyright (c) 1994, 1995 Ignatios Souvatzis
61638Srgrimes * Copyright (c) 1982, 1989, 1993
71638Srgrimes *	The Regents of the University of California.  All rights reserved.
81638Srgrimes *
91638Srgrimes * Redistribution and use in source and binary forms, with or without
101638Srgrimes * modification, are permitted provided that the following conditions
111638Srgrimes * are met:
121638Srgrimes * 1. Redistributions of source code must retain the above copyright
131638Srgrimes *    notice, this list of conditions and the following disclaimer.
141638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151638Srgrimes *    notice, this list of conditions and the following disclaimer in the
161638Srgrimes *    documentation and/or other materials provided with the distribution.
171638Srgrimes * 3. All advertising materials mentioning features or use of this software
181638Srgrimes *    must display the following acknowledgement:
191638Srgrimes *	This product includes software developed by the University of
201638Srgrimes *	California, Berkeley and its contributors.
211638Srgrimes * 4. Neither the name of the University nor the names of its contributors
221638Srgrimes *    may be used to endorse or promote products derived from this software
231638Srgrimes *    without specific prior written permission.
241638Srgrimes *
251638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281638Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291638Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301638Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311638Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321638Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3350476Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341638Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351638Srgrimes * SUCH DAMAGE.
361638Srgrimes *
371638Srgrimes * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
381638Srgrimes *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
39130126Smurray *
401638Srgrimes */
411638Srgrimes#include "opt_inet.h"
421638Srgrimes#include "opt_inet6.h"
431638Srgrimes
441638Srgrimes#include <sys/param.h>
451638Srgrimes#include <sys/systm.h>
461638Srgrimes#include <sys/kernel.h>
471638Srgrimes#include <sys/module.h>
481638Srgrimes#include <sys/malloc.h>
491638Srgrimes#include <sys/mbuf.h>
501638Srgrimes#include <sys/protosw.h>
511638Srgrimes#include <sys/socket.h>
521638Srgrimes#include <sys/sockio.h>
531638Srgrimes#include <sys/errno.h>
541638Srgrimes#include <sys/syslog.h>
551638Srgrimes
561638Srgrimes#include <machine/cpu.h>
571638Srgrimes
581638Srgrimes#include <net/if.h>
591638Srgrimes#include <net/if_var.h>
601638Srgrimes#include <net/netisr.h>
611638Srgrimes#include <net/route.h>
621638Srgrimes#include <net/if_dl.h>
631638Srgrimes#include <net/if_types.h>
641638Srgrimes#include <net/if_arc.h>
651638Srgrimes#include <net/if_arp.h>
661638Srgrimes#include <net/bpf.h>
671638Srgrimes#include <net/if_llatbl.h>
681638Srgrimes
691638Srgrimes#if defined(INET) || defined(INET6)
701638Srgrimes#include <netinet/in.h>
711638Srgrimes#include <netinet/in_var.h>
721638Srgrimes#include <netinet/if_ether.h>
731638Srgrimes#endif
741638Srgrimes
751638Srgrimes#ifdef INET6
761638Srgrimes#include <netinet6/nd6.h>
771638Srgrimes#endif
781638Srgrimes
791638Srgrimes#define ARCNET_ALLOW_BROKEN_ARP
801638Srgrimes
811638Srgrimesstatic struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
821638Srgrimesstatic int arc_resolvemulti(struct ifnet *, struct sockaddr **,
831638Srgrimes			    struct sockaddr *);
841638Srgrimes
851638Srgrimesu_int8_t  arcbroadcastaddr = 0;
861638Srgrimes
871638Srgrimes#define ARC_LLADDR(ifp)	(*(u_int8_t *)IF_LLADDR(ifp))
881638Srgrimes
891638Srgrimes#define senderr(e) { error = (e); goto bad;}
901638Srgrimes#define SIN(s)	((const struct sockaddr_in *)(s))
911638Srgrimes
92130126Smurray/*
93130126Smurray * ARCnet output routine.
94130126Smurray * Encapsulate a packet of type family for the local net.
95130126Smurray * Assumes that ifp is actually pointer to arccom structure.
96130126Smurray */
97130126Smurrayint
98130126Smurrayarc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
99130126Smurray    struct route *ro)
100130126Smurray{
101130126Smurray	struct arc_header	*ah;
102130126Smurray	int			error;
1031638Srgrimes	u_int8_t		atype, adst;
1041638Srgrimes	int			loop_copy = 0;
1051638Srgrimes	int			isphds;
1061638Srgrimes#if defined(INET) || defined(INET6)
1071638Srgrimes	int			is_gw = 0;
1081638Srgrimes#endif
1091638Srgrimes
1101638Srgrimes	if (!((ifp->if_flags & IFF_UP) &&
1111638Srgrimes	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
1121638Srgrimes		return(ENETDOWN); /* m, m1 aren't initialized yet */
1131638Srgrimes
1141638Srgrimes	error = 0;
1151638Srgrimes#if defined(INET) || defined(INET6)
1161638Srgrimes	if (ro != NULL)
1171638Srgrimes		is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
1181638Srgrimes#endif
1191638Srgrimes
1201638Srgrimes	switch (dst->sa_family) {
1211638Srgrimes#ifdef INET
1221638Srgrimes	case AF_INET:
1231638Srgrimes
1241638Srgrimes		/*
1251638Srgrimes		 * For now, use the simple IP addr -> ARCnet addr mapping
1261638Srgrimes		 */
1271638Srgrimes		if (m->m_flags & (M_BCAST|M_MCAST))
1281638Srgrimes			adst = arcbroadcastaddr; /* ARCnet broadcast address */
1291638Srgrimes		else if (ifp->if_flags & IFF_NOARP)
1301638Srgrimes			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
131101677Sschweikh		else {
1321638Srgrimes			error = arpresolve(ifp, is_gw, m, dst, &adst, NULL,
1331638Srgrimes			    NULL);
1341638Srgrimes			if (error)
1351638Srgrimes				return (error == EWOULDBLOCK ? 0 : error);
1361638Srgrimes		}
1371638Srgrimes
1381638Srgrimes		atype = (ifp->if_flags & IFF_LINK0) ?
1391638Srgrimes			ARCTYPE_IP_OLD : ARCTYPE_IP;
1401638Srgrimes		break;
1411638Srgrimes	case AF_ARP:
1421638Srgrimes	{
1431638Srgrimes		struct arphdr *ah;
1441638Srgrimes		ah = mtod(m, struct arphdr *);
1451638Srgrimes		ah->ar_hrd = htons(ARPHRD_ARCNET);
1461638Srgrimes
1471638Srgrimes		loop_copy = -1; /* if this is for us, don't do it */
1481638Srgrimes
1491638Srgrimes		switch(ntohs(ah->ar_op)) {
1501638Srgrimes		case ARPOP_REVREQUEST:
1511638Srgrimes		case ARPOP_REVREPLY:
1521638Srgrimes			atype = ARCTYPE_REVARP;
1531638Srgrimes			break;
1541638Srgrimes		case ARPOP_REQUEST:
1551638Srgrimes		case ARPOP_REPLY:
1561638Srgrimes		default:
1571638Srgrimes			atype = ARCTYPE_ARP;
1581638Srgrimes			break;
1591638Srgrimes		}
1601638Srgrimes
1611638Srgrimes		if (m->m_flags & M_BCAST)
1621638Srgrimes			bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN);
16322188Sache		else
1641638Srgrimes			bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN);
1651638Srgrimes
1661638Srgrimes	}
1671638Srgrimes	break;
1681638Srgrimes#endif
1691638Srgrimes#ifdef INET6
1701638Srgrimes	case AF_INET6:
1711638Srgrimes		if ((m->m_flags & M_MCAST) != 0)
1721638Srgrimes			adst = arcbroadcastaddr; /* ARCnet broadcast address */
1731638Srgrimes		else {
1741638Srgrimes			error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL,
1751638Srgrimes			    NULL);
1761638Srgrimes			if (error != 0)
1771638Srgrimes				return (error == EWOULDBLOCK ? 0 : error);
17822188Sache		}
1791638Srgrimes		atype = ARCTYPE_INET6;
1801638Srgrimes		break;
1811638Srgrimes#endif
1821638Srgrimes	case AF_UNSPEC:
1831638Srgrimes	    {
1841638Srgrimes		const struct arc_header *ah;
1851638Srgrimes
1861638Srgrimes		loop_copy = -1;
1871638Srgrimes		ah = (const struct arc_header *)dst->sa_data;
1881638Srgrimes		adst = ah->arc_dhost;
1891638Srgrimes		atype = ah->arc_type;
1901638Srgrimes
1911638Srgrimes		if (atype == ARCTYPE_ARP) {
1921638Srgrimes			atype = (ifp->if_flags & IFF_LINK0) ?
19322188Sache			    ARCTYPE_ARP_OLD: ARCTYPE_ARP;
1941638Srgrimes
1951638Srgrimes#ifdef ARCNET_ALLOW_BROKEN_ARP
1961638Srgrimes			/*
1971638Srgrimes			 * XXX It's not clear per RFC826 if this is needed, but
1981638Srgrimes			 * "assigned numbers" say this is wrong.
1991638Srgrimes			 * However, e.g., AmiTCP 3.0Beta used it... we make this
2001638Srgrimes			 * switchable for emergency cases. Not perfect, but...
2011638Srgrimes			 */
2021638Srgrimes			if (ifp->if_flags & IFF_LINK2)
2031638Srgrimes				mtod(m, struct arphdr *)->ar_pro = atype - 1;
2041638Srgrimes#endif
2051638Srgrimes		}
2061638Srgrimes		break;
2071638Srgrimes	    }
2081638Srgrimes	default:
2091638Srgrimes		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
2101638Srgrimes		senderr(EAFNOSUPPORT);
2111638Srgrimes	}
2121638Srgrimes
21322188Sache	isphds = arc_isphds(atype);
2141638Srgrimes	M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT);
2151638Srgrimes	if (m == NULL)
2161638Srgrimes		senderr(ENOBUFS);
2171638Srgrimes	ah = mtod(m, struct arc_header *);
2181638Srgrimes	ah->arc_type = atype;
2191638Srgrimes	ah->arc_dhost = adst;
2201638Srgrimes	ah->arc_shost = ARC_LLADDR(ifp);
2211638Srgrimes	if (isphds) {
2221638Srgrimes		ah->arc_flag = 0;
2231638Srgrimes		ah->arc_seqid = 0;
2241638Srgrimes	}
2251638Srgrimes
2261638Srgrimes	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
2271638Srgrimes		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
22822188Sache			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
2291638Srgrimes
2301638Srgrimes			(void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
2311638Srgrimes		} else if (ah->arc_dhost == ah->arc_shost) {
2321638Srgrimes			(void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
2331638Srgrimes			return (0);     /* XXX */
2341638Srgrimes		}
2351638Srgrimes	}
2361638Srgrimes
2371638Srgrimes	BPF_MTAP(ifp, m);
2381638Srgrimes
2391638Srgrimes	error = ifp->if_transmit(ifp, m);
2401638Srgrimes
2411638Srgrimes	return (error);
2421638Srgrimes
2431638Srgrimesbad:
2441638Srgrimes	if (m)
2451638Srgrimes		m_freem(m);
2461638Srgrimes	return (error);
2471638Srgrimes}
2481638Srgrimes
2491638Srgrimesvoid
2501638Srgrimesarc_frag_init(struct ifnet *ifp)
2511638Srgrimes{
2521638Srgrimes	struct arccom *ac;
2531638Srgrimes
2541638Srgrimes	ac = (struct arccom *)ifp->if_l2com;
2551638Srgrimes	ac->curr_frag = 0;
2561638Srgrimes}
2571638Srgrimes
2581638Srgrimesstruct mbuf *
2591638Srgrimesarc_frag_next(struct ifnet *ifp)
26022188Sache{
2611638Srgrimes	struct arccom *ac;
2621638Srgrimes	struct mbuf *m;
2631638Srgrimes	struct arc_header *ah;
2641638Srgrimes
2651638Srgrimes	ac = (struct arccom *)ifp->if_l2com;
26622188Sache	if ((m = ac->curr_frag) == NULL) {
26722188Sache		int tfrags;
2681638Srgrimes
2691638Srgrimes		/* dequeue new packet */
2701638Srgrimes		IF_DEQUEUE(&ifp->if_snd, m);
2711638Srgrimes		if (m == NULL)
2721638Srgrimes			return 0;
2731638Srgrimes
2741638Srgrimes		ah = mtod(m, struct arc_header *);
2751638Srgrimes		if (!arc_isphds(ah->arc_type))
2761638Srgrimes			return m;
2771638Srgrimes
2781638Srgrimes		++ac->ac_seqid;		/* make the seqid unique */
2791638Srgrimes		tfrags = howmany(m->m_pkthdr.len, ARC_MAX_DATA);
2801638Srgrimes		ac->fsflag = 2 * tfrags - 3;
2811638Srgrimes		ac->sflag = 0;
2821638Srgrimes		ac->rsflag = ac->fsflag;
2831638Srgrimes		ac->arc_dhost = ah->arc_dhost;
2841638Srgrimes		ac->arc_shost = ah->arc_shost;
2851638Srgrimes		ac->arc_type = ah->arc_type;
2861638Srgrimes
2871638Srgrimes		m_adj(m, ARC_HDRNEWLEN);
2881638Srgrimes		ac->curr_frag = m;
2891638Srgrimes	}
2901638Srgrimes
2911638Srgrimes	/* split out next fragment and return it */
2921638Srgrimes	if (ac->sflag < ac->fsflag) {
2931638Srgrimes		/* we CAN'T have short packets here */
2941638Srgrimes		ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
2951638Srgrimes		if (ac->curr_frag == 0) {
2961638Srgrimes			m_freem(m);
2971638Srgrimes			return 0;
29810073Speter		}
2991638Srgrimes
3001638Srgrimes		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
3011638Srgrimes		if (m == NULL) {
3021638Srgrimes			m_freem(ac->curr_frag);
3031638Srgrimes			ac->curr_frag = 0;
3041638Srgrimes			return 0;
3051638Srgrimes		}
3061638Srgrimes
3071638Srgrimes		ah = mtod(m, struct arc_header *);
3081638Srgrimes		ah->arc_flag = ac->rsflag;
3091638Srgrimes		ah->arc_seqid = ac->ac_seqid;
3101638Srgrimes
3111638Srgrimes		ac->sflag += 2;
3121638Srgrimes		ac->rsflag = ac->sflag;
3131638Srgrimes	} else if ((m->m_pkthdr.len >=
3141638Srgrimes	    ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
3151638Srgrimes	    (m->m_pkthdr.len <=
3161638Srgrimes	    ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
3171638Srgrimes		ac->curr_frag = 0;
3181638Srgrimes
3191638Srgrimes		M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
3201638Srgrimes		if (m == NULL)
3211638Srgrimes			return 0;
3221638Srgrimes
3231638Srgrimes		ah = mtod(m, struct arc_header *);
3241638Srgrimes		ah->arc_flag = 0xFF;
3251638Srgrimes		ah->arc_seqid = 0xFFFF;
3261638Srgrimes		ah->arc_type2 = ac->arc_type;
3271638Srgrimes		ah->arc_flag2 = ac->sflag;
3281638Srgrimes		ah->arc_seqid2 = ac->ac_seqid;
3291638Srgrimes	} else {
3301638Srgrimes		ac->curr_frag = 0;
3311638Srgrimes
3321638Srgrimes		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
3331638Srgrimes		if (m == NULL)
3341638Srgrimes			return 0;
3351638Srgrimes
3361638Srgrimes		ah = mtod(m, struct arc_header *);
33722188Sache		ah->arc_flag = ac->sflag;
3381638Srgrimes		ah->arc_seqid = ac->ac_seqid;
3391638Srgrimes	}
3401638Srgrimes
3411638Srgrimes	ah->arc_dhost = ac->arc_dhost;
3421638Srgrimes	ah->arc_shost = ac->arc_shost;
3431638Srgrimes	ah->arc_type = ac->arc_type;
3441638Srgrimes
3451638Srgrimes	return m;
3461638Srgrimes}
3471638Srgrimes
3481638Srgrimes/*
3491638Srgrimes * Defragmenter. Returns mbuf if last packet found, else
3501638Srgrimes * NULL. frees incoming mbuf as necessary.
3511638Srgrimes */
3521638Srgrimes
3531638Srgrimesstatic __inline struct mbuf *
3541638Srgrimesarc_defrag(struct ifnet *ifp, struct mbuf *m)
3551638Srgrimes{
3561638Srgrimes	struct arc_header *ah, *ah1;
3571638Srgrimes	struct arccom *ac;
3581638Srgrimes	struct ac_frag *af;
3591638Srgrimes	struct mbuf *m1;
3601638Srgrimes	char *s;
3611638Srgrimes	int newflen;
3621638Srgrimes	u_char src,dst,typ;
3631638Srgrimes
3641638Srgrimes	ac = (struct arccom *)ifp->if_l2com;
3651638Srgrimes
3661638Srgrimes	if (m->m_len < ARC_HDRNEWLEN) {
3671638Srgrimes		m = m_pullup(m, ARC_HDRNEWLEN);
3681638Srgrimes		if (m == NULL) {
3691638Srgrimes			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3701638Srgrimes			return NULL;
3711638Srgrimes		}
3721638Srgrimes	}
3731638Srgrimes
3741638Srgrimes	ah = mtod(m, struct arc_header *);
3751638Srgrimes	typ = ah->arc_type;
3761638Srgrimes
3771638Srgrimes	if (!arc_isphds(typ))
3781638Srgrimes		return m;
3791638Srgrimes
3801638Srgrimes	src = ah->arc_shost;
3811638Srgrimes	dst = ah->arc_dhost;
3821638Srgrimes
3831638Srgrimes	if (ah->arc_flag == 0xff) {
3841638Srgrimes		m_adj(m, 4);
3851638Srgrimes
3861638Srgrimes		if (m->m_len < ARC_HDRNEWLEN) {
3871638Srgrimes			m = m_pullup(m, ARC_HDRNEWLEN);
3881638Srgrimes			if (m == NULL) {
3891638Srgrimes				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3901638Srgrimes				return NULL;
3911638Srgrimes			}
3921638Srgrimes		}
3931638Srgrimes
3941638Srgrimes		ah = mtod(m, struct arc_header *);
3951638Srgrimes	}
3961638Srgrimes
3971638Srgrimes	af = &ac->ac_fragtab[src];
3981638Srgrimes	m1 = af->af_packet;
3991638Srgrimes	s = "debug code error";
4001638Srgrimes
4011638Srgrimes	if (ah->arc_flag & 1) {
4021638Srgrimes		/*
4031638Srgrimes		 * first fragment. We always initialize, which is
4041638Srgrimes		 * about the right thing to do, as we only want to
4051638Srgrimes		 * accept one fragmented packet per src at a time.
4061638Srgrimes		 */
4071638Srgrimes		if (m1 != NULL)
408101677Sschweikh			m_freem(m1);
4091638Srgrimes
4101638Srgrimes		af->af_packet = m;
4111638Srgrimes		m1 = m;
4121638Srgrimes		af->af_maxflag = ah->arc_flag;
4131638Srgrimes		af->af_lastseen = 0;
4141638Srgrimes		af->af_seqid = ah->arc_seqid;
415127232Sschweikh
4161638Srgrimes		return NULL;
4171638Srgrimes		/* notreached */
4181638Srgrimes	} else {
4191638Srgrimes		/* check for unfragmented packet */
4201638Srgrimes		if (ah->arc_flag == 0)
4211638Srgrimes			return m;
42236487Sthepish
4231638Srgrimes		/* do we have a first packet from that src? */
4241638Srgrimes		if (m1 == NULL) {
4251638Srgrimes			s = "no first frag";
4261638Srgrimes			goto outofseq;
4271638Srgrimes		}
4281638Srgrimes
4291638Srgrimes		ah1 = mtod(m1, struct arc_header *);
4301638Srgrimes
4311638Srgrimes		if (ah->arc_seqid != ah1->arc_seqid) {
4321638Srgrimes			s = "seqid differs";
4331638Srgrimes			goto outofseq;
4341638Srgrimes		}
4351638Srgrimes
4361638Srgrimes		if (typ != ah1->arc_type) {
4371638Srgrimes			s = "type differs";
4381638Srgrimes			goto outofseq;
4391638Srgrimes		}
4401638Srgrimes
4411638Srgrimes		if (dst != ah1->arc_dhost) {
4421638Srgrimes			s = "dest host differs";
4431638Srgrimes			goto outofseq;
4441638Srgrimes		}
4451638Srgrimes
4461638Srgrimes		/* typ, seqid and dst are ok here. */
4471638Srgrimes
4481638Srgrimes		if (ah->arc_flag == af->af_lastseen) {
4491638Srgrimes			m_freem(m);
4501638Srgrimes			return NULL;
4511638Srgrimes		}
4521638Srgrimes
4531638Srgrimes		if (ah->arc_flag == af->af_lastseen + 2) {
4541638Srgrimes			/* ok, this is next fragment */
455127232Sschweikh			af->af_lastseen = ah->arc_flag;
456127232Sschweikh			m_adj(m,ARC_HDRNEWLEN);
4571638Srgrimes
4581638Srgrimes			/*
4591638Srgrimes			 * m_cat might free the first mbuf (with pkthdr)
4601638Srgrimes			 * in 2nd chain; therefore:
4611638Srgrimes			 */
4621638Srgrimes
4631638Srgrimes			newflen = m->m_pkthdr.len;
4641638Srgrimes
4651638Srgrimes			m_cat(m1,m);
4661638Srgrimes
4671638Srgrimes			m1->m_pkthdr.len += newflen;
46855070Sache
4691638Srgrimes			/* is it the last one? */
4701638Srgrimes			if (af->af_lastseen > af->af_maxflag) {
4711638Srgrimes				af->af_packet = NULL;
4721638Srgrimes				return(m1);
4731638Srgrimes			} else
4741638Srgrimes				return NULL;
4751638Srgrimes		}
4761638Srgrimes		s = "other reason";
4771638Srgrimes		/* if all else fails, it is out of sequence, too */
4781638Srgrimes	}
4791638Srgrimesoutofseq:
4801638Srgrimes	if (m1) {
4811638Srgrimes		m_freem(m1);
4821638Srgrimes		af->af_packet = NULL;
4831638Srgrimes	}
4841638Srgrimes
4851638Srgrimes	if (m)
486127232Sschweikh		m_freem(m);
4871638Srgrimes
4881638Srgrimes	log(LOG_INFO,"%s: got out of seq. packet: %s\n",
4891638Srgrimes	    ifp->if_xname, s);
4901638Srgrimes
4911638Srgrimes	return NULL;
4921638Srgrimes}
493127232Sschweikh
494127232Sschweikh/*
495127232Sschweikh * return 1 if Packet Header Definition Standard, else 0.
496127232Sschweikh * For now: old IP, old ARP aren't obviously. Lacking correct information,
497127232Sschweikh * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
498127232Sschweikh * (Apple and Novell corporations were involved, among others, in PHDS work).
499127232Sschweikh * Easiest is to assume that everybody else uses that, too.
500127232Sschweikh */
501127232Sschweikhint
502127232Sschweikharc_isphds(u_int8_t type)
503127232Sschweikh{
504127232Sschweikh	return (type != ARCTYPE_IP_OLD &&
505127232Sschweikh		type != ARCTYPE_ARP_OLD &&
506127232Sschweikh		type != ARCTYPE_DIAGNOSE);
507127232Sschweikh}
508127232Sschweikh
509127232Sschweikh/*
510127232Sschweikh * Process a received Arcnet packet;
511127232Sschweikh * the packet is in the mbuf chain m with
512127232Sschweikh * the ARCnet header.
513127232Sschweikh */
514127232Sschweikhvoid
515127232Sschweikharc_input(struct ifnet *ifp, struct mbuf *m)
516127232Sschweikh{
517127232Sschweikh	struct arc_header *ah;
518127232Sschweikh	int isr;
519127232Sschweikh	u_int8_t atype;
5201638Srgrimes
5211638Srgrimes	if ((ifp->if_flags & IFF_UP) == 0) {
5221638Srgrimes		m_freem(m);
5231638Srgrimes		return;
5241638Srgrimes	}
5251638Srgrimes
5261638Srgrimes	/* possibly defragment: */
5271638Srgrimes	m = arc_defrag(ifp, m);
5281638Srgrimes	if (m == NULL)
5291638Srgrimes		return;
5301638Srgrimes
5311638Srgrimes	BPF_MTAP(ifp, m);
53214291Sjkh
5331638Srgrimes	ah = mtod(m, struct arc_header *);
5341638Srgrimes	/* does this belong to us? */
5351638Srgrimes	if ((ifp->if_flags & IFF_PROMISC) == 0
5361638Srgrimes	    && ah->arc_dhost != arcbroadcastaddr
5371638Srgrimes	    && ah->arc_dhost != ARC_LLADDR(ifp)) {
5381638Srgrimes		m_freem(m);
5391638Srgrimes		return;
5401638Srgrimes	}
5411638Srgrimes
5421638Srgrimes	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
5431638Srgrimes
5441638Srgrimes	if (ah->arc_dhost == arcbroadcastaddr) {
5451638Srgrimes		m->m_flags |= M_BCAST|M_MCAST;
5461638Srgrimes		if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
5471638Srgrimes	}
5481638Srgrimes
5491638Srgrimes	atype = ah->arc_type;
5501638Srgrimes	switch (atype) {
5511638Srgrimes#ifdef INET
5521638Srgrimes	case ARCTYPE_IP:
5531638Srgrimes		m_adj(m, ARC_HDRNEWLEN);
5541638Srgrimes		isr = NETISR_IP;
5551638Srgrimes		break;
5561638Srgrimes
5571638Srgrimes	case ARCTYPE_IP_OLD:
5581638Srgrimes		m_adj(m, ARC_HDRLEN);
5591638Srgrimes		isr = NETISR_IP;
5601638Srgrimes		break;
5611638Srgrimes
5621638Srgrimes	case ARCTYPE_ARP:
56322188Sache		if (ifp->if_flags & IFF_NOARP) {
5641638Srgrimes			/* Discard packet if ARP is disabled on interface */
5651638Srgrimes			m_freem(m);
5661638Srgrimes			return;
5671638Srgrimes		}
5681638Srgrimes		m_adj(m, ARC_HDRNEWLEN);
5691638Srgrimes		isr = NETISR_ARP;
5701638Srgrimes#ifdef ARCNET_ALLOW_BROKEN_ARP
5711638Srgrimes		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
5721638Srgrimes#endif
5731638Srgrimes		break;
5741638Srgrimes
5751638Srgrimes	case ARCTYPE_ARP_OLD:
5761638Srgrimes		if (ifp->if_flags & IFF_NOARP) {
5771638Srgrimes			/* Discard packet if ARP is disabled on interface */
5781638Srgrimes			m_freem(m);
5791638Srgrimes			return;
5801638Srgrimes		}
5811638Srgrimes		m_adj(m, ARC_HDRLEN);
5821638Srgrimes		isr = NETISR_ARP;
5831638Srgrimes#ifdef ARCNET_ALLOW_BROKEN_ARP
5841638Srgrimes		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
5851638Srgrimes#endif
5861638Srgrimes		break;
5871638Srgrimes#endif
5881638Srgrimes#ifdef INET6
5891638Srgrimes	case ARCTYPE_INET6:
5901638Srgrimes		m_adj(m, ARC_HDRNEWLEN);
5911638Srgrimes		isr = NETISR_IPV6;
5921638Srgrimes		break;
5931638Srgrimes#endif
5941638Srgrimes	default:
5951638Srgrimes		m_freem(m);
5961638Srgrimes		return;
5971638Srgrimes	}
5981638Srgrimes	M_SETFIB(m, ifp->if_fib);
5991638Srgrimes	netisr_dispatch(isr, m);
6001638Srgrimes}
6011638Srgrimes
6021638Srgrimes/*
6031638Srgrimes * Register (new) link level address.
6041638Srgrimes */
6051638Srgrimesvoid
6061638Srgrimesarc_storelladdr(struct ifnet *ifp, u_int8_t lla)
6071638Srgrimes{
6081638Srgrimes	ARC_LLADDR(ifp) = lla;
6091638Srgrimes}
6101638Srgrimes
6111638Srgrimes/*
6121638Srgrimes * Perform common duties while attaching to interface list
6131638Srgrimes */
6141638Srgrimesvoid
6151638Srgrimesarc_ifattach(struct ifnet *ifp, u_int8_t lla)
6161638Srgrimes{
6171638Srgrimes	struct ifaddr *ifa;
6181638Srgrimes	struct sockaddr_dl *sdl;
6191638Srgrimes	struct arccom *ac;
6201638Srgrimes
6211638Srgrimes	if_attach(ifp);
6221638Srgrimes	ifp->if_addrlen = 1;
6231638Srgrimes	ifp->if_hdrlen = ARC_HDRLEN;
6241638Srgrimes	ifp->if_mtu = 1500;
625127232Sschweikh	ifp->if_resolvemulti = arc_resolvemulti;
6261638Srgrimes	if (ifp->if_baudrate == 0)
627104076Sache		ifp->if_baudrate = 2500000;
6281638Srgrimes	ifa = ifp->if_addr;
6291638Srgrimes	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
6301638Srgrimes	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
6311638Srgrimes	sdl->sdl_type = IFT_ARCNET;
6321638Srgrimes	sdl->sdl_alen = ifp->if_addrlen;
6331638Srgrimes
6341638Srgrimes	if (ifp->if_flags & IFF_BROADCAST)
6351638Srgrimes		ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
6361638Srgrimes
6371638Srgrimes	ac = (struct arccom *)ifp->if_l2com;
6381638Srgrimes	ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
639127232Sschweikh	if (lla == 0) {
6401638Srgrimes		/* XXX this message isn't entirely clear, to me -- cgd */
6411638Srgrimes		log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
6421638Srgrimes		   ifp->if_xname, ifp->if_xname);
64322188Sache	}
6441638Srgrimes	arc_storelladdr(ifp, lla);
6451800Sphk
6461638Srgrimes	ifp->if_broadcastaddr = &arcbroadcastaddr;
6471638Srgrimes
6481638Srgrimes	bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
6491638Srgrimes}
6501638Srgrimes
6511638Srgrimesvoid
6521638Srgrimesarc_ifdetach(struct ifnet *ifp)
6531638Srgrimes{
6541638Srgrimes	bpfdetach(ifp);
6551638Srgrimes	if_detach(ifp);
6561638Srgrimes}
6571638Srgrimes
6581638Srgrimesint
6591638Srgrimesarc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
6601638Srgrimes{
6611638Srgrimes	struct ifaddr *ifa = (struct ifaddr *) data;
6621638Srgrimes	struct ifreq *ifr = (struct ifreq *) data;
6631638Srgrimes	int error = 0;
6641638Srgrimes
6651638Srgrimes	switch (command) {
6661638Srgrimes	case SIOCSIFADDR:
6671638Srgrimes		ifp->if_flags |= IFF_UP;
6681638Srgrimes		switch (ifa->ifa_addr->sa_family) {
6691638Srgrimes#ifdef INET
67022188Sache		case AF_INET:
6711638Srgrimes			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
672127232Sschweikh			arp_ifinit(ifp, ifa);
6731638Srgrimes			break;
67422188Sache#endif
6751638Srgrimes		default:
6761638Srgrimes			ifp->if_init(ifp->if_softc);
6771638Srgrimes			break;
6781638Srgrimes		}
6791638Srgrimes		break;
6801638Srgrimes
6811638Srgrimes	case SIOCGIFADDR:
6821638Srgrimes		ifr->ifr_addr.sa_data[0] = ARC_LLADDR(ifp);
6831638Srgrimes		break;
6841638Srgrimes
6851638Srgrimes	case SIOCADDMULTI:
6861638Srgrimes	case SIOCDELMULTI:
6871638Srgrimes		if (ifr == NULL)
6881638Srgrimes			error = EAFNOSUPPORT;
6891638Srgrimes		else {
6901638Srgrimes			switch (ifr->ifr_addr.sa_family) {
6911638Srgrimes			case AF_INET:
6921638Srgrimes			case AF_INET6:
6931638Srgrimes				error = 0;
6941638Srgrimes				break;
6951638Srgrimes			default:
6961638Srgrimes				error = EAFNOSUPPORT;
6971638Srgrimes				break;
6981638Srgrimes			}
6991638Srgrimes		}
7001638Srgrimes		break;
7011638Srgrimes
7021638Srgrimes	case SIOCSIFMTU:
7031638Srgrimes		/*
7041638Srgrimes		 * Set the interface MTU.
7051638Srgrimes		 * mtu can't be larger than ARCMTU for RFC1051
7061638Srgrimes		 * and can't be larger than ARC_PHDS_MTU
7071638Srgrimes		 */
7081638Srgrimes		if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
7091638Srgrimes		    ifr->ifr_mtu > ARC_PHDS_MAXMTU)
7101638Srgrimes			error = EINVAL;
7111638Srgrimes		else
7121638Srgrimes			ifp->if_mtu = ifr->ifr_mtu;
7131638Srgrimes		break;
7141638Srgrimes	}
7151638Srgrimes
7161638Srgrimes	return (error);
7171638Srgrimes}
7181638Srgrimes
7191638Srgrimes/* based on ether_resolvemulti() */
7201638Srgrimesint
7211638Srgrimesarc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
7221638Srgrimes    struct sockaddr *sa)
723127232Sschweikh{
7241638Srgrimes	struct sockaddr_dl *sdl;
7251638Srgrimes#ifdef INET
7261638Srgrimes	struct sockaddr_in *sin;
7271638Srgrimes#endif
7281638Srgrimes#ifdef INET6
7291638Srgrimes	struct sockaddr_in6 *sin6;
7301638Srgrimes#endif
73122188Sache
7321638Srgrimes	switch(sa->sa_family) {
7331638Srgrimes	case AF_LINK:
7341638Srgrimes		/*
7351638Srgrimes		* No mapping needed. Just check that it's a valid MC address.
7361638Srgrimes		*/
7371638Srgrimes		sdl = (struct sockaddr_dl *)sa;
7381638Srgrimes		if (*LLADDR(sdl) != arcbroadcastaddr)
7391638Srgrimes			return EADDRNOTAVAIL;
7401638Srgrimes		*llsa = NULL;
7411638Srgrimes		return 0;
7421638Srgrimes#ifdef INET
7431638Srgrimes	case AF_INET:
7441638Srgrimes		sin = (struct sockaddr_in *)sa;
7451638Srgrimes		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
7461638Srgrimes			return EADDRNOTAVAIL;
7471638Srgrimes		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
7481638Srgrimes		sdl->sdl_alen = ARC_ADDR_LEN;
7491638Srgrimes		*LLADDR(sdl) = 0;
7501638Srgrimes		*llsa = (struct sockaddr *)sdl;
7511638Srgrimes		return 0;
7521638Srgrimes#endif
7531638Srgrimes#ifdef INET6
7541638Srgrimes	case AF_INET6:
7551638Srgrimes		sin6 = (struct sockaddr_in6 *)sa;
7561638Srgrimes		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
7571638Srgrimes			/*
7581638Srgrimes			 * An IP6 address of 0 means listen to all
7591638Srgrimes			 * of the Ethernet multicast address used for IP6.
7601638Srgrimes			 * (This is used for multicast routers.)
7611638Srgrimes			 */
7621638Srgrimes			ifp->if_flags |= IFF_ALLMULTI;
7631638Srgrimes			*llsa = NULL;
7641638Srgrimes			return 0;
7651638Srgrimes		}
7661638Srgrimes		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
7671638Srgrimes			return EADDRNOTAVAIL;
768127232Sschweikh		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
7691638Srgrimes		sdl->sdl_alen = ARC_ADDR_LEN;
7701638Srgrimes		*LLADDR(sdl) = 0;
7711638Srgrimes		*llsa = (struct sockaddr *)sdl;
7721638Srgrimes		return 0;
7731638Srgrimes#endif
7741638Srgrimes
7751638Srgrimes	default:
7761638Srgrimes		/*
7771638Srgrimes		 * Well, the text isn't quite right, but it's the name
7781638Srgrimes		 * that counts...
7791638Srgrimes		 */
7801638Srgrimes		return EAFNOSUPPORT;
7811638Srgrimes	}
7821638Srgrimes}
7831638Srgrimes
7841638Srgrimesstatic MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals");
7851638Srgrimes
7861638Srgrimesstatic void*
7871638Srgrimesarc_alloc(u_char type, struct ifnet *ifp)
7881638Srgrimes{
7891638Srgrimes	struct arccom	*ac;
7901638Srgrimes
7911638Srgrimes	ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO);
7921638Srgrimes	ac->ac_ifp = ifp;
7931638Srgrimes
7941638Srgrimes	return (ac);
7951638Srgrimes}
7961638Srgrimes
7971638Srgrimesstatic void
7981638Srgrimesarc_free(void *com, u_char type)
7991638Srgrimes{
8001638Srgrimes
8011638Srgrimes	free(com, M_ARCCOM);
8021638Srgrimes}
8031638Srgrimes
8041638Srgrimesstatic int
8051638Srgrimesarc_modevent(module_t mod, int type, void *data)
8061638Srgrimes{
8071638Srgrimes
8081638Srgrimes	switch (type) {
8091638Srgrimes	case MOD_LOAD:
8101638Srgrimes		if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free);
8111638Srgrimes		break;
8121638Srgrimes	case MOD_UNLOAD:
8131638Srgrimes		if_deregister_com_alloc(IFT_ARCNET);
8141638Srgrimes		break;
8151638Srgrimes	default:
8161638Srgrimes		return EOPNOTSUPP;
8171638Srgrimes	}
8181638Srgrimes
8191638Srgrimes	return (0);
8201638Srgrimes}
8211638Srgrimes
8221638Srgrimesstatic moduledata_t arc_mod = {
8231638Srgrimes	"arcnet",
8241638Srgrimes	arc_modevent,
8251638Srgrimes	0
8261638Srgrimes};
8271638Srgrimes
8281638SrgrimesDECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
8291638SrgrimesMODULE_VERSION(arcnet, 1);
8301638Srgrimes