if_arcsubr.c revision 111767
189099Sfjoe/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 289099Sfjoe/* $FreeBSD: head/sys/net/if_arcsubr.c 111767 2003-03-02 21:34:37Z 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; 14589099Sfjoe#endif 14689099Sfjoe#ifdef INET6 14789099Sfjoe case AF_INET6: 14889099Sfjoe#ifdef OLDIP6OUTPUT 14989099Sfjoe if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst)) 15089099Sfjoe return(0); /* if not yet resolves */ 15189099Sfjoe#else 15289099Sfjoe if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst)) 15389099Sfjoe return(0); /* it must be impossible, but... */ 15489099Sfjoe#endif /* OLDIP6OUTPUT */ 15589099Sfjoe atype = ARCTYPE_INET6; 15689099Sfjoe break; 15789099Sfjoe#endif 158109771Sfjoe#ifdef IPX 159109771Sfjoe case AF_IPX: 160109771Sfjoe adst = SIPX(dst)->sipx_addr.x_host.c_host[5]; 161109771Sfjoe atype = ARCTYPE_IPX; 162109771Sfjoe if (adst == 0xff) 163109771Sfjoe adst = arcbroadcastaddr; 164109771Sfjoe break; 165109771Sfjoe#endif 16689099Sfjoe 16789099Sfjoe case AF_UNSPEC: 168109771Sfjoe loop_copy = -1; 16989099Sfjoe ah = (struct arc_header *)dst->sa_data; 17089099Sfjoe adst = ah->arc_dhost; 17189099Sfjoe atype = ah->arc_type; 17289099Sfjoe 17389099Sfjoe if (atype == ARCTYPE_ARP) { 17489099Sfjoe atype = (ifp->if_flags & IFF_LINK0) ? 17589099Sfjoe ARCTYPE_ARP_OLD: ARCTYPE_ARP; 17689099Sfjoe 17789099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP 17889099Sfjoe /* 17989099Sfjoe * XXX It's not clear per RFC826 if this is needed, but 18089099Sfjoe * "assigned numbers" say this is wrong. 18189099Sfjoe * However, e.g., AmiTCP 3.0Beta used it... we make this 18289099Sfjoe * switchable for emergency cases. Not perfect, but... 18389099Sfjoe */ 18489099Sfjoe if (ifp->if_flags & IFF_LINK2) 185109771Sfjoe mtod(m, struct arphdr *)->ar_pro = atype - 1; 18689099Sfjoe#endif 18789099Sfjoe } 18889099Sfjoe break; 18989099Sfjoe 19089099Sfjoe default: 191105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 19289099Sfjoe senderr(EAFNOSUPPORT); 19389099Sfjoe } 19489099Sfjoe 195110106Sfjoe isphds = arc_isphds(atype); 196111119Simp M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT); 19789099Sfjoe if (m == 0) 19889099Sfjoe senderr(ENOBUFS); 19989099Sfjoe ah = mtod(m, struct arc_header *); 20089099Sfjoe ah->arc_type = atype; 20189099Sfjoe ah->arc_dhost = adst; 202110106Sfjoe ah->arc_shost = ARC_LLADDR(ifp); 203110106Sfjoe if (isphds) { 204110106Sfjoe ah->arc_flag = 0; 205110106Sfjoe ah->arc_seqid = 0; 206110106Sfjoe } 20789099Sfjoe 208109771Sfjoe if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 209109771Sfjoe if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 210109771Sfjoe struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 211109771Sfjoe 212109771Sfjoe (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); 213109771Sfjoe } else if (ah->arc_dhost == ah->arc_shost) { 214109771Sfjoe (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); 215109771Sfjoe return (0); /* XXX */ 216109771Sfjoe } 217109771Sfjoe } 218109771Sfjoe 219106939Ssam BPF_MTAP(ifp, m); 22089099Sfjoe 22189099Sfjoe if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) { 22289099Sfjoe m = 0; 22389099Sfjoe senderr(ENOBUFS); 22489099Sfjoe } 22589099Sfjoe 22689099Sfjoe return (error); 22789099Sfjoe 22889099Sfjoebad: 22989099Sfjoe if (m) 23089099Sfjoe m_freem(m); 23189099Sfjoe return (error); 23289099Sfjoe} 23389099Sfjoe 23489099Sfjoevoid 23589099Sfjoearc_frag_init(ifp) 23689099Sfjoe struct ifnet *ifp; 23789099Sfjoe{ 23889099Sfjoe struct arccom *ac; 23989099Sfjoe 24089099Sfjoe ac = (struct arccom *)ifp; 24189099Sfjoe ac->curr_frag = 0; 24289099Sfjoe} 24389099Sfjoe 24489099Sfjoestruct mbuf * 24589099Sfjoearc_frag_next(ifp) 24689099Sfjoe struct ifnet *ifp; 24789099Sfjoe{ 24889099Sfjoe struct arccom *ac; 24989099Sfjoe struct mbuf *m; 25089099Sfjoe struct arc_header *ah; 25189099Sfjoe 25289099Sfjoe ac = (struct arccom *)ifp; 25389099Sfjoe if ((m = ac->curr_frag) == 0) { 25489099Sfjoe int tfrags; 25589099Sfjoe 25689099Sfjoe /* dequeue new packet */ 25789099Sfjoe IF_DEQUEUE(&ifp->if_snd, m); 25889099Sfjoe if (m == 0) 25989099Sfjoe return 0; 26089099Sfjoe 26189099Sfjoe ah = mtod(m, struct arc_header *); 26289099Sfjoe if (!arc_isphds(ah->arc_type)) 26389099Sfjoe return m; 26489099Sfjoe 26589099Sfjoe ++ac->ac_seqid; /* make the seqid unique */ 266109771Sfjoe tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA; 26789099Sfjoe ac->fsflag = 2 * tfrags - 3; 26889099Sfjoe ac->sflag = 0; 26989099Sfjoe ac->rsflag = ac->fsflag; 27089099Sfjoe ac->arc_dhost = ah->arc_dhost; 27189099Sfjoe ac->arc_shost = ah->arc_shost; 27289099Sfjoe ac->arc_type = ah->arc_type; 27389099Sfjoe 274110106Sfjoe m_adj(m, ARC_HDRNEWLEN); 27589099Sfjoe ac->curr_frag = m; 27689099Sfjoe } 27789099Sfjoe 27889099Sfjoe /* split out next fragment and return it */ 27989099Sfjoe if (ac->sflag < ac->fsflag) { 28089099Sfjoe /* we CAN'T have short packets here */ 281111119Simp ac->curr_frag = m_split(m, ARC_MAX_DATA, M_DONTWAIT); 28289099Sfjoe if (ac->curr_frag == 0) { 28393750Sluigi m_freem(m); 28489099Sfjoe return 0; 28589099Sfjoe } 28689099Sfjoe 287111119Simp M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 28889099Sfjoe if (m == 0) { 28993750Sluigi m_freem(ac->curr_frag); 29089099Sfjoe ac->curr_frag = 0; 29189099Sfjoe return 0; 29289099Sfjoe } 29389099Sfjoe 29489099Sfjoe ah = mtod(m, struct arc_header *); 29589099Sfjoe ah->arc_flag = ac->rsflag; 29689099Sfjoe ah->arc_seqid = ac->ac_seqid; 29789099Sfjoe 29889099Sfjoe ac->sflag += 2; 29989099Sfjoe ac->rsflag = ac->sflag; 30089099Sfjoe } else if ((m->m_pkthdr.len >= 30189099Sfjoe ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) && 30289099Sfjoe (m->m_pkthdr.len <= 30389099Sfjoe ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) { 30489099Sfjoe ac->curr_frag = 0; 30589099Sfjoe 306111119Simp M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT); 30789099Sfjoe if (m == 0) 30889099Sfjoe return 0; 30989099Sfjoe 31089099Sfjoe ah = mtod(m, struct arc_header *); 31189099Sfjoe ah->arc_flag = 0xFF; 31289099Sfjoe ah->arc_seqid = 0xFFFF; 31389099Sfjoe ah->arc_type2 = ac->arc_type; 31489099Sfjoe ah->arc_flag2 = ac->sflag; 31589099Sfjoe ah->arc_seqid2 = ac->ac_seqid; 31689099Sfjoe } else { 31789099Sfjoe ac->curr_frag = 0; 31889099Sfjoe 319111119Simp M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 32089099Sfjoe if (m == 0) 32189099Sfjoe return 0; 32289099Sfjoe 32389099Sfjoe ah = mtod(m, struct arc_header *); 32489099Sfjoe ah->arc_flag = ac->sflag; 32589099Sfjoe ah->arc_seqid = ac->ac_seqid; 32689099Sfjoe } 32789099Sfjoe 32889099Sfjoe ah->arc_dhost = ac->arc_dhost; 32989099Sfjoe ah->arc_shost = ac->arc_shost; 33089099Sfjoe ah->arc_type = ac->arc_type; 33189099Sfjoe 33289099Sfjoe return m; 33389099Sfjoe} 33489099Sfjoe 33589099Sfjoe/* 33689099Sfjoe * Defragmenter. Returns mbuf if last packet found, else 33789099Sfjoe * NULL. frees imcoming mbuf as necessary. 33889099Sfjoe */ 33989099Sfjoe 340105228Sphkstatic __inline struct mbuf * 34189099Sfjoearc_defrag(ifp, m) 34289099Sfjoe struct ifnet *ifp; 34389099Sfjoe struct mbuf *m; 34489099Sfjoe{ 34589099Sfjoe struct arc_header *ah, *ah1; 34689099Sfjoe struct arccom *ac; 34789099Sfjoe struct ac_frag *af; 34889099Sfjoe struct mbuf *m1; 34989099Sfjoe char *s; 35089099Sfjoe int newflen; 35189099Sfjoe u_char src,dst,typ; 35289099Sfjoe 35389099Sfjoe ac = (struct arccom *)ifp; 35489099Sfjoe 35589099Sfjoe if (m->m_len < ARC_HDRNEWLEN) { 35689099Sfjoe m = m_pullup(m, ARC_HDRNEWLEN); 35789099Sfjoe if (m == NULL) { 35889099Sfjoe ++ifp->if_ierrors; 35989099Sfjoe return NULL; 36089099Sfjoe } 36189099Sfjoe } 36289099Sfjoe 36389099Sfjoe ah = mtod(m, struct arc_header *); 36489099Sfjoe typ = ah->arc_type; 36589099Sfjoe 36689099Sfjoe if (!arc_isphds(typ)) 36789099Sfjoe return m; 36889099Sfjoe 36989099Sfjoe src = ah->arc_shost; 37089099Sfjoe dst = ah->arc_dhost; 37189099Sfjoe 37289099Sfjoe if (ah->arc_flag == 0xff) { 37389099Sfjoe m_adj(m, 4); 37489099Sfjoe 37589099Sfjoe if (m->m_len < ARC_HDRNEWLEN) { 37689099Sfjoe m = m_pullup(m, ARC_HDRNEWLEN); 37789099Sfjoe if (m == NULL) { 37889099Sfjoe ++ifp->if_ierrors; 37989099Sfjoe return NULL; 38089099Sfjoe } 38189099Sfjoe } 38289099Sfjoe 38389099Sfjoe ah = mtod(m, struct arc_header *); 38489099Sfjoe } 38589099Sfjoe 38689099Sfjoe af = &ac->ac_fragtab[src]; 38789099Sfjoe m1 = af->af_packet; 38889099Sfjoe s = "debug code error"; 38989099Sfjoe 39089099Sfjoe if (ah->arc_flag & 1) { 39189099Sfjoe /* 39289099Sfjoe * first fragment. We always initialize, which is 39389099Sfjoe * about the right thing to do, as we only want to 39489099Sfjoe * accept one fragmented packet per src at a time. 39589099Sfjoe */ 39689099Sfjoe if (m1 != NULL) 39789099Sfjoe m_freem(m1); 39889099Sfjoe 39989099Sfjoe af->af_packet = m; 40089099Sfjoe m1 = m; 40189099Sfjoe af->af_maxflag = ah->arc_flag; 40289099Sfjoe af->af_lastseen = 0; 40389099Sfjoe af->af_seqid = ah->arc_seqid; 40489099Sfjoe 40589099Sfjoe return NULL; 40689099Sfjoe /* notreached */ 40789099Sfjoe } else { 40889099Sfjoe /* check for unfragmented packet */ 40989099Sfjoe if (ah->arc_flag == 0) 41089099Sfjoe return m; 41189099Sfjoe 41289099Sfjoe /* do we have a first packet from that src? */ 41389099Sfjoe if (m1 == NULL) { 41489099Sfjoe s = "no first frag"; 41589099Sfjoe goto outofseq; 41689099Sfjoe } 41789099Sfjoe 41889099Sfjoe ah1 = mtod(m1, struct arc_header *); 41989099Sfjoe 42089099Sfjoe if (ah->arc_seqid != ah1->arc_seqid) { 42189099Sfjoe s = "seqid differs"; 42289099Sfjoe goto outofseq; 42389099Sfjoe } 42489099Sfjoe 42589099Sfjoe if (typ != ah1->arc_type) { 42689099Sfjoe s = "type differs"; 42789099Sfjoe goto outofseq; 42889099Sfjoe } 42989099Sfjoe 43089099Sfjoe if (dst != ah1->arc_dhost) { 43189099Sfjoe s = "dest host differs"; 43289099Sfjoe goto outofseq; 43389099Sfjoe } 43489099Sfjoe 43589099Sfjoe /* typ, seqid and dst are ok here. */ 43689099Sfjoe 43789099Sfjoe if (ah->arc_flag == af->af_lastseen) { 43889099Sfjoe m_freem(m); 43989099Sfjoe return NULL; 44089099Sfjoe } 44189099Sfjoe 44289099Sfjoe if (ah->arc_flag == af->af_lastseen + 2) { 44389099Sfjoe /* ok, this is next fragment */ 44489099Sfjoe af->af_lastseen = ah->arc_flag; 44589099Sfjoe m_adj(m,ARC_HDRNEWLEN); 44689099Sfjoe 44789099Sfjoe /* 44889099Sfjoe * m_cat might free the first mbuf (with pkthdr) 44989099Sfjoe * in 2nd chain; therefore: 45089099Sfjoe */ 45189099Sfjoe 45289099Sfjoe newflen = m->m_pkthdr.len; 45389099Sfjoe 45489099Sfjoe m_cat(m1,m); 45589099Sfjoe 45689099Sfjoe m1->m_pkthdr.len += newflen; 45789099Sfjoe 45889099Sfjoe /* is it the last one? */ 45989099Sfjoe if (af->af_lastseen > af->af_maxflag) { 46089099Sfjoe af->af_packet = NULL; 46189099Sfjoe return(m1); 46289099Sfjoe } else 46389099Sfjoe return NULL; 46489099Sfjoe } 46589099Sfjoe s = "other reason"; 46689099Sfjoe /* if all else fails, it is out of sequence, too */ 46789099Sfjoe } 46889099Sfjoeoutofseq: 46989099Sfjoe if (m1) { 47089099Sfjoe m_freem(m1); 47189099Sfjoe af->af_packet = NULL; 47289099Sfjoe } 47389099Sfjoe 47489099Sfjoe if (m) 47589099Sfjoe m_freem(m); 47689099Sfjoe 47789099Sfjoe log(LOG_INFO,"%s%d: got out of seq. packet: %s\n", 47889099Sfjoe ifp->if_name, ifp->if_unit, s); 47989099Sfjoe 48089099Sfjoe return NULL; 48189099Sfjoe} 48289099Sfjoe 48389099Sfjoe/* 48489099Sfjoe * return 1 if Packet Header Definition Standard, else 0. 48589099Sfjoe * For now: old IP, old ARP aren't obviously. Lacking correct information, 48689099Sfjoe * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. 48789099Sfjoe * (Apple and Novell corporations were involved, among others, in PHDS work). 48889099Sfjoe * Easiest is to assume that everybody else uses that, too. 48989099Sfjoe */ 49089099Sfjoeint 49189099Sfjoearc_isphds(type) 49289099Sfjoe u_int8_t type; 49389099Sfjoe{ 49489099Sfjoe return (type != ARCTYPE_IP_OLD && 49589099Sfjoe type != ARCTYPE_ARP_OLD && 49689099Sfjoe type != ARCTYPE_DIAGNOSE); 49789099Sfjoe} 49889099Sfjoe 49989099Sfjoe/* 50089099Sfjoe * Process a received Arcnet packet; 50189099Sfjoe * the packet is in the mbuf chain m with 50289099Sfjoe * the ARCnet header. 50389099Sfjoe */ 50489099Sfjoevoid 50589099Sfjoearc_input(ifp, m) 50689099Sfjoe struct ifnet *ifp; 50789099Sfjoe struct mbuf *m; 50889099Sfjoe{ 50989099Sfjoe struct arc_header *ah; 51089099Sfjoe struct ifqueue *inq; 51189099Sfjoe u_int8_t atype; 51289099Sfjoe 51389099Sfjoe if ((ifp->if_flags & IFF_UP) == 0) { 51489099Sfjoe m_freem(m); 51589099Sfjoe return; 51689099Sfjoe } 51789099Sfjoe 51889099Sfjoe /* possibly defragment: */ 51989099Sfjoe m = arc_defrag(ifp, m); 52089099Sfjoe if (m == NULL) 52189099Sfjoe return; 52289099Sfjoe 523106939Ssam BPF_MTAP(ifp, m); 52489099Sfjoe 52589099Sfjoe ah = mtod(m, struct arc_header *); 526109771Sfjoe /* does this belong to us? */ 527110106Sfjoe if ((ifp->if_flags & IFF_PROMISC) == 0 528109771Sfjoe && ah->arc_dhost != arcbroadcastaddr 529110106Sfjoe && ah->arc_dhost != ARC_LLADDR(ifp)) { 530109771Sfjoe m_freem(m); 531109771Sfjoe return; 532109771Sfjoe } 53389099Sfjoe 53489099Sfjoe ifp->if_ibytes += m->m_pkthdr.len; 53589099Sfjoe 536109771Sfjoe if (ah->arc_dhost == arcbroadcastaddr) { 53789099Sfjoe m->m_flags |= M_BCAST|M_MCAST; 53889099Sfjoe ifp->if_imcasts++; 53989099Sfjoe } 54089099Sfjoe 54189099Sfjoe atype = ah->arc_type; 54289099Sfjoe switch (atype) { 54389099Sfjoe#ifdef INET 54489099Sfjoe case ARCTYPE_IP: 54589099Sfjoe m_adj(m, ARC_HDRNEWLEN); 546109771Sfjoe if (ipflow_fastforward(m)) 547109771Sfjoe return; 54889099Sfjoe schednetisr(NETISR_IP); 54989099Sfjoe inq = &ipintrq; 55089099Sfjoe break; 55189099Sfjoe 55289099Sfjoe case ARCTYPE_IP_OLD: 55389099Sfjoe m_adj(m, ARC_HDRLEN); 554109771Sfjoe if (ipflow_fastforward(m)) 555109771Sfjoe return; 55689099Sfjoe schednetisr(NETISR_IP); 55789099Sfjoe inq = &ipintrq; 55889099Sfjoe break; 55989099Sfjoe 56089099Sfjoe case ARCTYPE_ARP: 56189099Sfjoe if (ifp->if_flags & IFF_NOARP) { 56289099Sfjoe /* Discard packet if ARP is disabled on interface */ 56389099Sfjoe m_freem(m); 56489099Sfjoe return; 56589099Sfjoe } 56689099Sfjoe m_adj(m, ARC_HDRNEWLEN); 56789099Sfjoe schednetisr(NETISR_ARP); 56889099Sfjoe inq = &arpintrq; 56989099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP 57089099Sfjoe mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 57189099Sfjoe#endif 57289099Sfjoe break; 57389099Sfjoe 57489099Sfjoe case ARCTYPE_ARP_OLD: 57589099Sfjoe if (ifp->if_flags & IFF_NOARP) { 57689099Sfjoe /* Discard packet if ARP is disabled on interface */ 57789099Sfjoe m_freem(m); 57889099Sfjoe return; 57989099Sfjoe } 58089099Sfjoe m_adj(m, ARC_HDRLEN); 58189099Sfjoe schednetisr(NETISR_ARP); 58289099Sfjoe inq = &arpintrq; 58389099Sfjoe#ifdef ARCNET_ALLOW_BROKEN_ARP 58489099Sfjoe mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 58589099Sfjoe#endif 58689099Sfjoe break; 58789099Sfjoe#endif 58889099Sfjoe#ifdef INET6 58989099Sfjoe case ARCTYPE_INET6: 59089099Sfjoe m_adj(m, ARC_HDRNEWLEN); 59189099Sfjoe schednetisr(NETISR_IPV6); 59289099Sfjoe inq = &ip6intrq; 59389099Sfjoe break; 59489099Sfjoe#endif 595109771Sfjoe#ifdef IPX 596109771Sfjoe case ARCTYPE_IPX: 597109771Sfjoe m_adj(m, ARC_HDRNEWLEN); 598109771Sfjoe schednetisr(NETISR_IPX); 599109771Sfjoe inq = &ipxintrq; 600109771Sfjoe break; 601109771Sfjoe#endif 60289099Sfjoe default: 60389099Sfjoe m_freem(m); 60489099Sfjoe return; 60589099Sfjoe } 60689099Sfjoe 60789099Sfjoe IF_HANDOFF(inq, m, NULL); 60889099Sfjoe} 60989099Sfjoe 61089099Sfjoe/* 61189099Sfjoe * Register (new) link level address. 61289099Sfjoe */ 61389099Sfjoevoid 61489099Sfjoearc_storelladdr(ifp, lla) 61589099Sfjoe struct ifnet *ifp; 61689099Sfjoe u_int8_t lla; 61789099Sfjoe{ 618110106Sfjoe ARC_LLADDR(ifp) = lla; 61989099Sfjoe} 62089099Sfjoe 62189099Sfjoe/* 62289099Sfjoe * Perform common duties while attaching to interface list 62389099Sfjoe */ 62489099Sfjoevoid 62589099Sfjoearc_ifattach(ifp, lla) 62689099Sfjoe struct ifnet *ifp; 62789099Sfjoe u_int8_t lla; 62889099Sfjoe{ 62989099Sfjoe struct ifaddr *ifa; 63089099Sfjoe struct sockaddr_dl *sdl; 63189099Sfjoe struct arccom *ac; 63289099Sfjoe 63389099Sfjoe if_attach(ifp); 63489099Sfjoe ifp->if_type = IFT_ARCNET; 63589099Sfjoe ifp->if_addrlen = 1; 63689099Sfjoe ifp->if_hdrlen = ARC_HDRLEN; 63789099Sfjoe ifp->if_mtu = 1500; 638109771Sfjoe ifp->if_resolvemulti = arc_resolvemulti; 63989099Sfjoe if (ifp->if_baudrate == 0) 64089099Sfjoe ifp->if_baudrate = 2500000; 64189099Sfjoe#if __FreeBSD_version < 500000 64289099Sfjoe ifa = ifnet_addrs[ifp->if_index - 1]; 64389099Sfjoe#else 64489099Sfjoe ifa = ifaddr_byindex(ifp->if_index); 64589099Sfjoe#endif 64689099Sfjoe KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__)); 64789099Sfjoe sdl = (struct sockaddr_dl *)ifa->ifa_addr; 64889099Sfjoe sdl->sdl_type = IFT_ARCNET; 64989099Sfjoe sdl->sdl_alen = ifp->if_addrlen; 65089099Sfjoe 65189099Sfjoe if (ifp->if_flags & IFF_BROADCAST) 65289099Sfjoe ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 65389099Sfjoe 65489099Sfjoe ac = (struct arccom *)ifp; 65589099Sfjoe ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 65689099Sfjoe if (lla == 0) { 65789099Sfjoe /* XXX this message isn't entirely clear, to me -- cgd */ 65889099Sfjoe log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n", 65989099Sfjoe ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit); 66089099Sfjoe } 66189099Sfjoe arc_storelladdr(ifp, lla); 66289099Sfjoe 66389099Sfjoe ifp->if_broadcastaddr = &arcbroadcastaddr; 66489099Sfjoe 66589099Sfjoe bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 66689099Sfjoe} 66789099Sfjoe 66889099Sfjoevoid 66989099Sfjoearc_ifdetach(ifp) 67089099Sfjoe struct ifnet *ifp; 67189099Sfjoe{ 67289099Sfjoe bpfdetach(ifp); 67389099Sfjoe if_detach(ifp); 67489099Sfjoe} 67589099Sfjoe 67689099Sfjoeint 67789099Sfjoearc_ioctl(ifp, command, data) 67889099Sfjoe struct ifnet *ifp; 67989099Sfjoe int command; 68089099Sfjoe caddr_t data; 68189099Sfjoe{ 68289099Sfjoe struct ifaddr *ifa = (struct ifaddr *) data; 68389099Sfjoe struct ifreq *ifr = (struct ifreq *) data; 68489099Sfjoe int error = 0; 68589099Sfjoe 68689099Sfjoe switch (command) { 68789099Sfjoe case SIOCSIFADDR: 68889099Sfjoe ifp->if_flags |= IFF_UP; 68989099Sfjoe switch (ifa->ifa_addr->sa_family) { 69089099Sfjoe#ifdef INET 69189099Sfjoe case AF_INET: 69289099Sfjoe ifp->if_init(ifp->if_softc); /* before arpwhohas */ 69389099Sfjoe arp_ifinit(ifp, ifa); 69489099Sfjoe break; 69589099Sfjoe#endif 696109771Sfjoe#ifdef IPX 697109771Sfjoe /* 698109771Sfjoe * XXX This code is probably wrong 699109771Sfjoe */ 700109771Sfjoe case AF_IPX: 701109771Sfjoe { 702109771Sfjoe struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 703109771Sfjoe 704109771Sfjoe if (ipx_nullhost(*ina)) 705110106Sfjoe ina->x_host.c_host[5] = ARC_LLADDR(ifp); 706109771Sfjoe else 707109771Sfjoe arc_storelladdr(ifp, ina->x_host.c_host[5]); 708109771Sfjoe 709109771Sfjoe /* 710109771Sfjoe * Set new address 711109771Sfjoe */ 712109771Sfjoe ifp->if_init(ifp->if_softc); 713109771Sfjoe break; 714109771Sfjoe } 715109771Sfjoe#endif 71689099Sfjoe default: 71789099Sfjoe ifp->if_init(ifp->if_softc); 71889099Sfjoe break; 71989099Sfjoe } 72089099Sfjoe break; 72189099Sfjoe 722109771Sfjoe case SIOCGIFADDR: 723109771Sfjoe { 724109771Sfjoe struct sockaddr *sa; 725109771Sfjoe 726109771Sfjoe sa = (struct sockaddr *) &ifr->ifr_data; 727110106Sfjoe *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 728109771Sfjoe } 729109771Sfjoe break; 730109771Sfjoe 73189099Sfjoe case SIOCADDMULTI: 73289099Sfjoe case SIOCDELMULTI: 73389099Sfjoe if (ifr == NULL) 73489099Sfjoe error = EAFNOSUPPORT; 73589099Sfjoe else { 73689099Sfjoe switch (ifr->ifr_addr.sa_family) { 73789099Sfjoe case AF_INET: 73889099Sfjoe case AF_INET6: 73989099Sfjoe error = 0; 74089099Sfjoe break; 74189099Sfjoe default: 74289099Sfjoe error = EAFNOSUPPORT; 74389099Sfjoe break; 74489099Sfjoe } 74589099Sfjoe } 74689099Sfjoe break; 74789099Sfjoe 74889099Sfjoe case SIOCSIFMTU: 74989099Sfjoe /* 75089099Sfjoe * Set the interface MTU. 75189099Sfjoe * mtu can't be larger than ARCMTU for RFC1051 75289099Sfjoe * and can't be larger than ARC_PHDS_MTU 75389099Sfjoe */ 75489099Sfjoe if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 75589099Sfjoe ifr->ifr_mtu > ARC_PHDS_MAXMTU) 75689099Sfjoe error = EINVAL; 75789099Sfjoe else 75889099Sfjoe ifp->if_mtu = ifr->ifr_mtu; 75989099Sfjoe break; 760109771Sfjoe } 76189099Sfjoe 762109771Sfjoe return (error); 763109771Sfjoe} 76489099Sfjoe 765109771Sfjoe/* based on ether_resolvemulti() */ 766109771Sfjoeint 767109771Sfjoearc_resolvemulti(ifp, llsa, sa) 768109771Sfjoe struct ifnet *ifp; 769109771Sfjoe struct sockaddr **llsa; 770109771Sfjoe struct sockaddr *sa; 771109771Sfjoe{ 772109771Sfjoe struct sockaddr_dl *sdl; 773109771Sfjoe struct sockaddr_in *sin; 774109771Sfjoe#ifdef INET6 775109771Sfjoe struct sockaddr_in6 *sin6; 776109771Sfjoe#endif 777109771Sfjoe 778109771Sfjoe switch(sa->sa_family) { 779109771Sfjoe case AF_LINK: 780109771Sfjoe /* 781109771Sfjoe * No mapping needed. Just check that it's a valid MC address. 782109771Sfjoe */ 783109771Sfjoe sdl = (struct sockaddr_dl *)sa; 784109771Sfjoe if (*LLADDR(sdl) != arcbroadcastaddr) 785109771Sfjoe return EADDRNOTAVAIL; 786109771Sfjoe *llsa = 0; 787109771Sfjoe return 0; 788109771Sfjoe#ifdef INET 789109771Sfjoe case AF_INET: 790109771Sfjoe sin = (struct sockaddr_in *)sa; 791109771Sfjoe if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 792109771Sfjoe return EADDRNOTAVAIL; 793109771Sfjoe MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 794109771Sfjoe M_ZERO); 795109771Sfjoe sdl->sdl_len = sizeof *sdl; 796109771Sfjoe sdl->sdl_family = AF_LINK; 797109771Sfjoe sdl->sdl_index = ifp->if_index; 798109771Sfjoe sdl->sdl_type = IFT_ARCNET; 799109771Sfjoe sdl->sdl_alen = ARC_ADDR_LEN; 800109771Sfjoe *LLADDR(sdl) = 0; 801109771Sfjoe *llsa = (struct sockaddr *)sdl; 802109771Sfjoe return 0; 803109771Sfjoe#endif 804109771Sfjoe#ifdef INET6 805109771Sfjoe case AF_INET6: 806109771Sfjoe sin6 = (struct sockaddr_in6 *)sa; 807109771Sfjoe if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 808109771Sfjoe /* 809109771Sfjoe * An IP6 address of 0 means listen to all 810109771Sfjoe * of the Ethernet multicast address used for IP6. 811109771Sfjoe * (This is used for multicast routers.) 812109771Sfjoe */ 813109771Sfjoe ifp->if_flags |= IFF_ALLMULTI; 814109771Sfjoe *llsa = 0; 815109771Sfjoe return 0; 81689099Sfjoe } 817109771Sfjoe if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 818109771Sfjoe return EADDRNOTAVAIL; 819109771Sfjoe MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 820109771Sfjoe M_ZERO); 821109771Sfjoe sdl->sdl_len = sizeof *sdl; 822109771Sfjoe sdl->sdl_family = AF_LINK; 823109771Sfjoe sdl->sdl_index = ifp->if_index; 824109771Sfjoe sdl->sdl_type = IFT_ARCNET; 825109771Sfjoe sdl->sdl_alen = ARC_ADDR_LEN; 826109771Sfjoe *LLADDR(sdl) = 0; 827109771Sfjoe *llsa = (struct sockaddr *)sdl; 828109771Sfjoe return 0; 82989099Sfjoe#endif 830109771Sfjoe 831109771Sfjoe default: 832109771Sfjoe /* 833109771Sfjoe * Well, the text isn't quite right, but it's the name 834109771Sfjoe * that counts... 835109771Sfjoe */ 836109771Sfjoe return EAFNOSUPPORT; 83789099Sfjoe } 83889099Sfjoe} 839