if_fddisubr.c revision 111767
17055Sdg/* 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: head/sys/net/if_fddisubr.c 111767 2003-03-02 21:34:37Z mdodd $ 377055Sdg */ 387055Sdg 3932356Seivind#include "opt_atalk.h" 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4231742Seivind#include "opt_ipx.h" 43105577Srwatson#include "opt_mac.h" 4431742Seivind 457055Sdg#include <sys/param.h> 467055Sdg#include <sys/systm.h> 4793375Smdodd#include <sys/kernel.h> 48105577Srwatson#include <sys/mac.h> 4993375Smdodd#include <sys/malloc.h> 507055Sdg#include <sys/mbuf.h> 5193375Smdodd#include <sys/module.h> 527055Sdg#include <sys/socket.h> 5393375Smdodd#include <sys/sockio.h> 547055Sdg 557055Sdg#include <net/if.h> 567055Sdg#include <net/if_llc.h> 577055Sdg#include <net/if_dl.h> 587055Sdg#include <net/if_types.h> 5993375Smdodd#include <net/netisr.h> 6093375Smdodd#include <net/route.h> 6193375Smdodd#include <net/bpf.h> 6293373Smdodd#include <net/fddi.h> 637055Sdg 6454263Sshin#if defined(INET) || defined(INET6) 657055Sdg#include <netinet/in.h> 667055Sdg#include <netinet/in_var.h> 6732350Seivind#include <netinet/if_ether.h> 687055Sdg#endif 6954263Sshin#ifdef INET6 7054263Sshin#include <netinet6/nd6.h> 7154263Sshin#endif 727055Sdg 7311819Sjulian#ifdef IPX 7421830Sjoerg#include <netipx/ipx.h> 7511819Sjulian#include <netipx/ipx_if.h> 7611819Sjulian#endif 7711819Sjulian 787055Sdg#ifdef NS 797055Sdg#include <netns/ns.h> 807055Sdg#include <netns/ns_if.h> 817055Sdg#endif 827055Sdg 837055Sdg#ifdef DECNET 847055Sdg#include <netdnet/dn.h> 857055Sdg#endif 867055Sdg 8721830Sjoerg#ifdef NETATALK 8821830Sjoerg#include <netatalk/at.h> 8921830Sjoerg#include <netatalk/at_var.h> 9021830Sjoerg#include <netatalk/at_extern.h> 9121830Sjoerg 9221830Sjoergextern u_char at_org_code[ 3 ]; 9321830Sjoergextern u_char aarp_org_code[ 3 ]; 9421830Sjoerg#endif /* NETATALK */ 9521830Sjoerg 9693382Smdoddstatic u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 9793382Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 9893382Smdodd 9993383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 10093084Sbde struct sockaddr *); 10193383Smdoddstatic int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *, 10293383Smdodd struct rtentry *); 103106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m); 10468180Sume 10593383Smdodd 10693369Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP) 10793369Smdodd#define senderr(e) { error = (e); goto bad; } 10893369Smdodd 1097055Sdg/* 1107055Sdg * FDDI output routine. 1117055Sdg * Encapsulate a packet of type family for the local net. 1127055Sdg * Use trailer local net encapsulation if enough data in first 1137055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1147055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1157055Sdg */ 11693383Smdoddstatic int 11754799Sgreenfddi_output(ifp, m, dst, rt0) 11893367Smdodd struct ifnet *ifp; 11954799Sgreen struct mbuf *m; 1207055Sdg struct sockaddr *dst; 1217055Sdg struct rtentry *rt0; 1227055Sdg{ 12321830Sjoerg u_int16_t type; 12469152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 12593373Smdodd u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 12693367Smdodd struct rtentry *rt; 12793367Smdodd struct fddi_header *fh; 12893369Smdodd struct arpcom *ac = IFP2AC(ifp); 1297055Sdg 130105577Srwatson#ifdef MAC 131105577Srwatson error = mac_check_ifnet_transmit(ifp, m); 132105577Srwatson if (error) 133105577Srwatson senderr(error); 134105577Srwatson#endif 135105577Srwatson 1367055Sdg if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1377055Sdg senderr(ENETDOWN); 13834961Sphk getmicrotime(&ifp->if_lastchange); 139111767Smdodd 140111767Smdodd error = rt_check(&rt, &rt0, dst); 141111767Smdodd if (error) 142111767Smdodd goto bad; 143111767Smdodd 1447055Sdg switch (dst->sa_family) { 1457055Sdg 1467055Sdg#ifdef INET 14721830Sjoerg case AF_INET: { 14893369Smdodd if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 1497055Sdg return (0); /* if not yet resolved */ 15021830Sjoerg type = htons(ETHERTYPE_IP); 1517055Sdg break; 15221830Sjoerg } 1537055Sdg#endif 15454263Sshin#ifdef INET6 15554263Sshin case AF_INET6: 15693375Smdodd if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) { 15774093Sbmilekic /* Something bad happened */ 15893369Smdodd return (0); 15954263Sshin } 16054263Sshin type = htons(ETHERTYPE_IPV6); 16154263Sshin break; 16254263Sshin#endif 16311819Sjulian#ifdef IPX 16411819Sjulian case AF_IPX: 16521830Sjoerg type = htons(ETHERTYPE_IPX); 16611819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 16793373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 16811819Sjulian break; 16911819Sjulian#endif 17021830Sjoerg#ifdef NETATALK 17121830Sjoerg case AF_APPLETALK: { 17221830Sjoerg struct at_ifaddr *aa; 17336908Sjulian if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 17421830Sjoerg return (0); 17521830Sjoerg /* 17621830Sjoerg * ifaddr is the first thing in at_ifaddr 17721830Sjoerg */ 17830834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 17921830Sjoerg goto bad; 18021830Sjoerg 18121830Sjoerg /* 18221830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 18321830Sjoerg * Since we must preserve the value of m, which is passed to us by 18421830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 18521830Sjoerg */ 18621830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 18721830Sjoerg struct llc llc; 18821830Sjoerg 189111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT); 19021830Sjoerg if (m == 0) 19121830Sjoerg senderr(ENOBUFS); 19221830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 19321830Sjoerg llc.llc_control = LLC_UI; 19493371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 19593371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 19693373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 19721830Sjoerg type = 0; 19821830Sjoerg } else { 19921830Sjoerg type = htons(ETHERTYPE_AT); 20021830Sjoerg } 20121830Sjoerg break; 20221830Sjoerg } 20321830Sjoerg#endif /* NETATALK */ 2047055Sdg#ifdef NS 2057055Sdg case AF_NS: 20621830Sjoerg type = htons(ETHERTYPE_NS); 2077055Sdg bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 20893373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 2097055Sdg break; 2107055Sdg#endif 2117055Sdg 21252248Smsmith case pseudo_AF_HDRCMPLT: 21352248Smsmith { 21493376Smdodd struct ether_header *eh; 21552248Smsmith hdrcmplt = 1; 21693376Smdodd eh = (struct ether_header *)dst->sa_data; 21793376Smdodd bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 21852248Smsmith /* FALLTHROUGH */ 21952248Smsmith } 22052248Smsmith 2217055Sdg case AF_UNSPEC: 2227055Sdg { 2237055Sdg struct ether_header *eh; 22436992Sjulian loop_copy = -1; 2257055Sdg eh = (struct ether_header *)dst->sa_data; 22693375Smdodd bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 2277055Sdg if (*edst & 1) 2287055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2297055Sdg type = eh->ether_type; 2307055Sdg break; 2317055Sdg } 2327055Sdg 2337055Sdg case AF_IMPLINK: 2347055Sdg { 2357055Sdg fh = mtod(m, struct fddi_header *); 2367055Sdg error = EPROTONOSUPPORT; 2377055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2387055Sdg case FDDIFC_LLC_ASYNC: { 2397055Sdg /* legal priorities are 0 through 7 */ 2407055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2417055Sdg goto bad; 2427055Sdg break; 2437055Sdg } 2447055Sdg case FDDIFC_LLC_SYNC: { 2457055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2467055Sdg if (fh->fddi_fc & FDDIFC_Z) 2477055Sdg goto bad; 2487055Sdg break; 2497055Sdg } 2507055Sdg case FDDIFC_SMT: { 2517055Sdg /* FDDIFC_Z bits must be non zero */ 2527055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2537055Sdg goto bad; 2547055Sdg break; 2557055Sdg } 2567055Sdg default: { 2577055Sdg /* anything else is too dangerous */ 2587055Sdg goto bad; 2597055Sdg } 2607055Sdg } 2617055Sdg error = 0; 2627055Sdg if (fh->fddi_dhost[0] & 1) 2637055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2647055Sdg goto queue_it; 2657055Sdg } 2667055Sdg default: 267105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 2687055Sdg senderr(EAFNOSUPPORT); 2697055Sdg } 2707055Sdg 27193380Smdodd /* 27293380Smdodd * Add LLC header. 27393380Smdodd */ 2747055Sdg if (type != 0) { 27593367Smdodd struct llc *l; 276111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 2777055Sdg if (m == 0) 2787055Sdg senderr(ENOBUFS); 2797055Sdg l = mtod(m, struct llc *); 2807055Sdg l->llc_control = LLC_UI; 2817055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 2827055Sdg l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 28393375Smdodd bcopy((caddr_t)&type, (caddr_t)&l->llc_snap.ether_type, 28421830Sjoerg sizeof(u_int16_t)); 2857055Sdg } 28636908Sjulian 2877055Sdg /* 2887055Sdg * Add local net header. If no space in first mbuf, 2897055Sdg * allocate another. 2907055Sdg */ 291111119Simp M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 2927055Sdg if (m == 0) 2937055Sdg senderr(ENOBUFS); 2947055Sdg fh = mtod(m, struct fddi_header *); 2957055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 29693375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 2977055Sdg queue_it: 29852248Smsmith if (hdrcmplt) 29993375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 30052248Smsmith else 30193375Smdodd bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost, 30293373Smdodd FDDI_ADDR_LEN); 30393377Smdodd 30436908Sjulian /* 30536908Sjulian * If a simplex interface, and the packet is being sent to our 30636908Sjulian * Ethernet address or a broadcast address, loopback a copy. 30736908Sjulian * XXX To make a simplex device behave exactly like a duplex 30836908Sjulian * device, we should copy in the case of sending to our own 30936908Sjulian * ethernet address (thus letting the original actually appear 31036908Sjulian * on the wire). However, we don't do that here for security 31136908Sjulian * reasons and compatibility with the original behavior. 31236908Sjulian */ 31393377Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 31436908Sjulian if ((m->m_flags & M_BCAST) || loop_copy) { 31536908Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 31636908Sjulian 31736908Sjulian (void) if_simloop(ifp, 31893373Smdodd n, dst->sa_family, FDDI_HDR_LEN); 31936908Sjulian } else if (bcmp(fh->fddi_dhost, 32093373Smdodd fh->fddi_shost, FDDI_ADDR_LEN) == 0) { 32136908Sjulian (void) if_simloop(ifp, 32293373Smdodd m, dst->sa_family, FDDI_HDR_LEN); 32393369Smdodd return (0); /* XXX */ 32436908Sjulian } 32536908Sjulian } 32636908Sjulian 32769152Sjlemon if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 3287055Sdg senderr(ENOBUFS); 3297055Sdg return (error); 3307055Sdg 3317055Sdgbad: 33293379Smdodd ifp->if_oerrors++; 3337055Sdg if (m) 3347055Sdg m_freem(m); 3357055Sdg return (error); 3367055Sdg} 3377055Sdg 3387055Sdg/* 3397055Sdg * Process a received FDDI packet; 3407055Sdg * the packet is in the mbuf chain m without 3417055Sdg * the fddi header, which is provided separately. 3427055Sdg */ 343106939Ssamstatic void 344106939Ssamfddi_input(ifp, m) 3457055Sdg struct ifnet *ifp; 3467055Sdg struct mbuf *m; 3477055Sdg{ 34893367Smdodd struct ifqueue *inq; 34993367Smdodd struct llc *l; 350106939Ssam struct fddi_header *fh; 3517055Sdg 352106939Ssam fh = mtod(m, struct fddi_header *); 353106939Ssam 35493379Smdodd /* 355106939Ssam * Update interface statistics. 356106939Ssam */ 357106939Ssam ifp->if_ibytes += m->m_pkthdr.len; 358106939Ssam getmicrotime(&ifp->if_lastchange); 359106939Ssam 360106939Ssam /* 36193379Smdodd * Discard packet if interface is not up. 36293379Smdodd */ 36393379Smdodd if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 36493379Smdodd goto dropanyway; 36593379Smdodd 366105577Srwatson#ifdef MAC 367105577Srwatson mac_create_mbuf_from_ifnet(ifp, m); 368105577Srwatson#endif 369105577Srwatson 37093379Smdodd /* 37193379Smdodd * Discard non local unicast packets when interface 37293379Smdodd * is in promiscuous mode. 37393379Smdodd */ 37493379Smdodd if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 37593379Smdodd (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 37693379Smdodd FDDI_ADDR_LEN) != 0)) 37793379Smdodd goto dropanyway; 37893379Smdodd 37993379Smdodd /* 38093379Smdodd * Set mbuf flags for bcast/mcast. 38193379Smdodd */ 38221830Sjoerg if (fh->fddi_dhost[0] & 1) { 38393381Smdodd if (bcmp((caddr_t)ifp->if_broadcastaddr, 38493381Smdodd (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN) == 0) 38521830Sjoerg m->m_flags |= M_BCAST; 38621830Sjoerg else 38721830Sjoerg m->m_flags |= M_MCAST; 3887055Sdg ifp->if_imcasts++; 38921830Sjoerg } 3907055Sdg 39121830Sjoerg#ifdef M_LINK0 39221830Sjoerg /* 39321830Sjoerg * If this has a LLC priority of 0, then mark it so upper 39421830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 39521830Sjoerg * bridge. 39621830Sjoerg */ 39721830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 39821830Sjoerg m->m_flags |= M_LINK0; 39921830Sjoerg#endif 40021830Sjoerg 401106939Ssam /* Strip off FDDI header. */ 402106939Ssam m_adj(m, sizeof(struct fddi_header)); 403106939Ssam 40493379Smdodd m = m_pullup(m, sizeof(struct llc)); 40593379Smdodd if (m == 0) { 40693379Smdodd ifp->if_ierrors++; 40793379Smdodd goto dropanyway; 40893379Smdodd } 4097055Sdg l = mtod(m, struct llc *); 41093377Smdodd 4117055Sdg switch (l->llc_dsap) { 4127055Sdg case LLC_SNAP_LSAP: 4137055Sdg { 41421830Sjoerg u_int16_t type; 41593379Smdodd if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) { 41693379Smdodd ifp->if_noproto++; 4177055Sdg goto dropanyway; 41893379Smdodd } 41921830Sjoerg#ifdef NETATALK 42093371Smdodd if (Bcmp(&(l->llc_snap.org_code)[0], at_org_code, 42121830Sjoerg sizeof(at_org_code)) == 0 && 42293371Smdodd ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 42321830Sjoerg inq = &atintrq2; 42493373Smdodd m_adj(m, LLC_SNAPFRAMELEN); 42521830Sjoerg schednetisr(NETISR_ATALK); 42621830Sjoerg break; 42721830Sjoerg } 42821830Sjoerg 42993371Smdodd if (Bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 43021830Sjoerg sizeof(aarp_org_code)) == 0 && 43193371Smdodd ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 43293373Smdodd m_adj(m, LLC_SNAPFRAMELEN); 43393369Smdodd aarpinput(IFP2AC(ifp), m); /* XXX */ 43421830Sjoerg return; 43521830Sjoerg } 43621830Sjoerg#endif /* NETATALK */ 43793377Smdodd if (l->llc_snap.org_code[0] != 0 || 43893377Smdodd l->llc_snap.org_code[1] != 0 || 43993379Smdodd l->llc_snap.org_code[2] != 0) { 44093379Smdodd ifp->if_noproto++; 4417055Sdg goto dropanyway; 44293379Smdodd } 44393377Smdodd 44421830Sjoerg type = ntohs(l->llc_snap.ether_type); 44593377Smdodd m_adj(m, LLC_SNAPFRAMELEN); 44693377Smdodd 44721830Sjoerg switch (type) { 4487055Sdg#ifdef INET 4497055Sdg case ETHERTYPE_IP: 45036265Sdg if (ipflow_fastforward(m)) 45136192Sdg return; 4527055Sdg schednetisr(NETISR_IP); 4537055Sdg inq = &ipintrq; 4547055Sdg break; 4557055Sdg 4567055Sdg case ETHERTYPE_ARP: 45778295Sjlemon if (ifp->if_flags & IFF_NOARP) 45878295Sjlemon goto dropanyway; 4597055Sdg schednetisr(NETISR_ARP); 4607055Sdg inq = &arpintrq; 4617055Sdg break; 4627055Sdg#endif 46354263Sshin#ifdef INET6 46454263Sshin case ETHERTYPE_IPV6: 46554263Sshin schednetisr(NETISR_IPV6); 46654263Sshin inq = &ip6intrq; 46754263Sshin break; 46854263Sshin#endif 46921830Sjoerg#ifdef IPX 47021830Sjoerg case ETHERTYPE_IPX: 47121830Sjoerg schednetisr(NETISR_IPX); 47221830Sjoerg inq = &ipxintrq; 47321830Sjoerg break; 47421830Sjoerg#endif 4757055Sdg#ifdef NS 4767055Sdg case ETHERTYPE_NS: 4777055Sdg schednetisr(NETISR_NS); 4787055Sdg inq = &nsintrq; 4797055Sdg break; 4807055Sdg#endif 4817055Sdg#ifdef DECNET 48221830Sjoerg case ETHERTYPE_DECNET: 4837055Sdg schednetisr(NETISR_DECNET); 4847055Sdg inq = &decnetintrq; 4857055Sdg break; 4867055Sdg#endif 48721830Sjoerg#ifdef NETATALK 48821830Sjoerg case ETHERTYPE_AT: 48921830Sjoerg schednetisr(NETISR_ATALK); 49021830Sjoerg inq = &atintrq1; 49121830Sjoerg break; 49221830Sjoerg case ETHERTYPE_AARP: 49321830Sjoerg /* probably this should be done with a NETISR as well */ 49493369Smdodd aarpinput(IFP2AC(ifp), m); /* XXX */ 49521830Sjoerg return; 49621830Sjoerg#endif /* NETATALK */ 4977055Sdg default: 49821830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 4997055Sdg ifp->if_noproto++; 5007055Sdg goto dropanyway; 5017055Sdg } 5027055Sdg break; 5037055Sdg } 50421830Sjoerg 5057055Sdg default: 50621830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 5077055Sdg ifp->if_noproto++; 50893377Smdodd goto dropanyway; 5097055Sdg } 5107055Sdg 51169152Sjlemon (void) IF_HANDOFF(inq, m, NULL); 51293377Smdodd return; 51393377Smdodd 51493377Smdodddropanyway: 51593377Smdodd ifp->if_iqdrops++; 51693377Smdodd if (m) 51793377Smdodd m_freem(m); 51893377Smdodd return; 5197055Sdg} 52093380Smdodd 5217055Sdg/* 5227055Sdg * Perform common duties while attaching to interface list 5237055Sdg */ 5247055Sdgvoid 52593383Smdoddfddi_ifattach(ifp, bpf) 52693367Smdodd struct ifnet *ifp; 52793383Smdodd int bpf; 5287055Sdg{ 52993367Smdodd struct ifaddr *ifa; 53093367Smdodd struct sockaddr_dl *sdl; 5317055Sdg 5327055Sdg ifp->if_type = IFT_FDDI; 53393373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 5347055Sdg ifp->if_hdrlen = 21; 53593379Smdodd 53693379Smdodd if_attach(ifp); /* Must be called before additional assignments */ 53793379Smdodd 5387055Sdg ifp->if_mtu = FDDIMTU; 53993379Smdodd ifp->if_output = fddi_output; 540106939Ssam ifp->if_input = fddi_input; 54168180Sume ifp->if_resolvemulti = fddi_resolvemulti; 54293379Smdodd ifp->if_broadcastaddr = fddibroadcastaddr; 54316063Sgpalmer ifp->if_baudrate = 100000000; 54421830Sjoerg#ifdef IFF_NOTRAILERS 54521830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 54621830Sjoerg#endif 54783130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 54893379Smdodd if (ifa == NULL) { 54993379Smdodd printf("%s(): no lladdr for %s%d!\n", __FUNCTION__, 55093379Smdodd ifp->if_name, ifp->if_unit); 55193379Smdodd return; 55293379Smdodd } 55393379Smdodd 55421831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 55521831Sjoerg sdl->sdl_type = IFT_FDDI; 55621831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 55793369Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 55893379Smdodd 55993383Smdodd if (bpf) 56093383Smdodd bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 56193383Smdodd 56293379Smdodd return; 5637055Sdg} 56468180Sume 56593382Smdoddvoid 56693382Smdoddfddi_ifdetach(ifp, bpf) 56793382Smdodd struct ifnet *ifp; 56893382Smdodd int bpf; 56993382Smdodd{ 57093382Smdodd 57193382Smdodd if (bpf) 57293382Smdodd bpfdetach(ifp); 57393382Smdodd 57493382Smdodd if_detach(ifp); 57593382Smdodd 57693382Smdodd return; 57793382Smdodd} 57893382Smdodd 57993382Smdoddint 58093382Smdoddfddi_ioctl (ifp, command, data) 58193382Smdodd struct ifnet *ifp; 58293382Smdodd int command; 58393382Smdodd caddr_t data; 58493382Smdodd{ 58593382Smdodd struct ifaddr *ifa; 58693382Smdodd struct ifreq *ifr; 58793382Smdodd int error; 58893382Smdodd 58993382Smdodd ifa = (struct ifaddr *) data; 59093382Smdodd ifr = (struct ifreq *) data; 59193382Smdodd error = 0; 59293382Smdodd 59393382Smdodd switch (command) { 59493382Smdodd case SIOCSIFADDR: 59593382Smdodd ifp->if_flags |= IFF_UP; 59693382Smdodd 59793382Smdodd switch (ifa->ifa_addr->sa_family) { 59893382Smdodd#ifdef INET 59993382Smdodd case AF_INET: /* before arpwhohas */ 60093382Smdodd ifp->if_init(ifp->if_softc); 60193382Smdodd arp_ifinit(ifp, ifa); 60293382Smdodd break; 60393382Smdodd#endif 60493382Smdodd#ifdef IPX 60593382Smdodd /* 60693382Smdodd * XXX - This code is probably wrong 60793382Smdodd */ 60893382Smdodd case AF_IPX: { 60993382Smdodd struct ipx_addr *ina; 61093382Smdodd struct arpcom *ac; 61193382Smdodd 61293382Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 61393382Smdodd ac = IFP2AC(ifp); 61493382Smdodd 61593382Smdodd if (ipx_nullhost(*ina)) { 61693382Smdodd ina->x_host = *(union ipx_host *) 61793382Smdodd ac->ac_enaddr; 61893382Smdodd } else { 61993382Smdodd bcopy((caddr_t) ina->x_host.c_host, 62093382Smdodd (caddr_t) ac->ac_enaddr, 62193382Smdodd sizeof(ac->ac_enaddr)); 62293382Smdodd } 62393382Smdodd 62493382Smdodd /* 62593382Smdodd * Set new address 62693382Smdodd */ 62793382Smdodd ifp->if_init(ifp->if_softc); 62893382Smdodd } 62993382Smdodd break; 63093382Smdodd#endif 63193382Smdodd default: 63293382Smdodd ifp->if_init(ifp->if_softc); 63393382Smdodd break; 634104302Sphk } 63593382Smdodd case SIOCGIFADDR: { 63693382Smdodd struct sockaddr *sa; 63793382Smdodd 63893382Smdodd sa = (struct sockaddr *) & ifr->ifr_data; 63993382Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, 64093382Smdodd (caddr_t) sa->sa_data, FDDI_ADDR_LEN); 64193382Smdodd 64293382Smdodd } 64393382Smdodd break; 64493382Smdodd case SIOCSIFMTU: 64593382Smdodd /* 64693382Smdodd * Set the interface MTU. 64793382Smdodd */ 64893382Smdodd if (ifr->ifr_mtu > FDDIMTU) { 64993382Smdodd error = EINVAL; 65093382Smdodd } else { 65193382Smdodd ifp->if_mtu = ifr->ifr_mtu; 65293382Smdodd } 65393382Smdodd break; 65493382Smdodd default: 65593382Smdodd break; 65693382Smdodd } 65793382Smdodd 65893382Smdodd return (error); 65993382Smdodd} 66093382Smdodd 66168180Sumestatic int 66268180Sumefddi_resolvemulti(ifp, llsa, sa) 66368180Sume struct ifnet *ifp; 66468180Sume struct sockaddr **llsa; 66568180Sume struct sockaddr *sa; 66668180Sume{ 66768180Sume struct sockaddr_dl *sdl; 66868180Sume struct sockaddr_in *sin; 66968180Sume#ifdef INET6 67068180Sume struct sockaddr_in6 *sin6; 67168180Sume#endif 67268180Sume u_char *e_addr; 67368180Sume 67468180Sume switch(sa->sa_family) { 67568180Sume case AF_LINK: 67668180Sume /* 67768180Sume * No mapping needed. Just check that it's a valid MC address. 67868180Sume */ 67968180Sume sdl = (struct sockaddr_dl *)sa; 68068180Sume e_addr = LLADDR(sdl); 68168180Sume if ((e_addr[0] & 1) != 1) 68293369Smdodd return (EADDRNOTAVAIL); 68368180Sume *llsa = 0; 68493369Smdodd return (0); 68568180Sume 68668180Sume#ifdef INET 68768180Sume case AF_INET: 68868180Sume sin = (struct sockaddr_in *)sa; 68968180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 69093369Smdodd return (EADDRNOTAVAIL); 69168180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 692111119Simp M_WAITOK); 69368180Sume sdl->sdl_len = sizeof *sdl; 69468180Sume sdl->sdl_family = AF_LINK; 69568180Sume sdl->sdl_index = ifp->if_index; 69668180Sume sdl->sdl_type = IFT_FDDI; 69768180Sume sdl->sdl_nlen = 0; 69893375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 69968180Sume sdl->sdl_slen = 0; 70068180Sume e_addr = LLADDR(sdl); 70168180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 70268180Sume *llsa = (struct sockaddr *)sdl; 70393369Smdodd return (0); 70468180Sume#endif 70568180Sume#ifdef INET6 70668180Sume case AF_INET6: 70768180Sume sin6 = (struct sockaddr_in6 *)sa; 70868180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 70968180Sume /* 71068180Sume * An IP6 address of 0 means listen to all 71168180Sume * of the Ethernet multicast address used for IP6. 71268180Sume * (This is used for multicast routers.) 71368180Sume */ 71468180Sume ifp->if_flags |= IFF_ALLMULTI; 71568180Sume *llsa = 0; 71693369Smdodd return (0); 71768180Sume } 71868180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 71993369Smdodd return (EADDRNOTAVAIL); 72068180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 721111119Simp M_WAITOK); 72268180Sume sdl->sdl_len = sizeof *sdl; 72368180Sume sdl->sdl_family = AF_LINK; 72468180Sume sdl->sdl_index = ifp->if_index; 72568180Sume sdl->sdl_type = IFT_FDDI; 72668180Sume sdl->sdl_nlen = 0; 72793375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 72868180Sume sdl->sdl_slen = 0; 72968180Sume e_addr = LLADDR(sdl); 73068180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 73168180Sume *llsa = (struct sockaddr *)sdl; 73293369Smdodd return (0); 73368180Sume#endif 73468180Sume 73568180Sume default: 73668180Sume /* 73768180Sume * Well, the text isn't quite right, but it's the name 73868180Sume * that counts... 73968180Sume */ 74093369Smdodd return (EAFNOSUPPORT); 74168180Sume } 74293375Smdodd 74393375Smdodd return (0); 74468180Sume} 74593375Smdodd 74693375Smdoddstatic moduledata_t fddi_mod = { 74793375Smdodd "fddi", /* module name */ 74893375Smdodd NULL, /* event handler */ 74993375Smdodd 0 /* extra data */ 75093375Smdodd}; 75193375Smdodd 75293375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 75393375SmdoddMODULE_VERSION(fddi, 1); 754