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