The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_ef.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999, 2000 Boris Popov
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/5.2/sys/net/if_ef.c 122702 2003-11-14 21:02:22Z andre $
   27  */
   28 
   29 #include "opt_inet.h"
   30 #include "opt_ipx.h"
   31 #include "opt_ef.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/sockio.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/socket.h>
   39 #include <sys/syslog.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 
   43 #include <net/ethernet.h>
   44 #include <net/if_llc.h>
   45 #include <net/if.h>
   46 #include <net/if_arp.h>
   47 #include <net/if_dl.h>
   48 #include <net/if_types.h>
   49 #include <net/netisr.h>
   50 #include <net/route.h>
   51 #include <net/bpf.h>
   52 
   53 #ifdef INET
   54 #include <netinet/in.h>
   55 #include <netinet/in_var.h>
   56 #include <netinet/if_ether.h>
   57 #endif
   58 
   59 #ifdef IPX
   60 #include <netipx/ipx.h>
   61 #include <netipx/ipx_if.h>
   62 #endif
   63 
   64 /* internal frame types */
   65 #define ETHER_FT_EII            0       /* Ethernet_II - default */
   66 #define ETHER_FT_8023           1       /* 802.3 (Novell) */
   67 #define ETHER_FT_8022           2       /* 802.2 */
   68 #define ETHER_FT_SNAP           3       /* SNAP */
   69 #define EF_NFT                  4       /* total number of frame types */
   70 
   71 #ifdef EF_DEBUG
   72 #define EFDEBUG(format, args...) printf("%s: "format, __func__ ,## args)
   73 #else
   74 #define EFDEBUG(format, args...)
   75 #endif
   76 
   77 #define EFERROR(format, args...) printf("%s: "format, __func__ ,## args)
   78 
   79 struct efnet {
   80         struct arpcom   ef_ac;
   81         struct ifnet *  ef_ifp;
   82         int             ef_frametype;
   83 };
   84 
   85 struct ef_link {
   86         SLIST_ENTRY(ef_link) el_next;
   87         struct ifnet    *el_ifp;                /* raw device for this clones */
   88         struct efnet    *el_units[EF_NFT];      /* our clones */
   89 };
   90 
   91 static SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
   92 static int efcount;
   93 
   94 extern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m);
   95 extern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
   96                 struct sockaddr *dst, short *tp, int *hlen);
   97 
   98 /*
   99 static void ef_reset (struct ifnet *);
  100 */
  101 static int ef_attach(struct efnet *sc);
  102 static int ef_detach(struct efnet *sc);
  103 static void ef_init(void *);
  104 static int ef_ioctl(struct ifnet *, u_long, caddr_t);
  105 static void ef_start(struct ifnet *);
  106 static int ef_input(struct ifnet*, struct ether_header *, struct mbuf *);
  107 static int ef_output(struct ifnet *ifp, struct mbuf **mp,
  108                 struct sockaddr *dst, short *tp, int *hlen);
  109 
  110 static int ef_load(void);
  111 static int ef_unload(void);
  112 
  113 /*
  114  * Install the interface, most of structure initialization done in ef_clone()
  115  */
  116 static int
  117 ef_attach(struct efnet *sc)
  118 {
  119         struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
  120         struct ifaddr *ifa2;
  121         struct sockaddr_dl *sdl2;
  122 
  123         ifp->if_output = ether_output;
  124         ifp->if_start = ef_start;
  125         ifp->if_watchdog = NULL;
  126         ifp->if_init = ef_init;
  127         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  128         ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
  129         /*
  130          * Attach the interface
  131          */
  132         ifa2 = ifaddr_byindex(sc->ef_ifp->if_index);
  133         sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
  134         ether_ifattach(ifp, LLADDR(sdl2));
  135 
  136         ifp->if_resolvemulti = 0;
  137         ifp->if_type = IFT_XETHER;
  138         ifp->if_flags |= IFF_RUNNING;
  139 
  140         bcopy(LLADDR(sdl2), sc->ef_ac.ac_enaddr, ETHER_ADDR_LEN);
  141 
  142         EFDEBUG("%s: attached\n", ifp->if_xname);
  143         return 1;
  144 }
  145 
  146 /*
  147  * This is for _testing_only_, just removes interface from interfaces list
  148  */
  149 static int
  150 ef_detach(struct efnet *sc)
  151 {
  152         struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
  153         int s;
  154 
  155         s = splimp();
  156 
  157         if (ifp->if_flags & IFF_UP) {
  158                 if_down(ifp);
  159                 if (ifp->if_flags & IFF_RUNNING) {
  160                     /* find internet addresses and delete routes */
  161                     register struct ifaddr *ifa;
  162                     TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  163                             rtinit(ifa, (int)RTM_DELETE, 0);
  164                     }
  165                 }
  166         }
  167         IFNET_WLOCK();
  168         TAILQ_REMOVE(&ifnet, ifp, if_link);
  169         IFNET_WUNLOCK();
  170         splx(s);
  171         return 0;
  172 }
  173 
  174 static void
  175 ef_init(void *foo) {
  176         return;
  177 }
  178 
  179 static int
  180 ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  181 {
  182         struct efnet *sc = ifp->if_softc;
  183         struct ifaddr *ifa = (struct ifaddr*)data;
  184         int s, error;
  185 
  186         EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
  187         error = 0;
  188         s = splimp();
  189         switch (cmd) {
  190             case SIOCSIFFLAGS:
  191                 error = 0;
  192                 break;
  193             case SIOCSIFADDR:
  194                 if (sc->ef_frametype == ETHER_FT_8023 && 
  195                     ifa->ifa_addr->sa_family != AF_IPX) {
  196                         error = EAFNOSUPPORT;
  197                         break;
  198                 }
  199                 ifp->if_flags |= IFF_UP; 
  200                 /* FALL THROUGH */
  201             default:
  202                 error = ether_ioctl(ifp, cmd, data);
  203                 break;
  204         }
  205         splx(s);
  206         return error;
  207 }
  208 
  209 /*
  210  * Currently packet prepared in the ether_output(), but this can be a better
  211  * place.
  212  */
  213 static void
  214 ef_start(struct ifnet *ifp)
  215 {
  216         struct efnet *sc = (struct efnet*)ifp->if_softc;
  217         struct ifnet *p;
  218         struct mbuf *m;
  219 
  220         ifp->if_flags |= IFF_OACTIVE;
  221         p = sc->ef_ifp;
  222 
  223         EFDEBUG("\n");
  224         for (;;) {
  225                 IF_DEQUEUE(&ifp->if_snd, m);
  226                 if (m == 0)
  227                         break;
  228                 BPF_MTAP(ifp, m);
  229                 if (! IF_HANDOFF(&p->if_snd, m, p)) {
  230                         ifp->if_oerrors++;
  231                         continue;
  232                 }
  233                 ifp->if_opackets++;
  234         }
  235         ifp->if_flags &= ~IFF_OACTIVE;
  236         return;
  237 }
  238 
  239 /*
  240  * Inline functions do not put additional overhead to procedure call or
  241  * parameter passing but simplify the code
  242  */
  243 static int __inline
  244 ef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
  245 {
  246         int isr;
  247 
  248         switch(ether_type) {
  249 #ifdef IPX
  250         case ETHERTYPE_IPX:
  251                 isr = NETISR_IPX;
  252                 break;
  253 #endif
  254 #ifdef INET
  255         case ETHERTYPE_IP:
  256                 if (ip_fastforward(m))
  257                         return (0);
  258                 isr = NETISR_IP;
  259                 break;
  260 
  261         case ETHERTYPE_ARP:
  262                 isr = NETISR_ARP;
  263                 break;
  264 #endif
  265         default:
  266                 return (EPROTONOSUPPORT);
  267         }
  268         netisr_dispatch(isr, m);
  269         return (0);
  270 }
  271 
  272 static int __inline
  273 ef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
  274         u_short ether_type)
  275 {
  276         int isr;
  277 
  278         switch(ether_type) {
  279 #ifdef IPX
  280         case ETHERTYPE_IPX:
  281                 m_adj(m, 8);
  282                 isr = NETISR_IPX;
  283                 break;
  284 #endif
  285         default:
  286                 return (EPROTONOSUPPORT);
  287         }
  288         netisr_dispatch(isr, m);
  289         return (0);
  290 }
  291 
  292 static int __inline
  293 ef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
  294         u_short ether_type)
  295 {
  296         int isr;
  297 
  298         switch(ether_type) {
  299 #ifdef IPX
  300         case 0xe0:
  301                 m_adj(m, 3);
  302                 isr = NETISR_IPX;
  303                 break;
  304 #endif
  305         default:
  306                 return (EPROTONOSUPPORT);
  307         }
  308         netisr_dispatch(isr, m);
  309         return (0);
  310 }
  311 
  312 /*
  313  * Called from ether_input()
  314  */
  315 static int
  316 ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
  317 {
  318         u_short ether_type;
  319         int ft = -1;
  320         struct efnet *efp;
  321         struct ifnet *eifp;
  322         struct llc *l;
  323         struct ef_link *efl;
  324         int isr;
  325 
  326         ether_type = ntohs(eh->ether_type);
  327         if (ether_type < ETHERMTU) {
  328                 l = mtod(m, struct llc*);
  329                 if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
  330                         /* 
  331                          * Novell's "802.3" frame
  332                          */
  333                         ft = ETHER_FT_8023;
  334                 } else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
  335                         /*
  336                          * 802.2/SNAP
  337                          */
  338                         ft = ETHER_FT_SNAP;
  339                         ether_type = ntohs(l->llc_un.type_snap.ether_type);
  340                 } else if (l->llc_dsap == l->llc_ssap) {
  341                         /*
  342                          * 802.3/802.2
  343                          */
  344                         ft = ETHER_FT_8022;
  345                         ether_type = l->llc_ssap;
  346                 }
  347         } else
  348                 ft = ETHER_FT_EII;
  349 
  350         if (ft == -1) {
  351                 EFDEBUG("Unrecognised ether_type %x\n", ether_type);
  352                 return EPROTONOSUPPORT;
  353         }
  354 
  355         /*
  356          * Check if interface configured for the given frame
  357          */
  358         efp = NULL;
  359         SLIST_FOREACH(efl, &efdev, el_next) {
  360                 if (efl->el_ifp == ifp) {
  361                         efp = efl->el_units[ft];
  362                         break;
  363                 }
  364         }
  365         if (efp == NULL) {
  366                 EFDEBUG("Can't find if for %d\n", ft);
  367                 return EPROTONOSUPPORT;
  368         }
  369         eifp = &efp->ef_ac.ac_if;
  370         if ((eifp->if_flags & IFF_UP) == 0)
  371                 return EPROTONOSUPPORT;
  372         eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
  373         m->m_pkthdr.rcvif = eifp;
  374 
  375         if (eifp->if_bpf) {
  376                 struct mbuf m0;
  377                 m0.m_next = m;
  378                 m0.m_len = ETHER_HDR_LEN;
  379                 m0.m_data = (char *)eh;
  380                 BPF_MTAP(eifp, &m0);
  381         }
  382         /*
  383          * Now we ready to adjust mbufs and pass them to protocol intr's
  384          */
  385         switch(ft) {
  386         case ETHER_FT_EII:
  387                 return (ef_inputEII(m, eh, ether_type));
  388 #ifdef IPX
  389         case ETHER_FT_8023:             /* only IPX can be here */
  390                 isr = NETISR_IPX;
  391                 break;
  392 #endif
  393         case ETHER_FT_SNAP:
  394                 return (ef_inputSNAP(m, eh, l, ether_type));
  395         case ETHER_FT_8022:
  396                 return (ef_input8022(m, eh, l, ether_type));
  397         default:
  398                 EFDEBUG("No support for frame %d and proto %04x\n",
  399                         ft, ether_type);
  400                 return (EPROTONOSUPPORT);
  401         }
  402         netisr_dispatch(isr, m);
  403         return (0);
  404 }
  405 
  406 static int
  407 ef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
  408         int *hlen)
  409 {
  410         struct efnet *sc = (struct efnet*)ifp->if_softc;
  411         struct mbuf *m = *mp;
  412         u_char *cp;
  413         short type;
  414 
  415         if (ifp->if_type != IFT_XETHER)
  416                 return ENETDOWN;
  417         switch (sc->ef_frametype) {
  418             case ETHER_FT_EII:
  419 #ifdef IPX
  420                 type = htons(ETHERTYPE_IPX);
  421 #else
  422                 return EPFNOSUPPORT;
  423 #endif
  424                 break;
  425             case ETHER_FT_8023:
  426                 type = htons(m->m_pkthdr.len);
  427                 break;
  428             case ETHER_FT_8022:
  429                 M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
  430                 if (m == NULL) {
  431                         *mp = NULL;
  432                         return ENOBUFS;
  433                 }
  434                 /*
  435                  * Ensure that ethernet header and next three bytes
  436                  * will fit into single mbuf
  437                  */
  438                 m = m_pullup(m, ETHER_HDR_LEN + 3);
  439                 if (m == NULL) {
  440                         *mp = NULL;
  441                         return ENOBUFS;
  442                 }
  443                 m_adj(m, ETHER_HDR_LEN);
  444                 type = htons(m->m_pkthdr.len);
  445                 cp = mtod(m, u_char *);
  446                 *cp++ = 0xE0;
  447                 *cp++ = 0xE0;
  448                 *cp++ = 0x03;
  449                 *hlen += 3;
  450                 break;
  451             case ETHER_FT_SNAP:
  452                 M_PREPEND(m, 8, M_TRYWAIT);
  453                 if (m == NULL) {
  454                         *mp = NULL;
  455                         return ENOBUFS;
  456                 }
  457                 type = htons(m->m_pkthdr.len);
  458                 cp = mtod(m, u_char *);
  459                 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
  460                 *hlen += 8;
  461                 break;
  462             default:
  463                 return EPFNOSUPPORT;
  464         }
  465         *mp = m;
  466         *tp = type;
  467         return 0;
  468 }
  469 
  470 /*
  471  * Create clone from the given interface
  472  */
  473 static int
  474 ef_clone(struct ef_link *efl, int ft)
  475 {
  476         struct efnet *efp;
  477         struct ifnet *eifp;
  478         struct ifnet *ifp = efl->el_ifp;
  479 
  480         efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
  481             M_WAITOK | M_ZERO);
  482         if (efp == NULL)
  483                 return ENOMEM;
  484         efp->ef_ifp = ifp;
  485         efp->ef_frametype = ft;
  486         eifp = &efp->ef_ac.ac_if;
  487         snprintf(eifp->if_xname, IFNAMSIZ,
  488             "%sf%d", ifp->if_xname, efp->ef_frametype);
  489         eifp->if_dname = "ef";
  490         eifp->if_dunit = IF_DUNIT_NONE;
  491         eifp->if_softc = efp;
  492         if (ifp->if_ioctl)
  493                 eifp->if_ioctl = ef_ioctl;
  494         efl->el_units[ft] = efp;
  495         return 0;
  496 }
  497 
  498 static int
  499 ef_load(void)
  500 {
  501         struct ifnet *ifp;
  502         struct efnet *efp;
  503         struct ef_link *efl = NULL;
  504         int error = 0, d;
  505 
  506         IFNET_RLOCK();
  507         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  508                 if (ifp->if_type != IFT_ETHER) continue;
  509                 EFDEBUG("Found interface %s\n", ifp->if_xname);
  510                 efl = (struct ef_link*)malloc(sizeof(struct ef_link), 
  511                     M_IFADDR, M_WAITOK | M_ZERO);
  512                 if (efl == NULL) {
  513                         error = ENOMEM;
  514                         break;
  515                 }
  516 
  517                 efl->el_ifp = ifp;
  518 #ifdef ETHER_II
  519                 error = ef_clone(efl, ETHER_FT_EII);
  520                 if (error) break;
  521 #endif
  522 #ifdef ETHER_8023
  523                 error = ef_clone(efl, ETHER_FT_8023);
  524                 if (error) break;
  525 #endif
  526 #ifdef ETHER_8022
  527                 error = ef_clone(efl, ETHER_FT_8022);
  528                 if (error) break;
  529 #endif
  530 #ifdef ETHER_SNAP
  531                 error = ef_clone(efl, ETHER_FT_SNAP);
  532                 if (error) break;
  533 #endif
  534                 efcount++;
  535                 SLIST_INSERT_HEAD(&efdev, efl, el_next);
  536         }
  537         IFNET_RUNLOCK();
  538         if (error) {
  539                 if (efl)
  540                         SLIST_INSERT_HEAD(&efdev, efl, el_next);
  541                 SLIST_FOREACH(efl, &efdev, el_next) {
  542                         for (d = 0; d < EF_NFT; d++)
  543                                 if (efl->el_units[d])
  544                                         free(efl->el_units[d], M_IFADDR);
  545                         free(efl, M_IFADDR);
  546                 }
  547                 return error;
  548         }
  549         SLIST_FOREACH(efl, &efdev, el_next) {
  550                 for (d = 0; d < EF_NFT; d++) {
  551                         efp = efl->el_units[d];
  552                         if (efp)
  553                                 ef_attach(efp);
  554                 }
  555         }
  556         ef_inputp = ef_input;
  557         ef_outputp = ef_output;
  558         EFDEBUG("Loaded\n");
  559         return 0;
  560 }
  561 
  562 static int
  563 ef_unload(void)
  564 {
  565         struct efnet *efp;
  566         struct ef_link *efl;
  567         int d;
  568 
  569         ef_inputp = NULL;
  570         ef_outputp = NULL;
  571         SLIST_FOREACH(efl, &efdev, el_next) {
  572                 for (d = 0; d < EF_NFT; d++) {
  573                         efp = efl->el_units[d];
  574                         if (efp) {
  575                                 ef_detach(efp);
  576                         }
  577                 }
  578         }
  579         EFDEBUG("Unloaded\n");
  580         return 0;
  581 }
  582 
  583 static int 
  584 if_ef_modevent(module_t mod, int type, void *data)
  585 {
  586         switch ((modeventtype_t)type) {
  587             case MOD_LOAD:
  588                 return ef_load();
  589             case MOD_UNLOAD:
  590                 return ef_unload();
  591             default:
  592                 break;
  593         }
  594         return 0;
  595 }
  596 
  597 static moduledata_t if_ef_mod = {
  598         "if_ef", if_ef_modevent, NULL
  599 };
  600 
  601 DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);

Cache object: feb2d76cbfc45f40c83e11c5b0d33669


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.