root/dev/ic/pdq_ifsubr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pdq_ifinit
  2. pdq_ifwatchdog
  3. pdq_ifstart
  4. pdq_os_receive_pdu
  5. pdq_os_restart_transmitter
  6. pdq_os_transmit_done
  7. pdq_os_addr_fill
  8. pdq_ifioctl
  9. pdq_ifattach

    1 /*      $OpenBSD: pdq_ifsubr.c,v 1.19 2006/05/30 21:33:59 fkr Exp $     */
    2 /*      $NetBSD: pdq_ifsubr.c,v 1.5 1996/05/20 00:26:21 thorpej Exp $   */
    3 
    4 /*-
    5  * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
    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. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  * Id: pdq_ifsubr.c,v 1.6 1996/05/16 14:25:26 thomas Exp
   28  *
   29  */
   30 
   31 /*
   32  * DEC PDQ FDDI Controller; code for BSD derived operating systems
   33  *
   34  *      This module provide bus independent BSD specific O/S functions.
   35  *      (ie. it provides an ifnet interface to the rest of the system)
   36  */
   37 
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/protosw.h>
   43 #include <sys/socket.h>
   44 #include <sys/ioctl.h>
   45 #include <sys/errno.h>
   46 #include <sys/malloc.h>
   47 #if defined(__FreeBSD__)
   48 #include <sys/devconf.h>
   49 #elif defined(__NetBSD__) || defined(__OpenBSD__)
   50 #include <sys/device.h>
   51 #endif
   52 
   53 #include <net/if.h>
   54 #include <net/if_types.h>
   55 #include <net/if_dl.h>
   56 #include <net/route.h>
   57 
   58 #include "bpfilter.h"
   59 #if NBPFILTER > 0
   60 #include <net/bpf.h>
   61 #endif
   62 
   63 #ifdef INET
   64 #include <netinet/in.h>
   65 #include <netinet/in_systm.h>
   66 #include <netinet/in_var.h>
   67 #include <netinet/ip.h>
   68 #include <netinet/if_ether.h>
   69 #endif
   70 #if defined(__FreeBSD__)
   71 #include <netinet/if_fddi.h>
   72 #else
   73 #include <net/if_fddi.h>
   74 #endif
   75 
   76 #include <uvm/uvm_extern.h>
   77 
   78 #include "pdqvar.h"
   79 #include "pdqreg.h"
   80 
   81 void
   82 pdq_ifinit(
   83     pdq_softc_t *sc)
   84 {
   85     if (sc->sc_if.if_flags & IFF_UP) {
   86         sc->sc_if.if_flags |= IFF_RUNNING;
   87         if (sc->sc_if.if_flags & IFF_PROMISC) {
   88             sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
   89         } else {
   90             sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
   91         }
   92         if (sc->sc_if.if_flags & IFF_ALLMULTI) {
   93             sc->sc_pdq->pdq_flags |= PDQ_ALLMULTI;
   94         } else {
   95             sc->sc_pdq->pdq_flags &= ~PDQ_ALLMULTI;
   96         }
   97         if (sc->sc_if.if_flags & IFF_LINK1) {
   98             sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
   99         } else {
  100             sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
  101         }
  102         sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
  103         pdq_run(sc->sc_pdq);
  104     } else {
  105         sc->sc_if.if_flags &= ~IFF_RUNNING;
  106         sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
  107         pdq_stop(sc->sc_pdq);
  108     }
  109 }
  110 
  111 void
  112 pdq_ifwatchdog(
  113     struct ifnet *ifp)
  114 {
  115     /*
  116      * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
  117      * seconds.  Remove all queued packets.
  118      */
  119 
  120     ifp->if_flags &= ~IFF_OACTIVE;
  121     ifp->if_timer = 0;
  122     IFQ_PURGE(&ifp->if_snd);
  123 }
  124 
  125 ifnet_ret_t
  126 pdq_ifstart(
  127     struct ifnet *ifp)
  128 {
  129     pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_arpcom.ac_if));
  130     struct mbuf *m;
  131     int tx = 0;
  132 
  133     if ((ifp->if_flags & IFF_RUNNING) == 0)
  134         return;
  135 
  136     if (sc->sc_if.if_timer == 0)
  137         sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
  138 
  139     if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
  140         sc->sc_if.if_flags |= IFF_OACTIVE;
  141         return;
  142     }
  143     for (;; tx = 1) {
  144         IFQ_POLL(&ifp->if_snd, m);
  145         if (m == NULL)
  146             break;
  147 
  148         if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
  149             ifp->if_flags |= IFF_OACTIVE;
  150             break;
  151         }
  152 
  153         IFQ_DEQUEUE(&ifp->if_snd, m);
  154     }
  155     if (tx)
  156         PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
  157 }
  158 
  159 void
  160 pdq_os_receive_pdu(
  161     pdq_t *pdq,
  162     struct mbuf *m,
  163     size_t pktlen)
  164 {
  165     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
  166     struct fddi_header *fh = mtod(m, struct fddi_header *);
  167 
  168     sc->sc_if.if_ipackets++;
  169 #if NBPFILTER > 0
  170     if (sc->sc_bpf != NULL)
  171         PDQ_BPF_MTAP(sc, m, BPF_DIRECTION_IN);
  172     if ((fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
  173         m_freem(m);
  174         return;
  175     }
  176 #endif
  177 
  178     m->m_data += sizeof(struct fddi_header);
  179     m->m_len  -= sizeof(struct fddi_header);
  180     m->m_pkthdr.len = pktlen - sizeof(struct fddi_header);
  181     m->m_pkthdr.rcvif = &sc->sc_if;
  182     fddi_input(&sc->sc_if, fh, m);
  183 }
  184 
  185 void
  186 pdq_os_restart_transmitter(
  187     pdq_t *pdq)
  188 {
  189     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
  190     sc->sc_if.if_flags &= ~IFF_OACTIVE;
  191     if (!IFQ_IS_EMPTY(&sc->sc_if.if_snd)) {
  192         sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
  193         pdq_ifstart(&sc->sc_if);
  194     } else {
  195         sc->sc_if.if_timer = 0;
  196     }
  197 }
  198 
  199 void
  200 pdq_os_transmit_done(
  201     pdq_t *pdq,
  202     struct mbuf *m)
  203 {
  204     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
  205 #if NBPFILTER > 0
  206     if (sc->sc_bpf != NULL)
  207         PDQ_BPF_MTAP(sc, m, BPF_DIRECTION_OUT);
  208 #endif
  209     m_freem(m);
  210     sc->sc_if.if_opackets++;
  211 }
  212 
  213 void
  214 pdq_os_addr_fill(
  215     pdq_t *pdq,
  216     pdq_lanaddr_t *addr,
  217     size_t num_addrs)
  218 {
  219     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
  220     struct ether_multistep step;
  221     struct ether_multi *enm;
  222 
  223     ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
  224     while (enm != NULL && num_addrs > 0) {
  225         ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) enm->enm_addrlo)[0];
  226         ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) enm->enm_addrlo)[1];
  227         ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) enm->enm_addrlo)[2];
  228         ETHER_NEXT_MULTI(step, enm);
  229         addr++;
  230         num_addrs--;
  231     }
  232 }
  233 
  234 int
  235 pdq_ifioctl(
  236     struct ifnet *ifp,
  237     ioctl_cmd_t cmd,
  238     caddr_t data)
  239 {
  240     pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_arpcom.ac_if));
  241     int s, error = 0;
  242 
  243     s = splnet();
  244 
  245     switch (cmd) {
  246         case SIOCSIFADDR: {
  247             struct ifaddr *ifa = (struct ifaddr *)data;
  248 
  249             ifp->if_flags |= IFF_UP;
  250             switch(ifa->ifa_addr->sa_family) {
  251 #if defined(INET)
  252                 case AF_INET: {
  253                     pdq_ifinit(sc);
  254                     arp_ifinit(&sc->sc_arpcom, ifa);
  255                     break;
  256                 }
  257 #endif /* INET */
  258 
  259 #if defined(NS)
  260                 /* This magic copied from if_is.c; I don't use XNS,
  261                  * so I have no way of telling if this actually
  262                  * works or not.
  263                  */
  264                 case AF_NS: {
  265                     struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  266                     if (ns_nullhost(*ina)) {
  267                         ina->x_host = *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
  268                     } else {
  269                         ifp->if_flags &= ~IFF_RUNNING;
  270                         bcopy((caddr_t)ina->x_host.c_host,
  271                               (caddr_t)sc->sc_arpcom.ac_enaddr,
  272                               sizeof sc->sc_arpcom.ac_enaddr);
  273                     }
  274 
  275                     pdq_ifinit(sc);
  276                     break;
  277                 }
  278 #endif /* NS */
  279 
  280                 default: {
  281                     pdq_ifinit(sc);
  282                     break;
  283                 }
  284             }
  285             break;
  286         }
  287 
  288         case SIOCSIFFLAGS: {
  289             pdq_ifinit(sc);
  290             break;
  291         }
  292 
  293         case SIOCADDMULTI:
  294         case SIOCDELMULTI: {
  295             /*
  296              * Update multicast listeners
  297              */
  298             if (cmd == SIOCADDMULTI)
  299                 error = ether_addmulti((struct ifreq *)data, &sc->sc_arpcom);
  300             else
  301                 error = ether_delmulti((struct ifreq *)data, &sc->sc_arpcom);
  302 
  303             if (error == ENETRESET) {
  304                 if (sc->sc_if.if_flags & IFF_RUNNING)
  305                     pdq_run(sc->sc_pdq);
  306                 error = 0;
  307             }
  308             break;
  309         }
  310 
  311         default: {
  312             error = EINVAL;
  313             break;
  314         }
  315     }
  316 
  317     splx(s);
  318     return error;
  319 }
  320 
  321 #ifndef IFF_NOTRAILERS
  322 #define IFF_NOTRAILERS  0
  323 #endif
  324 
  325 void
  326 pdq_ifattach(
  327     pdq_softc_t *sc,
  328     ifnet_ret_t (*ifwatchdog)(int unit))
  329 {
  330     struct ifnet *ifp = &sc->sc_if;
  331 
  332     ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
  333 
  334 #if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__) || \
  335         defined(__OpenBSD__)
  336     ifp->if_watchdog = pdq_ifwatchdog;
  337 #else
  338     ifp->if_watchdog = ifwatchdog;
  339 #endif
  340 
  341     ifp->if_ioctl = pdq_ifioctl;
  342     ifp->if_start = pdq_ifstart;
  343     IFQ_SET_READY(&ifp->if_snd);
  344   
  345     if_attach(ifp);
  346     fddi_ifattach(ifp);
  347 #if NBPFILTER > 0
  348     PDQ_BPFATTACH(sc, DLT_FDDI, sizeof(struct fddi_header));
  349 #endif
  350 }

/* [<][>][^][v][top][bottom][index][help] */