1139823Simp/*- 221830Sjoerg * Copyright (c) 1995, 1996 321830Sjoerg * Matt Thomas <matt@3am-software.com>. All rights reserved. 47055Sdg * Copyright (c) 1982, 1989, 1993 57055Sdg * The Regents of the University of California. All rights reserved. 67055Sdg * 77055Sdg * Redistribution and use in source and binary forms, with or without 87055Sdg * modification, are permitted provided that the following conditions 97055Sdg * are met: 107055Sdg * 1. Redistributions of source code must retain the above copyright 117055Sdg * notice, this list of conditions and the following disclaimer. 127055Sdg * 2. Redistributions in binary form must reproduce the above copyright 137055Sdg * notice, this list of conditions and the following disclaimer in the 147055Sdg * documentation and/or other materials provided with the distribution. 157055Sdg * 3. All advertising materials mentioning features or use of this software 167055Sdg * must display the following acknowledgement: 177055Sdg * This product includes software developed by the University of 187055Sdg * California, Berkeley and its contributors. 197055Sdg * 4. Neither the name of the University nor the names of its contributors 207055Sdg * may be used to endorse or promote products derived from this software 217055Sdg * without specific prior written permission. 227055Sdg * 237055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 247055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 257055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 267055Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 277055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 287055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 297055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 307055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 317055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 327055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 337055Sdg * SUCH DAMAGE. 347055Sdg * 357061Sdg * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 3650477Speter * $FreeBSD: stable/10/sys/net/if_fddisubr.c 332160 2018-04-07 00:04:28Z brooks $ 377055Sdg */ 387055Sdg 3932356Seivind#include "opt_atalk.h" 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4231742Seivind#include "opt_ipx.h" 4331742Seivind 447055Sdg#include <sys/param.h> 457055Sdg#include <sys/systm.h> 4693375Smdodd#include <sys/kernel.h> 4793375Smdodd#include <sys/malloc.h> 487055Sdg#include <sys/mbuf.h> 4993375Smdodd#include <sys/module.h> 507055Sdg#include <sys/socket.h> 5193375Smdodd#include <sys/sockio.h> 527055Sdg 537055Sdg#include <net/if.h> 54112271Smdodd#include <net/if_dl.h> 557055Sdg#include <net/if_llc.h> 567055Sdg#include <net/if_types.h> 57186119Sqingli#include <net/if_llatbl.h> 58112271Smdodd 59184709Sbz#include <net/ethernet.h> 6093375Smdodd#include <net/netisr.h> 6193375Smdodd#include <net/route.h> 6293375Smdodd#include <net/bpf.h> 6393373Smdodd#include <net/fddi.h> 647055Sdg 6554263Sshin#if defined(INET) || defined(INET6) 667055Sdg#include <netinet/in.h> 677055Sdg#include <netinet/in_var.h> 6832350Seivind#include <netinet/if_ether.h> 697055Sdg#endif 7054263Sshin#ifdef INET6 7154263Sshin#include <netinet6/nd6.h> 7254263Sshin#endif 737055Sdg 7411819Sjulian#ifdef IPX 7521830Sjoerg#include <netipx/ipx.h> 7611819Sjulian#include <netipx/ipx_if.h> 7711819Sjulian#endif 7811819Sjulian 797055Sdg#ifdef DECNET 807055Sdg#include <netdnet/dn.h> 817055Sdg#endif 827055Sdg 8321830Sjoerg#ifdef NETATALK 8421830Sjoerg#include <netatalk/at.h> 8521830Sjoerg#include <netatalk/at_var.h> 8621830Sjoerg#include <netatalk/at_extern.h> 8721830Sjoerg 8821830Sjoergextern u_char at_org_code[ 3 ]; 8921830Sjoergextern u_char aarp_org_code[ 3 ]; 9021830Sjoerg#endif /* NETATALK */ 9121830Sjoerg 92163606Srwatson#include <security/mac/mac_framework.h> 93163606Srwatson 94126788Srwatsonstatic const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 9593382Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 9693382Smdodd 9793383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 9893084Sbde struct sockaddr *); 99249925Sglebiusstatic int fddi_output(struct ifnet *, struct mbuf *, const struct sockaddr *, 100191148Skmacy struct route *); 101106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m); 10268180Sume 103112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 10493369Smdodd 1057055Sdg/* 1067055Sdg * FDDI output routine. 1077055Sdg * Encapsulate a packet of type family for the local net. 1087055Sdg * Use trailer local net encapsulation if enough data in first 1097055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1107055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1117055Sdg */ 11293383Smdoddstatic int 113249925Sglebiusfddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 114249925Sglebius struct route *ro) 1157055Sdg{ 11621830Sjoerg u_int16_t type; 11769152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 11893373Smdodd u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 11993367Smdodd struct fddi_header *fh; 120193891Sbz#if defined(INET) || defined(INET6) 121186119Sqingli struct llentry *lle; 122193891Sbz#endif 1237055Sdg 124105577Srwatson#ifdef MAC 125172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 126105577Srwatson if (error) 127105577Srwatson senderr(error); 128105577Srwatson#endif 129105577Srwatson 130112308Smdodd if (ifp->if_flags & IFF_MONITOR) 131112308Smdodd senderr(ENETDOWN); 132148887Srwatson if (!((ifp->if_flags & IFF_UP) && 133148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 1347055Sdg senderr(ENETDOWN); 13534961Sphk getmicrotime(&ifp->if_lastchange); 136111767Smdodd 1377055Sdg switch (dst->sa_family) { 1387055Sdg#ifdef INET 13921830Sjoerg case AF_INET: { 140193891Sbz struct rtentry *rt0 = NULL; 141193891Sbz 142193891Sbz if (ro != NULL) 143193891Sbz rt0 = ro->ro_rt; 144186119Sqingli error = arpresolve(ifp, rt0, m, dst, edst, &lle); 145128636Sluigi if (error) 146128636Sluigi return (error == EWOULDBLOCK ? 0 : error); 14721830Sjoerg type = htons(ETHERTYPE_IP); 1487055Sdg break; 14921830Sjoerg } 150126951Smdodd case AF_ARP: 151126951Smdodd { 152126951Smdodd struct arphdr *ah; 153126951Smdodd ah = mtod(m, struct arphdr *); 154126951Smdodd ah->ar_hrd = htons(ARPHRD_ETHER); 155126951Smdodd 156126951Smdodd loop_copy = -1; /* if this is for us, don't do it */ 157126951Smdodd 158126951Smdodd switch (ntohs(ah->ar_op)) { 159126951Smdodd case ARPOP_REVREQUEST: 160126951Smdodd case ARPOP_REVREPLY: 161126951Smdodd type = htons(ETHERTYPE_REVARP); 162126951Smdodd break; 163126951Smdodd case ARPOP_REQUEST: 164126951Smdodd case ARPOP_REPLY: 165126951Smdodd default: 166126951Smdodd type = htons(ETHERTYPE_ARP); 167126951Smdodd break; 168126951Smdodd } 169126951Smdodd 170126951Smdodd if (m->m_flags & M_BCAST) 171126951Smdodd bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); 172126951Smdodd else 173126951Smdodd bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); 174126951Smdodd 175126951Smdodd } 176126951Smdodd break; 177112266Smdodd#endif /* INET */ 17854263Sshin#ifdef INET6 17954263Sshin case AF_INET6: 180186217Sqingli error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 181128636Sluigi if (error) 182128636Sluigi return (error); /* Something bad happened */ 18354263Sshin type = htons(ETHERTYPE_IPV6); 18454263Sshin break; 185112266Smdodd#endif /* INET6 */ 18611819Sjulian#ifdef IPX 18711819Sjulian case AF_IPX: 18821830Sjoerg type = htons(ETHERTYPE_IPX); 189249925Sglebius bcopy(&((const struct sockaddr_ipx *)dst)->sipx_addr.x_host, 190249925Sglebius edst, FDDI_ADDR_LEN); 19111819Sjulian break; 192112266Smdodd#endif /* IPX */ 19321830Sjoerg#ifdef NETATALK 19421830Sjoerg case AF_APPLETALK: { 19521830Sjoerg struct at_ifaddr *aa; 196249925Sglebius if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) 19721830Sjoerg return (0); 19821830Sjoerg /* 19921830Sjoerg * ifaddr is the first thing in at_ifaddr 20021830Sjoerg */ 201249925Sglebius if ((aa = at_ifawithnet((const struct sockaddr_at *)dst)) == 0) 20221830Sjoerg goto bad; 20321830Sjoerg 20421830Sjoerg /* 20521830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 20621830Sjoerg * Since we must preserve the value of m, which is passed to us by 20721830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 20821830Sjoerg */ 20921830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 21021830Sjoerg struct llc llc; 21121830Sjoerg 212243882Sglebius M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAITOK); 21321830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 21421830Sjoerg llc.llc_control = LLC_UI; 21593371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 21693371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 21793373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 21821830Sjoerg type = 0; 21921830Sjoerg } else { 22021830Sjoerg type = htons(ETHERTYPE_AT); 22121830Sjoerg } 222194819Srwatson ifa_free(&aa->aa_ifa); 22321830Sjoerg break; 22421830Sjoerg } 22521830Sjoerg#endif /* NETATALK */ 2267055Sdg 22752248Smsmith case pseudo_AF_HDRCMPLT: 22852248Smsmith { 229249925Sglebius const struct ether_header *eh; 230249925Sglebius 23152248Smsmith hdrcmplt = 1; 232249925Sglebius eh = (const struct ether_header *)dst->sa_data; 233249925Sglebius bcopy(eh->ether_shost, esrc, FDDI_ADDR_LEN); 23452248Smsmith /* FALLTHROUGH */ 23552248Smsmith } 23652248Smsmith 2377055Sdg case AF_UNSPEC: 2387055Sdg { 239249925Sglebius const struct ether_header *eh; 240249925Sglebius 24136992Sjulian loop_copy = -1; 242249925Sglebius eh = (const struct ether_header *)dst->sa_data; 243249925Sglebius bcopy(eh->ether_dhost, edst, FDDI_ADDR_LEN); 2447055Sdg if (*edst & 1) 2457055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2467055Sdg type = eh->ether_type; 2477055Sdg break; 2487055Sdg } 2497055Sdg 2507055Sdg case AF_IMPLINK: 2517055Sdg { 2527055Sdg fh = mtod(m, struct fddi_header *); 2537055Sdg error = EPROTONOSUPPORT; 2547055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2557055Sdg case FDDIFC_LLC_ASYNC: { 2567055Sdg /* legal priorities are 0 through 7 */ 2577055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2587055Sdg goto bad; 2597055Sdg break; 2607055Sdg } 2617055Sdg case FDDIFC_LLC_SYNC: { 2627055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2637055Sdg if (fh->fddi_fc & FDDIFC_Z) 2647055Sdg goto bad; 2657055Sdg break; 2667055Sdg } 2677055Sdg case FDDIFC_SMT: { 2687055Sdg /* FDDIFC_Z bits must be non zero */ 2697055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2707055Sdg goto bad; 2717055Sdg break; 2727055Sdg } 2737055Sdg default: { 2747055Sdg /* anything else is too dangerous */ 2757055Sdg goto bad; 2767055Sdg } 2777055Sdg } 2787055Sdg error = 0; 2797055Sdg if (fh->fddi_dhost[0] & 1) 2807055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2817055Sdg goto queue_it; 2827055Sdg } 2837055Sdg default: 284105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 2857055Sdg senderr(EAFNOSUPPORT); 2867055Sdg } 2877055Sdg 28893380Smdodd /* 28993380Smdodd * Add LLC header. 29093380Smdodd */ 2917055Sdg if (type != 0) { 29293367Smdodd struct llc *l; 293243882Sglebius M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); 2947055Sdg if (m == 0) 2957055Sdg senderr(ENOBUFS); 2967055Sdg l = mtod(m, struct llc *); 2977055Sdg l->llc_control = LLC_UI; 2987055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 299112266Smdodd l->llc_snap.org_code[0] = 300112266Smdodd l->llc_snap.org_code[1] = 301112266Smdodd l->llc_snap.org_code[2] = 0; 302112266Smdodd l->llc_snap.ether_type = htons(type); 3037055Sdg } 30436908Sjulian 3057055Sdg /* 3067055Sdg * Add local net header. If no space in first mbuf, 3077055Sdg * allocate another. 3087055Sdg */ 309243882Sglebius M_PREPEND(m, FDDI_HDR_LEN, M_NOWAIT); 3107055Sdg if (m == 0) 3117055Sdg senderr(ENOBUFS); 3127055Sdg fh = mtod(m, struct fddi_header *); 3137055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 31493375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 3157055Sdg queue_it: 31652248Smsmith if (hdrcmplt) 31793375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 31852248Smsmith else 319152315Sru bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, 32093373Smdodd FDDI_ADDR_LEN); 32193377Smdodd 32236908Sjulian /* 32336908Sjulian * If a simplex interface, and the packet is being sent to our 32436908Sjulian * Ethernet address or a broadcast address, loopback a copy. 32536908Sjulian * XXX To make a simplex device behave exactly like a duplex 32636908Sjulian * device, we should copy in the case of sending to our own 32736908Sjulian * ethernet address (thus letting the original actually appear 32836908Sjulian * on the wire). However, we don't do that here for security 32936908Sjulian * reasons and compatibility with the original behavior. 33036908Sjulian */ 33193377Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 332112279Smdodd if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 333112279Smdodd struct mbuf *n; 334112279Smdodd n = m_copy(m, 0, (int)M_COPYALL); 335112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 336112279Smdodd FDDI_HDR_LEN); 337112279Smdodd } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, 338112279Smdodd FDDI_ADDR_LEN) == 0) { 339112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 340112279Smdodd FDDI_HDR_LEN); 34193369Smdodd return (0); /* XXX */ 34236908Sjulian } 34336908Sjulian } 34436908Sjulian 345185164Skmacy error = (ifp->if_transmit)(ifp, m); 346130549Smlaier if (error) 347130549Smlaier ifp->if_oerrors++; 348130549Smlaier 3497055Sdg return (error); 3507055Sdg 3517055Sdgbad: 35293379Smdodd ifp->if_oerrors++; 3537055Sdg if (m) 3547055Sdg m_freem(m); 3557055Sdg return (error); 3567055Sdg} 3577055Sdg 3587055Sdg/* 359112308Smdodd * Process a received FDDI packet. 3607055Sdg */ 361106939Ssamstatic void 362106939Ssamfddi_input(ifp, m) 3637055Sdg struct ifnet *ifp; 3647055Sdg struct mbuf *m; 3657055Sdg{ 366111888Sjlemon int isr; 36793367Smdodd struct llc *l; 368106939Ssam struct fddi_header *fh; 3697055Sdg 370112308Smdodd /* 371112308Smdodd * Do consistency checks to verify assumptions 372112308Smdodd * made by code past this point. 373112308Smdodd */ 374112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 375112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 376112308Smdodd ifp->if_ierrors++; 377112308Smdodd m_freem(m); 378112308Smdodd return; 379112308Smdodd } 380112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 381112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 382112308Smdodd ifp->if_ierrors++; 383112308Smdodd m_freem(m); 384112308Smdodd return; 385112308Smdodd } 386112308Smdodd 387112308Smdodd m = m_pullup(m, FDDI_HDR_LEN); 388112308Smdodd if (m == NULL) { 389112308Smdodd ifp->if_ierrors++; 390112308Smdodd goto dropanyway; 391112308Smdodd } 392106939Ssam fh = mtod(m, struct fddi_header *); 393106939Ssam 39493379Smdodd /* 39593379Smdodd * Discard packet if interface is not up. 39693379Smdodd */ 397148887Srwatson if (!((ifp->if_flags & IFF_UP) && 398148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 39993379Smdodd goto dropanyway; 40093379Smdodd 401112308Smdodd /* 402112308Smdodd * Give bpf a chance at the packet. 403112308Smdodd */ 404112308Smdodd BPF_MTAP(ifp, m); 405112308Smdodd 406112308Smdodd /* 407112308Smdodd * Interface marked for monitoring; discard packet. 408112308Smdodd */ 409112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 410112308Smdodd m_freem(m); 411112308Smdodd return; 412112308Smdodd } 413112308Smdodd 414105577Srwatson#ifdef MAC 415172930Srwatson mac_ifnet_create_mbuf(ifp, m); 416105577Srwatson#endif 417105577Srwatson 41893379Smdodd /* 419112287Smdodd * Update interface statistics. 420112287Smdodd */ 421112287Smdodd ifp->if_ibytes += m->m_pkthdr.len; 422112287Smdodd getmicrotime(&ifp->if_lastchange); 423112287Smdodd 424112287Smdodd /* 42593379Smdodd * Discard non local unicast packets when interface 42693379Smdodd * is in promiscuous mode. 42793379Smdodd */ 42893379Smdodd if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 429152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, 43093379Smdodd FDDI_ADDR_LEN) != 0)) 43193379Smdodd goto dropanyway; 43293379Smdodd 43393379Smdodd /* 43493379Smdodd * Set mbuf flags for bcast/mcast. 43593379Smdodd */ 43621830Sjoerg if (fh->fddi_dhost[0] & 1) { 437121436Simp if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, 438121436Simp FDDI_ADDR_LEN) == 0) 43921830Sjoerg m->m_flags |= M_BCAST; 44021830Sjoerg else 44121830Sjoerg m->m_flags |= M_MCAST; 4427055Sdg ifp->if_imcasts++; 44321830Sjoerg } 4447055Sdg 44521830Sjoerg#ifdef M_LINK0 44621830Sjoerg /* 44721830Sjoerg * If this has a LLC priority of 0, then mark it so upper 44821830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 44921830Sjoerg * bridge. 45021830Sjoerg */ 45121830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 45221830Sjoerg m->m_flags |= M_LINK0; 45321830Sjoerg#endif 45421830Sjoerg 455106939Ssam /* Strip off FDDI header. */ 456111790Smdodd m_adj(m, FDDI_HDR_LEN); 457106939Ssam 458111790Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 45993379Smdodd if (m == 0) { 46093379Smdodd ifp->if_ierrors++; 46193379Smdodd goto dropanyway; 46293379Smdodd } 4637055Sdg l = mtod(m, struct llc *); 46493377Smdodd 4657055Sdg switch (l->llc_dsap) { 4667055Sdg case LLC_SNAP_LSAP: 4677055Sdg { 46821830Sjoerg u_int16_t type; 469112266Smdodd if ((l->llc_control != LLC_UI) || 470112266Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 47193379Smdodd ifp->if_noproto++; 4727055Sdg goto dropanyway; 47393379Smdodd } 47421830Sjoerg#ifdef NETATALK 475128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], at_org_code, 476111888Sjlemon sizeof(at_org_code)) == 0 && 477111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 478111888Sjlemon isr = NETISR_ATALK2; 479111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 480111888Sjlemon break; 48121830Sjoerg } 48221830Sjoerg 483128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 484111888Sjlemon sizeof(aarp_org_code)) == 0 && 485111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 486111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 487111888Sjlemon isr = NETISR_AARP; 488111888Sjlemon break; 48921830Sjoerg } 49021830Sjoerg#endif /* NETATALK */ 49193377Smdodd if (l->llc_snap.org_code[0] != 0 || 49293377Smdodd l->llc_snap.org_code[1] != 0 || 49393379Smdodd l->llc_snap.org_code[2] != 0) { 49493379Smdodd ifp->if_noproto++; 4957055Sdg goto dropanyway; 49693379Smdodd } 49793377Smdodd 49821830Sjoerg type = ntohs(l->llc_snap.ether_type); 49993377Smdodd m_adj(m, LLC_SNAPFRAMELEN); 50093377Smdodd 50121830Sjoerg switch (type) { 5027055Sdg#ifdef INET 5037055Sdg case ETHERTYPE_IP: 504295896Sgnn if ((m = ip_fastforward(m)) == NULL) 505295896Sgnn return; 506111888Sjlemon isr = NETISR_IP; 5077055Sdg break; 5087055Sdg 5097055Sdg case ETHERTYPE_ARP: 51078295Sjlemon if (ifp->if_flags & IFF_NOARP) 51178295Sjlemon goto dropanyway; 512111888Sjlemon isr = NETISR_ARP; 5137055Sdg break; 5147055Sdg#endif 51554263Sshin#ifdef INET6 51654263Sshin case ETHERTYPE_IPV6: 517111888Sjlemon isr = NETISR_IPV6; 51854263Sshin break; 51954263Sshin#endif 52021830Sjoerg#ifdef IPX 52121830Sjoerg case ETHERTYPE_IPX: 522111888Sjlemon isr = NETISR_IPX; 52321830Sjoerg break; 52421830Sjoerg#endif 5257055Sdg#ifdef DECNET 52621830Sjoerg case ETHERTYPE_DECNET: 527111888Sjlemon isr = NETISR_DECNET; 5287055Sdg break; 5297055Sdg#endif 53021830Sjoerg#ifdef NETATALK 53121830Sjoerg case ETHERTYPE_AT: 532111888Sjlemon isr = NETISR_ATALK1; 53321830Sjoerg break; 53421830Sjoerg case ETHERTYPE_AARP: 535111888Sjlemon isr = NETISR_AARP; 536111888Sjlemon break; 53721830Sjoerg#endif /* NETATALK */ 5387055Sdg default: 53921830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5407055Sdg ifp->if_noproto++; 5417055Sdg goto dropanyway; 5427055Sdg } 5437055Sdg break; 5447055Sdg } 54521830Sjoerg 5467055Sdg default: 54721830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 5487055Sdg ifp->if_noproto++; 54993377Smdodd goto dropanyway; 5507055Sdg } 551223741Sbz M_SETFIB(m, ifp->if_fib); 552111888Sjlemon netisr_dispatch(isr, m); 55393377Smdodd return; 55493377Smdodd 55593377Smdodddropanyway: 55693377Smdodd ifp->if_iqdrops++; 55793377Smdodd if (m) 55893377Smdodd m_freem(m); 55993377Smdodd return; 5607055Sdg} 56193380Smdodd 5627055Sdg/* 5637055Sdg * Perform common duties while attaching to interface list 5647055Sdg */ 5657055Sdgvoid 566152296Srufddi_ifattach(ifp, lla, bpf) 56793367Smdodd struct ifnet *ifp; 568152296Sru const u_int8_t *lla; 56993383Smdodd int bpf; 5707055Sdg{ 57193367Smdodd struct ifaddr *ifa; 57293367Smdodd struct sockaddr_dl *sdl; 5737055Sdg 5747055Sdg ifp->if_type = IFT_FDDI; 57593373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 5767055Sdg ifp->if_hdrlen = 21; 57793379Smdodd 57893379Smdodd if_attach(ifp); /* Must be called before additional assignments */ 57993379Smdodd 5807055Sdg ifp->if_mtu = FDDIMTU; 58193379Smdodd ifp->if_output = fddi_output; 582106939Ssam ifp->if_input = fddi_input; 58368180Sume ifp->if_resolvemulti = fddi_resolvemulti; 58493379Smdodd ifp->if_broadcastaddr = fddibroadcastaddr; 58516063Sgpalmer ifp->if_baudrate = 100000000; 58621830Sjoerg#ifdef IFF_NOTRAILERS 58721830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 58821830Sjoerg#endif 589152315Sru ifa = ifp->if_addr; 590152315Sru KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 59193379Smdodd 59221831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 59321831Sjoerg sdl->sdl_type = IFT_FDDI; 59421831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 595152296Sru bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 59693379Smdodd 59793383Smdodd if (bpf) 59893383Smdodd bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 59993383Smdodd 60093379Smdodd return; 6017055Sdg} 60268180Sume 60393382Smdoddvoid 60493382Smdoddfddi_ifdetach(ifp, bpf) 60593382Smdodd struct ifnet *ifp; 60693382Smdodd int bpf; 60793382Smdodd{ 60893382Smdodd 60993382Smdodd if (bpf) 61093382Smdodd bpfdetach(ifp); 61193382Smdodd 61293382Smdodd if_detach(ifp); 61393382Smdodd 61493382Smdodd return; 61593382Smdodd} 61693382Smdodd 61793382Smdoddint 61893382Smdoddfddi_ioctl (ifp, command, data) 61993382Smdodd struct ifnet *ifp; 620194581Srdivacky u_long command; 62193382Smdodd caddr_t data; 62293382Smdodd{ 62393382Smdodd struct ifaddr *ifa; 62493382Smdodd struct ifreq *ifr; 62593382Smdodd int error; 62693382Smdodd 62793382Smdodd ifa = (struct ifaddr *) data; 62893382Smdodd ifr = (struct ifreq *) data; 62993382Smdodd error = 0; 63093382Smdodd 63193382Smdodd switch (command) { 63293382Smdodd case SIOCSIFADDR: 63393382Smdodd ifp->if_flags |= IFF_UP; 63493382Smdodd 63593382Smdodd switch (ifa->ifa_addr->sa_family) { 63693382Smdodd#ifdef INET 63793382Smdodd case AF_INET: /* before arpwhohas */ 63893382Smdodd ifp->if_init(ifp->if_softc); 63993382Smdodd arp_ifinit(ifp, ifa); 64093382Smdodd break; 64193382Smdodd#endif 64293382Smdodd#ifdef IPX 64393382Smdodd /* 64493382Smdodd * XXX - This code is probably wrong 64593382Smdodd */ 64693382Smdodd case AF_IPX: { 64793382Smdodd struct ipx_addr *ina; 64893382Smdodd 64993382Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 65093382Smdodd 65193382Smdodd if (ipx_nullhost(*ina)) { 65293382Smdodd ina->x_host = *(union ipx_host *) 653152315Sru IF_LLADDR(ifp); 65493382Smdodd } else { 65593382Smdodd bcopy((caddr_t) ina->x_host.c_host, 656152315Sru (caddr_t) IF_LLADDR(ifp), 657147256Sbrooks ETHER_ADDR_LEN); 65893382Smdodd } 65993382Smdodd 66093382Smdodd /* 66193382Smdodd * Set new address 66293382Smdodd */ 66393382Smdodd ifp->if_init(ifp->if_softc); 66493382Smdodd } 66593382Smdodd break; 66693382Smdodd#endif 66793382Smdodd default: 66893382Smdodd ifp->if_init(ifp->if_softc); 66993382Smdodd break; 670104302Sphk } 671144045Smdodd break; 672332160Sbrooks case SIOCGIFADDR: 673332160Sbrooks bcopy(IF_LLADDR(ifp), &ifr->ifr_addr.sa_data[0], 674332160Sbrooks FDDI_ADDR_LEN); 67593382Smdodd break; 67693382Smdodd case SIOCSIFMTU: 67793382Smdodd /* 67893382Smdodd * Set the interface MTU. 67993382Smdodd */ 68093382Smdodd if (ifr->ifr_mtu > FDDIMTU) { 68193382Smdodd error = EINVAL; 68293382Smdodd } else { 68393382Smdodd ifp->if_mtu = ifr->ifr_mtu; 68493382Smdodd } 68593382Smdodd break; 68693382Smdodd default: 687144045Smdodd error = EINVAL; 68893382Smdodd break; 68993382Smdodd } 69093382Smdodd 69193382Smdodd return (error); 69293382Smdodd} 69393382Smdodd 69468180Sumestatic int 69568180Sumefddi_resolvemulti(ifp, llsa, sa) 69668180Sume struct ifnet *ifp; 69768180Sume struct sockaddr **llsa; 69868180Sume struct sockaddr *sa; 69968180Sume{ 70068180Sume struct sockaddr_dl *sdl; 701184709Sbz#ifdef INET 70268180Sume struct sockaddr_in *sin; 703184709Sbz#endif 70468180Sume#ifdef INET6 70568180Sume struct sockaddr_in6 *sin6; 70668180Sume#endif 70768180Sume u_char *e_addr; 70868180Sume 70968180Sume switch(sa->sa_family) { 71068180Sume case AF_LINK: 71168180Sume /* 71268180Sume * No mapping needed. Just check that it's a valid MC address. 71368180Sume */ 71468180Sume sdl = (struct sockaddr_dl *)sa; 71568180Sume e_addr = LLADDR(sdl); 71668180Sume if ((e_addr[0] & 1) != 1) 71793369Smdodd return (EADDRNOTAVAIL); 71868180Sume *llsa = 0; 71993369Smdodd return (0); 72068180Sume 72168180Sume#ifdef INET 72268180Sume case AF_INET: 72368180Sume sin = (struct sockaddr_in *)sa; 72468180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 72593369Smdodd return (EADDRNOTAVAIL); 726184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 727148641Srwatson M_NOWAIT | M_ZERO); 728148641Srwatson if (sdl == NULL) 729148641Srwatson return (ENOMEM); 73068180Sume sdl->sdl_len = sizeof *sdl; 73168180Sume sdl->sdl_family = AF_LINK; 73268180Sume sdl->sdl_index = ifp->if_index; 73368180Sume sdl->sdl_type = IFT_FDDI; 73468180Sume sdl->sdl_nlen = 0; 73593375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 73668180Sume sdl->sdl_slen = 0; 73768180Sume e_addr = LLADDR(sdl); 73868180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 73968180Sume *llsa = (struct sockaddr *)sdl; 74093369Smdodd return (0); 74168180Sume#endif 74268180Sume#ifdef INET6 74368180Sume case AF_INET6: 74468180Sume sin6 = (struct sockaddr_in6 *)sa; 74568180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 74668180Sume /* 74768180Sume * An IP6 address of 0 means listen to all 74868180Sume * of the Ethernet multicast address used for IP6. 74968180Sume * (This is used for multicast routers.) 75068180Sume */ 75168180Sume ifp->if_flags |= IFF_ALLMULTI; 75268180Sume *llsa = 0; 75393369Smdodd return (0); 75468180Sume } 75568180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 75693369Smdodd return (EADDRNOTAVAIL); 757184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 758148641Srwatson M_NOWAIT | M_ZERO); 759148641Srwatson if (sdl == NULL) 760148641Srwatson return (ENOMEM); 76168180Sume sdl->sdl_len = sizeof *sdl; 76268180Sume sdl->sdl_family = AF_LINK; 76368180Sume sdl->sdl_index = ifp->if_index; 76468180Sume sdl->sdl_type = IFT_FDDI; 76568180Sume sdl->sdl_nlen = 0; 76693375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 76768180Sume sdl->sdl_slen = 0; 76868180Sume e_addr = LLADDR(sdl); 76968180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 77068180Sume *llsa = (struct sockaddr *)sdl; 77193369Smdodd return (0); 77268180Sume#endif 77368180Sume 77468180Sume default: 77568180Sume /* 77668180Sume * Well, the text isn't quite right, but it's the name 77768180Sume * that counts... 77868180Sume */ 77993369Smdodd return (EAFNOSUPPORT); 78068180Sume } 78193375Smdodd 78293375Smdodd return (0); 78368180Sume} 78493375Smdodd 78593375Smdoddstatic moduledata_t fddi_mod = { 78693375Smdodd "fddi", /* module name */ 78793375Smdodd NULL, /* event handler */ 788241394Skevlo 0 /* extra data */ 78993375Smdodd}; 79093375Smdodd 79193375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 79293375SmdoddMODULE_VERSION(fddi, 1); 793