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/dev/ofw/ofnet.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 /*      $NetBSD: ofnet.c,v 1.31 2003/01/15 22:01:57 bouyer Exp $        */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
    5  * Copyright (C) 1995, 1996 TooLs GmbH.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by TooLs GmbH.
   19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: ofnet.c,v 1.31 2003/01/15 22:01:57 bouyer Exp $");
   36 
   37 #include "ofnet.h"
   38 #include "opt_inet.h"
   39 #include "bpfilter.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/callout.h>
   44 #include <sys/device.h>
   45 #include <sys/disk.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/mbuf.h>
   48 #include <sys/socket.h>
   49 #include <sys/syslog.h>
   50 
   51 #include <net/if.h>
   52 #include <net/if_ether.h>
   53 
   54 #ifdef INET
   55 #include <netinet/in.h>
   56 #include <netinet/if_inarp.h>
   57 #endif
   58 
   59 #if NBPFILTER > 0
   60 #include <net/bpf.h>
   61 #include <net/bpfdesc.h>
   62 #endif
   63 
   64 #include <dev/ofw/openfirm.h>
   65 
   66 #if NIPKDB_OFN > 0
   67 #include <ipkdb/ipkdb.h>
   68 #include <machine/ipkdb.h>
   69 
   70 CFATTACH_DECL(ipkdb_ofn, 0,
   71     ipkdb_probe, ipkdb_attach, NULL, NULL);
   72 
   73 static struct ipkdb_if *kifp;
   74 static struct ofnet_softc *ipkdb_of;
   75 
   76 static int ipkdbprobe (struct cfdata *, void *);
   77 #endif
   78 
   79 struct ofnet_softc {
   80         struct device sc_dev;
   81         int sc_phandle;
   82         int sc_ihandle;
   83         struct ethercom sc_ethercom;
   84         struct callout sc_callout;
   85 };
   86 
   87 static int ofnet_match (struct device *, struct cfdata *, void *);
   88 static void ofnet_attach (struct device *, struct device *, void *);
   89 
   90 CFATTACH_DECL(ofnet, sizeof(struct ofnet_softc),
   91     ofnet_match, ofnet_attach, NULL, NULL);
   92 
   93 static void ofnet_read (struct ofnet_softc *);
   94 static void ofnet_timer (void *);
   95 static void ofnet_init (struct ofnet_softc *);
   96 static void ofnet_stop (struct ofnet_softc *);
   97 
   98 static void ofnet_start (struct ifnet *);
   99 static int ofnet_ioctl (struct ifnet *, u_long, caddr_t);
  100 static void ofnet_watchdog (struct ifnet *);
  101 
  102 static int
  103 ofnet_match(struct device *parent, struct cfdata *match, void *aux)
  104 {
  105         struct ofbus_attach_args *oba = aux;
  106         char type[32];
  107         int l;
  108         
  109 #if NIPKDB_OFN > 0
  110         if (!parent)
  111                 return ipkdbprobe(match, aux);
  112 #endif
  113         if (strcmp(oba->oba_busname, "ofw"))
  114                 return (0);
  115         if ((l = OF_getprop(oba->oba_phandle, "device_type", type,
  116             sizeof type - 1)) < 0)
  117                 return 0;
  118         if (l >= sizeof type)
  119                 return 0;
  120         type[l] = 0;
  121         if (strcmp(type, "network"))
  122                 return 0;
  123         return 1;
  124 }
  125 
  126 static void
  127 ofnet_attach(struct device *parent, struct device *self, void *aux)
  128 {
  129         struct ofnet_softc *of = (void *)self;
  130         struct ifnet *ifp = &of->sc_ethercom.ec_if;
  131         struct ofbus_attach_args *oba = aux;
  132         char path[256];
  133         int l;
  134         u_int8_t myaddr[ETHER_ADDR_LEN];
  135         
  136         of->sc_phandle = oba->oba_phandle;
  137 #if NIPKDB_OFN > 0
  138         if (kifp &&
  139             kifp->unit - 1 == of->sc_dev.dv_unit &&
  140             OF_instance_to_package(kifp->port) == oba->oba_phandle)  {
  141                 ipkdb_of = of;
  142                 of->sc_ihandle = kifp->port;
  143         } else
  144 #endif
  145         if ((l = OF_package_to_path(oba->oba_phandle, path,
  146             sizeof path - 1)) < 0 ||
  147             l >= sizeof path ||
  148             (path[l] = 0, !(of->sc_ihandle = OF_open(path))))
  149                 panic("ofnet_attach: unable to open");
  150         if (OF_getprop(oba->oba_phandle, "mac-address", myaddr,
  151             sizeof myaddr) < 0)
  152                 panic("ofnet_attach: no mac-address");
  153         printf(": address %s\n", ether_sprintf(myaddr));
  154 
  155         callout_init(&of->sc_callout);
  156 
  157         bcopy(of->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  158         ifp->if_softc = of;
  159         ifp->if_start = ofnet_start;
  160         ifp->if_ioctl = ofnet_ioctl;
  161         ifp->if_watchdog = ofnet_watchdog;
  162         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  163         IFQ_SET_READY(&ifp->if_snd);
  164 
  165         if_attach(ifp);
  166         ether_ifattach(ifp, myaddr);
  167 }
  168 
  169 static char buf[ETHERMTU + sizeof(struct ether_header)];
  170 
  171 static void
  172 ofnet_read(struct ofnet_softc *of)
  173 {
  174         struct ifnet *ifp = &of->sc_ethercom.ec_if;
  175         struct mbuf *m, **mp, *head;
  176         int s, l, len;
  177         char *bufp;
  178 
  179         s = splnet();
  180 #if NIPKDB_OFN > 0
  181         ipkdbrint(kifp, ifp);
  182 #endif  
  183         for (;;) {
  184                 len = OF_read(of->sc_ihandle, buf, sizeof buf);
  185                 if (len == -2 || len == 0)
  186                         break;
  187                 if (len < sizeof(struct ether_header)) {
  188                         ifp->if_ierrors++;
  189                         continue;
  190                 }
  191                 bufp = buf;
  192 
  193                 /* Allocate a header mbuf */
  194                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  195                 if (m == 0) {
  196                         ifp->if_ierrors++;
  197                         continue;
  198                 }
  199                 m->m_pkthdr.rcvif = ifp;
  200                 m->m_pkthdr.len = len;
  201 
  202                 /*
  203                  * We don't know if the interface included the FCS
  204                  * or not.  For now, assume that it did if we got
  205                  * a packet length that looks like it could include
  206                  * the FCS.
  207                  *
  208                  * XXX Yuck.
  209                  */
  210 
  211                 if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN))
  212                         m->m_flags |= M_HASFCS;
  213 
  214                 l = MHLEN;
  215                 head = 0;
  216                 mp = &head;
  217                 
  218                 while (len > 0) {
  219                         if (head) {
  220                                 MGET(m, M_DONTWAIT, MT_DATA);
  221                                 if (m == 0) {
  222                                         ifp->if_ierrors++;
  223                                         m_freem(head);
  224                                         head = 0;
  225                                         break;
  226                                 }
  227                                 l = MLEN;
  228                         }
  229                         if (len >= MINCLSIZE) {
  230                                 MCLGET(m, M_DONTWAIT);
  231                                 if ((m->m_flags & M_EXT) == 0) {
  232                                         ifp->if_ierrors++;
  233                                         m_free(m);
  234                                         m_freem(head);
  235                                         head = 0;
  236                                         break;
  237                                 }
  238                                 l = MCLBYTES;
  239                         }
  240 
  241                         /*
  242                          * Make sure the data after the Ethernet header
  243                          * is aligned.
  244                          *
  245                          * XXX Assumes the device is an ethernet, but
  246                          * XXX then so does other code in this driver.
  247                          */
  248                         if (head == NULL) {
  249                                 caddr_t newdata = (caddr_t)ALIGN(m->m_data +
  250                                       sizeof(struct ether_header)) -
  251                                     sizeof(struct ether_header);
  252                                 l -= newdata - m->m_data;
  253                                 m->m_data = newdata;
  254                         }
  255 
  256                         m->m_len = l = min(len, l);
  257                         bcopy(bufp, mtod(m, char *), l);
  258                         bufp += l;
  259                         len -= l;
  260                         *mp = m;
  261                         mp = &m->m_next;
  262                 }
  263                 if (head == 0)
  264                         continue;
  265 
  266 #if NBPFILTER > 0
  267                 if (ifp->if_bpf)
  268                         bpf_mtap(ifp->if_bpf, m);
  269 #endif
  270                 ifp->if_ipackets++;
  271                 (*ifp->if_input)(ifp, head);
  272         }
  273         splx(s);
  274 }
  275 
  276 static void
  277 ofnet_timer(arg)
  278         void *arg;
  279 {
  280         struct ofnet_softc *of = arg;
  281 
  282         ofnet_read(of);
  283         callout_reset(&of->sc_callout, 1, ofnet_timer, of);
  284 }
  285 
  286 static void
  287 ofnet_init(struct ofnet_softc *of)
  288 {
  289         struct ifnet *ifp = &of->sc_ethercom.ec_if;
  290 
  291         if (ifp->if_flags & IFF_RUNNING)
  292                 return;
  293 
  294         ifp->if_flags |= IFF_RUNNING;
  295         /* Start reading from interface */
  296         ofnet_timer(of);
  297         /* Attempt to start output */
  298         ofnet_start(ifp);
  299 }
  300 
  301 static void
  302 ofnet_stop(struct ofnet_softc *of)
  303 {
  304         callout_stop(&of->sc_callout);
  305         of->sc_ethercom.ec_if.if_flags &= ~IFF_RUNNING;
  306 }
  307 
  308 static void
  309 ofnet_start(struct ifnet *ifp)
  310 {
  311         struct ofnet_softc *of = ifp->if_softc;
  312         struct mbuf *m, *m0;
  313         char *bufp;
  314         int len;
  315         
  316         if (!(ifp->if_flags & IFF_RUNNING))
  317                 return;
  318 
  319         for (;;) {
  320                 /* First try reading any packets */
  321                 ofnet_read(of);
  322                 
  323                 /* Now get the first packet on the queue */
  324                 IFQ_DEQUEUE(&ifp->if_snd, m0);
  325                 if (!m0)
  326                         return;
  327                 
  328                 if (!(m0->m_flags & M_PKTHDR))
  329                         panic("ofnet_start: no header mbuf");
  330                 len = m0->m_pkthdr.len;
  331 
  332 #if NBPFILTER > 0
  333                 if (ifp->if_bpf)
  334                         bpf_mtap(ifp->if_bpf, m0);
  335 #endif
  336 
  337                 if (len > ETHERMTU + sizeof(struct ether_header)) {
  338                         /* packet too large, toss it */
  339                         ifp->if_oerrors++;
  340                         m_freem(m0);
  341                         continue;
  342                 }
  343 
  344                 for (bufp = buf; (m = m0) != NULL;) {
  345                         bcopy(mtod(m, char *), bufp, m->m_len);
  346                         bufp += m->m_len;
  347                         MFREE(m, m0);
  348                 }
  349 
  350                 /*
  351                  * We don't know if the interface will auto-pad for
  352                  * us, so make sure it's at least as large as a
  353                  * minimum size Ethernet packet.
  354                  */
  355 
  356                 if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
  357                         memset(bufp, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - len);
  358                         bufp += ETHER_MIN_LEN - ETHER_CRC_LEN - len;
  359                 } else
  360                         len = bufp - buf;
  361 
  362                 if (OF_write(of->sc_ihandle, buf, len) != len)
  363                         ifp->if_oerrors++;
  364                 else
  365                         ifp->if_opackets++;
  366         }
  367 }
  368 
  369 static int
  370 ofnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  371 {
  372         struct ofnet_softc *of = ifp->if_softc;
  373         struct ifaddr *ifa = (struct ifaddr *)data;
  374         /* struct ifreq *ifr = (struct ifreq *)data; */
  375         int error = 0;
  376         
  377         switch (cmd) {
  378         case SIOCSIFADDR:
  379                 ifp->if_flags |= IFF_UP;
  380                 
  381                 switch (ifa->ifa_addr->sa_family) {
  382 #ifdef  INET
  383                 case AF_INET:
  384                         arp_ifinit(ifp, ifa);
  385                         break;
  386 #endif
  387                 default:
  388                         break;
  389                 }
  390                 ofnet_init(of);
  391                 break;
  392         case SIOCSIFFLAGS:
  393                 if ((ifp->if_flags & IFF_UP) == 0 &&
  394                     (ifp->if_flags & IFF_RUNNING) != 0) {
  395                         /* If interface is down, but running, stop it. */
  396                         ofnet_stop(of);
  397                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  398                            (ifp->if_flags & IFF_RUNNING) == 0) {
  399                         /* If interface is up, but not running, start it. */
  400                         ofnet_init(of);
  401                 } else {
  402                         /* Other flags are ignored. */
  403                 }
  404                 break;
  405         default:
  406                 error = EINVAL;
  407                 break;
  408         }
  409         return error;
  410 }
  411 
  412 static void
  413 ofnet_watchdog(struct ifnet *ifp)
  414 {
  415         struct ofnet_softc *of = ifp->if_softc;
  416         
  417         log(LOG_ERR, "%s: device timeout\n", of->sc_dev.dv_xname);
  418         ifp->if_oerrors++;
  419         ofnet_stop(of);
  420         ofnet_init(of);
  421 }
  422 
  423 #if NIPKDB_OFN > 0
  424 static void
  425 ipkdbofstart(struct ipkdb_if *kip)
  426 {
  427         int unit = kip->unit - 1;
  428         
  429         if (ipkdb_of)
  430                 ipkdbattach(kip, &ipkdb_of->sc_ethercom);
  431 }
  432 
  433 static void
  434 ipkdbofleave(struct ipkdb_if *kip)
  435 {
  436 }
  437 
  438 static int
  439 ipkdbofrcv(struct ipkdb_if *kip, u_char *buf, int poll)
  440 {
  441         int l;
  442         
  443         do {
  444                 l = OF_read(kip->port, buf, ETHERMTU);
  445                 if (l < 0)
  446                         l = 0;
  447         } while (!poll && !l);
  448         return l;
  449 }
  450 
  451 static void
  452 ipkdbofsend(struct ipkdb_if *kip, u_char *buf, int l)
  453 {
  454         OF_write(kip->port, buf, l);
  455 }
  456 
  457 static int
  458 ipkdbprobe(struct cfdata *match, void *aux)
  459 {
  460         struct ipkdb_if *kip = aux;
  461         static char name[256];
  462         int len;
  463         int phandle;
  464         
  465         kip->unit = match->cf_unit + 1;
  466 
  467         if (!(kip->port = OF_open("net")))
  468                 return -1;
  469         if ((len = OF_instance_to_path(kip->port, name, sizeof name - 1)) < 0 ||
  470             len >= sizeof name)
  471                 return -1;
  472         name[len] = 0;
  473         if ((phandle = OF_instance_to_package(kip->port)) == -1)
  474                 return -1;
  475         if (OF_getprop(phandle, "mac-address", kip->myenetaddr,
  476             sizeof kip->myenetaddr) < 0)
  477                 return -1;
  478         
  479         kip->flags |= IPKDB_MYHW;
  480         kip->name = name;
  481         kip->start = ipkdbofstart;
  482         kip->leave = ipkdbofleave;
  483         kip->receive = ipkdbofrcv;
  484         kip->send = ipkdbofsend;
  485 
  486         kifp = kip;
  487         
  488         return 0;
  489 }
  490 #endif

Cache object: c5535747a1fa41d5b8396d9e28db7565


[ 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.