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