if_arcsubr.c revision 330897
111894Speter/*	$NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $	*/
211894Speter/*	$FreeBSD: stable/11/sys/net/if_arcsubr.c 330897 2018-03-14 03:19:51Z eadler $ */
39Sjkh
49Sjkh/*-
511894Speter * SPDX-License-Identifier: BSD-4-Clause
69Sjkh *
79Sjkh * Copyright (c) 1994, 1995 Ignatios Souvatzis
89Sjkh * Copyright (c) 1982, 1989, 1993
99Sjkh *	The Regents of the University of California.  All rights reserved.
1011894Speter *
1111894Speter * Redistribution and use in source and binary forms, with or without
129Sjkh * modification, are permitted provided that the following conditions
139Sjkh * are met:
149Sjkh * 1. Redistributions of source code must retain the above copyright
159Sjkh *    notice, this list of conditions and the following disclaimer.
169Sjkh * 2. Redistributions in binary form must reproduce the above copyright
179Sjkh *    notice, this list of conditions and the following disclaimer in the
189Sjkh *    documentation and/or other materials provided with the distribution.
199Sjkh * 3. All advertising materials mentioning features or use of this software
209Sjkh *    must display the following acknowledgement:
219Sjkh *	This product includes software developed by the University of
229Sjkh *	California, Berkeley and its contributors.
239Sjkh * 4. Neither the name of the University nor the names of its contributors
249Sjkh *    may be used to endorse or promote products derived from this software
259Sjkh *    without specific prior written permission.
269Sjkh *
2711894Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2811894Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2911894Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
309Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
319Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
329Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
339Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
349Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
359Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
369Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
379Sjkh * SUCH DAMAGE.
389Sjkh *
399Sjkh * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
4011894Speter *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
4111894Speter *
4211894Speter */
4311894Speter#include "opt_inet.h"
448858Srgrimes#include "opt_inet6.h"
4511894Speter
4611894Speter#include <sys/param.h>
4711894Speter#include <sys/systm.h>
4811894Speter#include <sys/kernel.h>
4911894Speter#include <sys/module.h>
5011894Speter#include <sys/malloc.h>
5111894Speter#include <sys/mbuf.h>
5211894Speter#include <sys/protosw.h>
5311894Speter#include <sys/socket.h>
5411894Speter#include <sys/sockio.h>
5511894Speter#include <sys/errno.h>
5611894Speter#include <sys/syslog.h>
5711894Speter
5811894Speter#include <machine/cpu.h>
5911894Speter
6011894Speter#include <net/if.h>
6111894Speter#include <net/if_var.h>
6211894Speter#include <net/netisr.h>
6311894Speter#include <net/route.h>
6411894Speter#include <net/if_dl.h>
6511894Speter#include <net/if_types.h>
6611894Speter#include <net/if_arc.h>
6711894Speter#include <net/if_arp.h>
6811894Speter#include <net/bpf.h>
6911894Speter#include <net/if_llatbl.h>
7011894Speter
7111894Speter#if defined(INET) || defined(INET6)
7211894Speter#include <netinet/in.h>
7311894Speter#include <netinet/in_var.h>
7411894Speter#include <netinet/if_ether.h>
7511894Speter#endif
7611894Speter
7711894Speter#ifdef INET6
7811894Speter#include <netinet6/nd6.h>
799Sjkh#endif
809Sjkh
819Sjkh#define ARCNET_ALLOW_BROKEN_ARP
829Sjkh
839Sjkhstatic struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
849Sjkhstatic int arc_resolvemulti(struct ifnet *, struct sockaddr **,
859Sjkh			    struct sockaddr *);
869Sjkh
879Sjkhu_int8_t  arcbroadcastaddr = 0;
889Sjkh
899Sjkh#define ARC_LLADDR(ifp)	(*(u_int8_t *)IF_LLADDR(ifp))
909Sjkh
919Sjkh#define senderr(e) { error = (e); goto bad;}
929Sjkh#define SIN(s)	((const struct sockaddr_in *)(s))
939Sjkh
949Sjkh/*
959Sjkh * ARCnet output routine.
969Sjkh * Encapsulate a packet of type family for the local net.
979Sjkh * Assumes that ifp is actually pointer to arccom structure.
989Sjkh */
999Sjkhint
1009Sjkharc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
1019Sjkh    struct route *ro)
1029Sjkh{
1039Sjkh	struct arc_header	*ah;
1049Sjkh	int			error;
1059Sjkh	u_int8_t		atype, adst;
1069Sjkh	int			loop_copy = 0;
10711894Speter	int			isphds;
10811894Speter#if defined(INET) || defined(INET6)
1099Sjkh	int			is_gw = 0;
1109Sjkh#endif
1119Sjkh
1129Sjkh	if (!((ifp->if_flags & IFF_UP) &&
1139Sjkh	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
1149Sjkh		return(ENETDOWN); /* m, m1 aren't initialized yet */
1159Sjkh
1168858Srgrimes	error = 0;
1179Sjkh#if defined(INET) || defined(INET6)
1189Sjkh	if (ro != NULL)
1198858Srgrimes		is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
1209Sjkh#endif
1219Sjkh
1229Sjkh	switch (dst->sa_family) {
1238858Srgrimes#ifdef INET
1249Sjkh	case AF_INET:
1259Sjkh
1269Sjkh		/*
1278858Srgrimes		 * For now, use the simple IP addr -> ARCnet addr mapping
1289Sjkh		 */
1299Sjkh		if (m->m_flags & (M_BCAST|M_MCAST))
1308858Srgrimes			adst = arcbroadcastaddr; /* ARCnet broadcast address */
1319Sjkh		else if (ifp->if_flags & IFF_NOARP)
1329Sjkh			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
1338858Srgrimes		else {
1349Sjkh			error = arpresolve(ifp, is_gw, m, dst, &adst, NULL,
13511894Speter			    NULL);
1368858Srgrimes			if (error)
1379Sjkh				return (error == EWOULDBLOCK ? 0 : error);
13811894Speter		}
1398858Srgrimes
1409Sjkh		atype = (ifp->if_flags & IFF_LINK0) ?
1419Sjkh			ARCTYPE_IP_OLD : ARCTYPE_IP;
1429Sjkh		break;
1439Sjkh	case AF_ARP:
1449Sjkh	{
1458858Srgrimes		struct arphdr *ah;
1469Sjkh		ah = mtod(m, struct arphdr *);
14711894Speter		ah->ar_hrd = htons(ARPHRD_ARCNET);
1489Sjkh
1498858Srgrimes		loop_copy = -1; /* if this is for us, don't do it */
1509Sjkh
1519Sjkh		switch(ntohs(ah->ar_op)) {
1528858Srgrimes		case ARPOP_REVREQUEST:
1539Sjkh		case ARPOP_REVREPLY:
1549Sjkh			atype = ARCTYPE_REVARP;
1559Sjkh			break;
1569Sjkh		case ARPOP_REQUEST:
1579Sjkh		case ARPOP_REPLY:
1589Sjkh		default:
1599Sjkh			atype = ARCTYPE_ARP;
1609Sjkh			break;
1619Sjkh		}
16211894Speter
1639Sjkh		if (m->m_flags & M_BCAST)
1649Sjkh			bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN);
1659Sjkh		else
1669Sjkh			bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN);
1679Sjkh
1689Sjkh	}
1699Sjkh	break;
1709Sjkh#endif
1719Sjkh#ifdef INET6
1729Sjkh	case AF_INET6:
1739Sjkh		if ((m->m_flags & M_MCAST) != 0)
1749Sjkh			adst = arcbroadcastaddr; /* ARCnet broadcast address */
1759Sjkh		else {
1769Sjkh			error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL,
1779Sjkh			    NULL);
1789Sjkh			if (error != 0)
1799Sjkh				return (error == EWOULDBLOCK ? 0 : error);
1809Sjkh		}
18111894Speter		atype = ARCTYPE_INET6;
1829Sjkh		break;
18311894Speter#endif
18411894Speter	case AF_UNSPEC:
18511894Speter	    {
18611894Speter		const struct arc_header *ah;
18711894Speter
18811894Speter		loop_copy = -1;
18911894Speter		ah = (const struct arc_header *)dst->sa_data;
19011894Speter		adst = ah->arc_dhost;
19111894Speter		atype = ah->arc_type;
19211894Speter
19311894Speter		if (atype == ARCTYPE_ARP) {
1949Sjkh			atype = (ifp->if_flags & IFF_LINK0) ?
1959Sjkh			    ARCTYPE_ARP_OLD: ARCTYPE_ARP;
1969Sjkh
1979Sjkh#ifdef ARCNET_ALLOW_BROKEN_ARP
1989Sjkh			/*
19911894Speter			 * XXX It's not clear per RFC826 if this is needed, but
2009Sjkh			 * "assigned numbers" say this is wrong.
2019Sjkh			 * However, e.g., AmiTCP 3.0Beta used it... we make this
2029Sjkh			 * switchable for emergency cases. Not perfect, but...
2039Sjkh			 */
2049Sjkh			if (ifp->if_flags & IFF_LINK2)
20511894Speter				mtod(m, struct arphdr *)->ar_pro = atype - 1;
2069Sjkh#endif
20711894Speter		}
2089Sjkh		break;
2099Sjkh	    }
2109Sjkh	default:
2119Sjkh		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
2129Sjkh		senderr(EAFNOSUPPORT);
2139Sjkh	}
21411894Speter
21511894Speter	isphds = arc_isphds(atype);
21611894Speter	M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT);
21711894Speter	if (m == NULL)
2189Sjkh		senderr(ENOBUFS);
21911894Speter	ah = mtod(m, struct arc_header *);
22011894Speter	ah->arc_type = atype;
22111894Speter	ah->arc_dhost = adst;
22211894Speter	ah->arc_shost = ARC_LLADDR(ifp);
22311894Speter	if (isphds) {
22411894Speter		ah->arc_flag = 0;
22511894Speter		ah->arc_seqid = 0;
22611894Speter	}
22711894Speter
22811894Speter	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
22911894Speter		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
23011894Speter			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
23111894Speter
23211894Speter			(void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
23311894Speter		} else if (ah->arc_dhost == ah->arc_shost) {
23411894Speter			(void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
23511894Speter			return (0);     /* XXX */
23611894Speter		}
23711894Speter	}
23811894Speter
23911894Speter	BPF_MTAP(ifp, m);
24011894Speter
24111894Speter	error = ifp->if_transmit(ifp, m);
24211894Speter
24311894Speter	return (error);
24411894Speter
24511894Speterbad:
24611894Speter	if (m)
24711894Speter		m_freem(m);
24811894Speter	return (error);
24911894Speter}
25011894Speter
25111894Spetervoid
25211894Speterarc_frag_init(struct ifnet *ifp)
25311894Speter{
25411894Speter	struct arccom *ac;
25511894Speter
25611894Speter	ac = (struct arccom *)ifp->if_l2com;
25711894Speter	ac->curr_frag = 0;
2589Sjkh}
2599Sjkh
2609Sjkhstruct mbuf *
26111894Speterarc_frag_next(struct ifnet *ifp)
2629Sjkh{
2639Sjkh	struct arccom *ac;
2649Sjkh	struct mbuf *m;
2659Sjkh	struct arc_header *ah;
2669Sjkh
2679Sjkh	ac = (struct arccom *)ifp->if_l2com;
2689Sjkh	if ((m = ac->curr_frag) == NULL) {
2699Sjkh		int tfrags;
2709Sjkh
2719Sjkh		/* dequeue new packet */
2729Sjkh		IF_DEQUEUE(&ifp->if_snd, m);
2739Sjkh		if (m == NULL)
2749Sjkh			return 0;
2759Sjkh
2769Sjkh		ah = mtod(m, struct arc_header *);
2779Sjkh		if (!arc_isphds(ah->arc_type))
2789Sjkh			return m;
2799Sjkh
28011894Speter		++ac->ac_seqid;		/* make the seqid unique */
28111894Speter		tfrags = howmany(m->m_pkthdr.len, ARC_MAX_DATA);
28211894Speter		ac->fsflag = 2 * tfrags - 3;
28311894Speter		ac->sflag = 0;
2849Sjkh		ac->rsflag = ac->fsflag;
2859Sjkh		ac->arc_dhost = ah->arc_dhost;
2869Sjkh		ac->arc_shost = ah->arc_shost;
28711894Speter		ac->arc_type = ah->arc_type;
2889Sjkh
2899Sjkh		m_adj(m, ARC_HDRNEWLEN);
2909Sjkh		ac->curr_frag = m;
2919Sjkh	}
2929Sjkh
2939Sjkh	/* split out next fragment and return it */
2949Sjkh	if (ac->sflag < ac->fsflag) {
2959Sjkh		/* we CAN'T have short packets here */
29611894Speter		ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
29711894Speter		if (ac->curr_frag == 0) {
29811894Speter			m_freem(m);
2999Sjkh			return 0;
30011894Speter		}
30111894Speter
3029Sjkh		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
3039Sjkh		if (m == NULL) {
30411894Speter			m_freem(ac->curr_frag);
30511894Speter			ac->curr_frag = 0;
3069Sjkh			return 0;
3079Sjkh		}
30811894Speter
3099Sjkh		ah = mtod(m, struct arc_header *);
31011894Speter		ah->arc_flag = ac->rsflag;
3119Sjkh		ah->arc_seqid = ac->ac_seqid;
3129Sjkh
3139Sjkh		ac->sflag += 2;
3149Sjkh		ac->rsflag = ac->sflag;
31511894Speter	} else if ((m->m_pkthdr.len >=
3169Sjkh	    ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
3179Sjkh	    (m->m_pkthdr.len <=
3189Sjkh	    ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
3199Sjkh		ac->curr_frag = 0;
3209Sjkh
3219Sjkh		M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
3229Sjkh		if (m == NULL)
3239Sjkh			return 0;
3249Sjkh
3259Sjkh		ah = mtod(m, struct arc_header *);
3269Sjkh		ah->arc_flag = 0xFF;
3279Sjkh		ah->arc_seqid = 0xFFFF;
32811894Speter		ah->arc_type2 = ac->arc_type;
3299Sjkh		ah->arc_flag2 = ac->sflag;
3309Sjkh		ah->arc_seqid2 = ac->ac_seqid;
3319Sjkh	} else {
3329Sjkh		ac->curr_frag = 0;
3339Sjkh
3349Sjkh		M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
33511894Speter		if (m == NULL)
3369Sjkh			return 0;
3379Sjkh
3389Sjkh		ah = mtod(m, struct arc_header *);
3399Sjkh		ah->arc_flag = ac->sflag;
3409Sjkh		ah->arc_seqid = ac->ac_seqid;
34111894Speter	}
3429Sjkh
34311894Speter	ah->arc_dhost = ac->arc_dhost;
3449Sjkh	ah->arc_shost = ac->arc_shost;
3459Sjkh	ah->arc_type = ac->arc_type;
3469Sjkh
3479Sjkh	return m;
3489Sjkh}
34911894Speter
3509Sjkh/*
3519Sjkh * Defragmenter. Returns mbuf if last packet found, else
3529Sjkh * NULL. frees incoming mbuf as necessary.
3539Sjkh */
3549Sjkh
3559Sjkhstatic __inline struct mbuf *
3569Sjkharc_defrag(struct ifnet *ifp, struct mbuf *m)
3579Sjkh{
3589Sjkh	struct arc_header *ah, *ah1;
3599Sjkh	struct arccom *ac;
3609Sjkh	struct ac_frag *af;
3619Sjkh	struct mbuf *m1;
3629Sjkh	char *s;
3639Sjkh	int newflen;
3649Sjkh	u_char src,dst,typ;
3659Sjkh
3669Sjkh	ac = (struct arccom *)ifp->if_l2com;
3679Sjkh
3689Sjkh	if (m->m_len < ARC_HDRNEWLEN) {
3699Sjkh		m = m_pullup(m, ARC_HDRNEWLEN);
3709Sjkh		if (m == NULL) {
3719Sjkh			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3729Sjkh			return NULL;
3739Sjkh		}
3749Sjkh	}
3759Sjkh
3769Sjkh	ah = mtod(m, struct arc_header *);
3779Sjkh	typ = ah->arc_type;
3789Sjkh
3799Sjkh	if (!arc_isphds(typ))
3809Sjkh		return m;
3819Sjkh
3829Sjkh	src = ah->arc_shost;
3839Sjkh	dst = ah->arc_dhost;
3849Sjkh
3859Sjkh	if (ah->arc_flag == 0xff) {
3869Sjkh		m_adj(m, 4);
3879Sjkh
3889Sjkh		if (m->m_len < ARC_HDRNEWLEN) {
3899Sjkh			m = m_pullup(m, ARC_HDRNEWLEN);
39011894Speter			if (m == NULL) {
3919Sjkh				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3929Sjkh				return NULL;
3939Sjkh			}
39411894Speter		}
39511894Speter
3969Sjkh		ah = mtod(m, struct arc_header *);
39711894Speter	}
3989Sjkh
3999Sjkh	af = &ac->ac_fragtab[src];
40011894Speter	m1 = af->af_packet;
40111894Speter	s = "debug code error";
4029Sjkh
4039Sjkh	if (ah->arc_flag & 1) {
4049Sjkh		/*
4059Sjkh		 * first fragment. We always initialize, which is
4069Sjkh		 * about the right thing to do, as we only want to
4079Sjkh		 * accept one fragmented packet per src at a time.
4089Sjkh		 */
4099Sjkh		if (m1 != NULL)
4109Sjkh			m_freem(m1);
4119Sjkh
4129Sjkh		af->af_packet = m;
4139Sjkh		m1 = m;
4149Sjkh		af->af_maxflag = ah->arc_flag;
4159Sjkh		af->af_lastseen = 0;
4169Sjkh		af->af_seqid = ah->arc_seqid;
4179Sjkh
4189Sjkh		return NULL;
4199Sjkh		/* notreached */
4209Sjkh	} else {
4219Sjkh		/* check for unfragmented packet */
4229Sjkh		if (ah->arc_flag == 0)
4239Sjkh			return m;
4249Sjkh
4259Sjkh		/* do we have a first packet from that src? */
4269Sjkh		if (m1 == NULL) {
4279Sjkh			s = "no first frag";
4289Sjkh			goto outofseq;
4299Sjkh		}
4309Sjkh
4319Sjkh		ah1 = mtod(m1, struct arc_header *);
4329Sjkh
4339Sjkh		if (ah->arc_seqid != ah1->arc_seqid) {
4349Sjkh			s = "seqid differs";
4359Sjkh			goto outofseq;
4369Sjkh		}
43711894Speter
4389Sjkh		if (typ != ah1->arc_type) {
4399Sjkh			s = "type differs";
4409Sjkh			goto outofseq;
4419Sjkh		}
4429Sjkh
4439Sjkh		if (dst != ah1->arc_dhost) {
4449Sjkh			s = "dest host differs";
4459Sjkh			goto outofseq;
4469Sjkh		}
4479Sjkh
4489Sjkh		/* typ, seqid and dst are ok here. */
4499Sjkh
4509Sjkh		if (ah->arc_flag == af->af_lastseen) {
4519Sjkh			m_freem(m);
4529Sjkh			return NULL;
4539Sjkh		}
4549Sjkh
4559Sjkh		if (ah->arc_flag == af->af_lastseen + 2) {
4569Sjkh			/* ok, this is next fragment */
4579Sjkh			af->af_lastseen = ah->arc_flag;
4589Sjkh			m_adj(m,ARC_HDRNEWLEN);
4599Sjkh
4609Sjkh			/*
4619Sjkh			 * m_cat might free the first mbuf (with pkthdr)
4629Sjkh			 * in 2nd chain; therefore:
4639Sjkh			 */
4649Sjkh
4659Sjkh			newflen = m->m_pkthdr.len;
4669Sjkh
4679Sjkh			m_cat(m1,m);
4689Sjkh
4699Sjkh			m1->m_pkthdr.len += newflen;
4709Sjkh
4719Sjkh			/* is it the last one? */
4729Sjkh			if (af->af_lastseen > af->af_maxflag) {
4739Sjkh				af->af_packet = NULL;
4749Sjkh				return(m1);
4759Sjkh			} else
4769Sjkh				return NULL;
4779Sjkh		}
4789Sjkh		s = "other reason";
4799Sjkh		/* if all else fails, it is out of sequence, too */
4809Sjkh	}
4819Sjkhoutofseq:
4829Sjkh	if (m1) {
4839Sjkh		m_freem(m1);
4849Sjkh		af->af_packet = NULL;
4859Sjkh	}
4869Sjkh
4879Sjkh	if (m)
4889Sjkh		m_freem(m);
4899Sjkh
4909Sjkh	log(LOG_INFO,"%s: got out of seq. packet: %s\n",
4919Sjkh	    ifp->if_xname, s);
4929Sjkh
4939Sjkh	return NULL;
4949Sjkh}
4959Sjkh
4969Sjkh/*
4979Sjkh * return 1 if Packet Header Definition Standard, else 0.
4989Sjkh * For now: old IP, old ARP aren't obviously. Lacking correct information,
4999Sjkh * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
5009Sjkh * (Apple and Novell corporations were involved, among others, in PHDS work).
5019Sjkh * Easiest is to assume that everybody else uses that, too.
5029Sjkh */
5039Sjkhint
5049Sjkharc_isphds(u_int8_t type)
5059Sjkh{
5069Sjkh	return (type != ARCTYPE_IP_OLD &&
5079Sjkh		type != ARCTYPE_ARP_OLD &&
5089Sjkh		type != ARCTYPE_DIAGNOSE);
5099Sjkh}
51011894Speter
5119Sjkh/*
5129Sjkh * Process a received Arcnet packet;
5139Sjkh * the packet is in the mbuf chain m with
5149Sjkh * the ARCnet header.
5159Sjkh */
5169Sjkhvoid
5179Sjkharc_input(struct ifnet *ifp, struct mbuf *m)
5189Sjkh{
5199Sjkh	struct arc_header *ah;
5209Sjkh	int isr;
5219Sjkh	u_int8_t atype;
5229Sjkh
5239Sjkh	if ((ifp->if_flags & IFF_UP) == 0) {
5249Sjkh		m_freem(m);
5259Sjkh		return;
52611894Speter	}
5279Sjkh
5289Sjkh	/* possibly defragment: */
5299Sjkh	m = arc_defrag(ifp, m);
5309Sjkh	if (m == NULL)
5319Sjkh		return;
5329Sjkh
5339Sjkh	BPF_MTAP(ifp, m);
5349Sjkh
5359Sjkh	ah = mtod(m, struct arc_header *);
5369Sjkh	/* does this belong to us? */
5379Sjkh	if ((ifp->if_flags & IFF_PROMISC) == 0
5389Sjkh	    && ah->arc_dhost != arcbroadcastaddr
5399Sjkh	    && ah->arc_dhost != ARC_LLADDR(ifp)) {
5409Sjkh		m_freem(m);
5419Sjkh		return;
5429Sjkh	}
5439Sjkh
5449Sjkh	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
54511894Speter
5469Sjkh	if (ah->arc_dhost == arcbroadcastaddr) {
5479Sjkh		m->m_flags |= M_BCAST|M_MCAST;
54811894Speter		if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
5499Sjkh	}
5509Sjkh
5519Sjkh	atype = ah->arc_type;
5529Sjkh	switch (atype) {
5539Sjkh#ifdef INET
5549Sjkh	case ARCTYPE_IP:
5559Sjkh		m_adj(m, ARC_HDRNEWLEN);
5569Sjkh		isr = NETISR_IP;
55711894Speter		break;
55811894Speter
55911894Speter	case ARCTYPE_IP_OLD:
56011894Speter		m_adj(m, ARC_HDRLEN);
56111894Speter		isr = NETISR_IP;
56211894Speter		break;
56311894Speter
56411894Speter	case ARCTYPE_ARP:
5659Sjkh		if (ifp->if_flags & IFF_NOARP) {
5669Sjkh			/* Discard packet if ARP is disabled on interface */
5679Sjkh			m_freem(m);
5689Sjkh			return;
5699Sjkh		}
5709Sjkh		m_adj(m, ARC_HDRNEWLEN);
57111894Speter		isr = NETISR_ARP;
57211894Speter#ifdef ARCNET_ALLOW_BROKEN_ARP
5739Sjkh		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
5749Sjkh#endif
57511894Speter		break;
5769Sjkh
57711894Speter	case ARCTYPE_ARP_OLD:
5789Sjkh		if (ifp->if_flags & IFF_NOARP) {
57911894Speter			/* Discard packet if ARP is disabled on interface */
5809Sjkh			m_freem(m);
5819Sjkh			return;
5829Sjkh		}
5839Sjkh		m_adj(m, ARC_HDRLEN);
5849Sjkh		isr = NETISR_ARP;
5859Sjkh#ifdef ARCNET_ALLOW_BROKEN_ARP
5869Sjkh		mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
5879Sjkh#endif
5889Sjkh		break;
5899Sjkh#endif
5909Sjkh#ifdef INET6
5919Sjkh	case ARCTYPE_INET6:
5929Sjkh		m_adj(m, ARC_HDRNEWLEN);
5939Sjkh		isr = NETISR_IPV6;
5949Sjkh		break;
5959Sjkh#endif
5969Sjkh	default:
5979Sjkh		m_freem(m);
5989Sjkh		return;
5999Sjkh	}
60011894Speter	M_SETFIB(m, ifp->if_fib);
6019Sjkh	netisr_dispatch(isr, m);
6029Sjkh}
6039Sjkh
6049Sjkh/*
6059Sjkh * Register (new) link level address.
6069Sjkh */
6079Sjkhvoid
6089Sjkharc_storelladdr(struct ifnet *ifp, u_int8_t lla)
6099Sjkh{
6109Sjkh	ARC_LLADDR(ifp) = lla;
6119Sjkh}
6129Sjkh
6139Sjkh/*
6149Sjkh * Perform common duties while attaching to interface list
6159Sjkh */
6169Sjkhvoid
6179Sjkharc_ifattach(struct ifnet *ifp, u_int8_t lla)
6189Sjkh{
6199Sjkh	struct ifaddr *ifa;
6209Sjkh	struct sockaddr_dl *sdl;
62111894Speter	struct arccom *ac;
6229Sjkh
6239Sjkh	if_attach(ifp);
6249Sjkh	ifp->if_addrlen = 1;
6259Sjkh	ifp->if_hdrlen = ARC_HDRLEN;
6269Sjkh	ifp->if_mtu = 1500;
6279Sjkh	ifp->if_resolvemulti = arc_resolvemulti;
6289Sjkh	if (ifp->if_baudrate == 0)
6299Sjkh		ifp->if_baudrate = 2500000;
6309Sjkh	ifa = ifp->if_addr;
6319Sjkh	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
63211894Speter	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
6339Sjkh	sdl->sdl_type = IFT_ARCNET;
6349Sjkh	sdl->sdl_alen = ifp->if_addrlen;
6359Sjkh
63611894Speter	if (ifp->if_flags & IFF_BROADCAST)
63711894Speter		ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
6389Sjkh
6399Sjkh	ac = (struct arccom *)ifp->if_l2com;
6409Sjkh	ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
6419Sjkh	if (lla == 0) {
6429Sjkh		/* XXX this message isn't entirely clear, to me -- cgd */
6439Sjkh		log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
6449Sjkh		   ifp->if_xname, ifp->if_xname);
6459Sjkh	}
6469Sjkh	arc_storelladdr(ifp, lla);
6479Sjkh
6489Sjkh	ifp->if_broadcastaddr = &arcbroadcastaddr;
6499Sjkh
6509Sjkh	bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
6519Sjkh}
6529Sjkh
6539Sjkhvoid
6549Sjkharc_ifdetach(struct ifnet *ifp)
6559Sjkh{
6569Sjkh	bpfdetach(ifp);
65711894Speter	if_detach(ifp);
6589Sjkh}
6599Sjkh
6609Sjkhint
6619Sjkharc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
66211894Speter{
66311894Speter	struct ifaddr *ifa = (struct ifaddr *) data;
6649Sjkh	struct ifreq *ifr = (struct ifreq *) data;
66511894Speter	int error = 0;
66611894Speter
66711894Speter	switch (command) {
6689Sjkh	case SIOCSIFADDR:
6699Sjkh		ifp->if_flags |= IFF_UP;
6709Sjkh		switch (ifa->ifa_addr->sa_family) {
6719Sjkh#ifdef INET
6729Sjkh		case AF_INET:
6739Sjkh			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
6749Sjkh			arp_ifinit(ifp, ifa);
6759Sjkh			break;
6769Sjkh#endif
6779Sjkh		default:
6789Sjkh			ifp->if_init(ifp->if_softc);
6799Sjkh			break;
6809Sjkh		}
6819Sjkh		break;
6829Sjkh
6839Sjkh	case SIOCGIFADDR:
68411894Speter		{
6859Sjkh			struct sockaddr *sa;
6869Sjkh
6879Sjkh			sa = (struct sockaddr *) &ifr->ifr_data;
68811894Speter			*(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
68911894Speter		}
69011894Speter		break;
6919Sjkh
69211894Speter	case SIOCADDMULTI:
6939Sjkh	case SIOCDELMULTI:
6949Sjkh		if (ifr == NULL)
6959Sjkh			error = EAFNOSUPPORT;
69611894Speter		else {
6979Sjkh			switch (ifr->ifr_addr.sa_family) {
6989Sjkh			case AF_INET:
6999Sjkh			case AF_INET6:
7009Sjkh				error = 0;
7019Sjkh				break;
70211894Speter			default:
7039Sjkh				error = EAFNOSUPPORT;
70411894Speter				break;
70511894Speter			}
7069Sjkh		}
7079Sjkh		break;
70811894Speter
7099Sjkh	case SIOCSIFMTU:
71011894Speter		/*
71111894Speter		 * Set the interface MTU.
7129Sjkh		 * mtu can't be larger than ARCMTU for RFC1051
7139Sjkh		 * and can't be larger than ARC_PHDS_MTU
7149Sjkh		 */
7159Sjkh		if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
71611894Speter		    ifr->ifr_mtu > ARC_PHDS_MAXMTU)
71711894Speter			error = EINVAL;
7189Sjkh		else
7199Sjkh			ifp->if_mtu = ifr->ifr_mtu;
7209Sjkh		break;
7219Sjkh	}
72211894Speter
72311894Speter	return (error);
72411894Speter}
7259Sjkh
7269Sjkh/* based on ether_resolvemulti() */
7279Sjkhint
7289Sjkharc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
72911894Speter    struct sockaddr *sa)
73011894Speter{
7319Sjkh	struct sockaddr_dl *sdl;
7329Sjkh#ifdef INET
7339Sjkh	struct sockaddr_in *sin;
7349Sjkh#endif
73511894Speter#ifdef INET6
7369Sjkh	struct sockaddr_in6 *sin6;
73711894Speter#endif
7389Sjkh
73911894Speter	switch(sa->sa_family) {
7409Sjkh	case AF_LINK:
7419Sjkh		/*
7429Sjkh		* No mapping needed. Just check that it's a valid MC address.
7439Sjkh		*/
7449Sjkh		sdl = (struct sockaddr_dl *)sa;
7459Sjkh		if (*LLADDR(sdl) != arcbroadcastaddr)
7469Sjkh			return EADDRNOTAVAIL;
74711894Speter		*llsa = NULL;
74811894Speter		return 0;
7499Sjkh#ifdef INET
7509Sjkh	case AF_INET:
7519Sjkh		sin = (struct sockaddr_in *)sa;
75211894Speter		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
7539Sjkh			return EADDRNOTAVAIL;
75411894Speter		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
7559Sjkh		sdl->sdl_alen = ARC_ADDR_LEN;
75611894Speter		*LLADDR(sdl) = 0;
7579Sjkh		*llsa = (struct sockaddr *)sdl;
7589Sjkh		return 0;
7599Sjkh#endif
7609Sjkh#ifdef INET6
7619Sjkh	case AF_INET6:
7629Sjkh		sin6 = (struct sockaddr_in6 *)sa;
7639Sjkh		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
7649Sjkh			/*
76511894Speter			 * An IP6 address of 0 means listen to all
7669Sjkh			 * of the Ethernet multicast address used for IP6.
7679Sjkh			 * (This is used for multicast routers.)
7689Sjkh			 */
7699Sjkh			ifp->if_flags |= IFF_ALLMULTI;
7709Sjkh			*llsa = NULL;
7719Sjkh			return 0;
7729Sjkh		}
77311894Speter		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
7749Sjkh			return EADDRNOTAVAIL;
7759Sjkh		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
7769Sjkh		sdl->sdl_alen = ARC_ADDR_LEN;
7779Sjkh		*LLADDR(sdl) = 0;
7789Sjkh		*llsa = (struct sockaddr *)sdl;
7799Sjkh		return 0;
7809Sjkh#endif
7819Sjkh
7829Sjkh	default:
7839Sjkh		/*
78411894Speter		 * Well, the text isn't quite right, but it's the name
7859Sjkh		 * that counts...
7869Sjkh		 */
7879Sjkh		return EAFNOSUPPORT;
7889Sjkh	}
7899Sjkh}
7909Sjkh
7919Sjkhstatic MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals");
7929Sjkh
79311894Speterstatic void*
79411894Speterarc_alloc(u_char type, struct ifnet *ifp)
79511894Speter{
7969Sjkh	struct arccom	*ac;
7979Sjkh
79811894Speter	ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO);
79911894Speter	ac->ac_ifp = ifp;
80011894Speter
80111894Speter	return (ac);
80211894Speter}
80311894Speter
80411894Speterstatic void
80511894Speterarc_free(void *com, u_char type)
80611894Speter{
80711894Speter
80811894Speter	free(com, M_ARCCOM);
80911894Speter}
81011894Speter
81111894Speterstatic int
81211894Speterarc_modevent(module_t mod, int type, void *data)
8139Sjkh{
81411894Speter
81511894Speter	switch (type) {
81611894Speter	case MOD_LOAD:
81711894Speter		if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free);
8189Sjkh		break;
8199Sjkh	case MOD_UNLOAD:
8209Sjkh		if_deregister_com_alloc(IFT_ARCNET);
82111894Speter		break;
82211894Speter	default:
82311894Speter		return EOPNOTSUPP;
82411894Speter	}
82511894Speter
82611894Speter	return (0);
82711894Speter}
82811894Speter
82911894Speterstatic moduledata_t arc_mod = {
8309Sjkh	"arcnet",
83111894Speter	arc_modevent,
83211894Speter	0
83311894Speter};
83411894Speter
83511894SpeterDECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
83611894SpeterMODULE_VERSION(arcnet, 1);
83711894Speter