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_ecosubr.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: if_ecosubr.c,v 1.28 2008/03/12 18:22:24 dyoung Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2001 Ben Harris
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 /*
   30  * Copyright (c) 1982, 1989, 1993
   31  *      The Regents of the University of California.  All rights reserved.
   32  *
   33  * Redistribution and use in source and binary forms, with or without
   34  * modification, are permitted provided that the following conditions
   35  * are met:
   36  * 1. Redistributions of source code must retain the above copyright
   37  *    notice, this list of conditions and the following disclaimer.
   38  * 2. Redistributions in binary form must reproduce the above copyright
   39  *    notice, this list of conditions and the following disclaimer in the
   40  *    documentation and/or other materials provided with the distribution.
   41  * 3. Neither the name of the University nor the names of its contributors
   42  *    may be used to endorse or promote products derived from this software
   43  *    without specific prior written permission.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  *
   57  *      @(#)if_ethersubr.c      8.2 (Berkeley) 4/4/96
   58  */
   59 
   60 #include <sys/cdefs.h>
   61 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.28 2008/03/12 18:22:24 dyoung Exp $");
   62 
   63 #include "bpfilter.h"
   64 #include "opt_inet.h"
   65 #include "opt_pfil_hooks.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/errno.h>
   69 #include <sys/kernel.h>
   70 #include <sys/socket.h>
   71 #include <sys/sockio.h>
   72 #include <sys/syslog.h>
   73 #include <sys/systm.h>
   74 
   75 #include <net/if.h>
   76 #include <net/if_dl.h>
   77 #include <net/if_eco.h>
   78 #include <net/if_types.h>
   79 #include <net/netisr.h>
   80 #include <net/route.h>
   81 
   82 #if NBPFILTER > 0
   83 #include <net/bpf.h>
   84 #endif
   85 
   86 #ifdef INET
   87 #include <net/ethertypes.h>
   88 #include <net/if_arp.h>
   89 #include <netinet/in.h>
   90 #include <netinet/in_var.h>
   91 #endif
   92 
   93 struct eco_retryparms {
   94         int     erp_delay;
   95         int     erp_count;
   96 };
   97 
   98 /* Default broadcast address */
   99 static const uint8_t eco_broadcastaddr[] = { 0xff, 0xff };
  100 
  101 static int eco_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  102     struct rtentry *);
  103 static void eco_input(struct ifnet *, struct mbuf *);
  104 static void eco_start(struct ifnet *);
  105 static int eco_ioctl(struct ifnet *, u_long, void *);
  106 
  107 static int eco_interestingp(struct ifnet *ifp, struct mbuf *m);
  108 static struct mbuf *eco_immediate(struct ifnet *ifp, struct mbuf *m);
  109 static struct mbuf *eco_ack(struct ifnet *ifp, struct mbuf *m);
  110 
  111 static void eco_defer(struct ifnet *, struct mbuf *, int);
  112 static void eco_retry_free(struct eco_retry *er);
  113 static void eco_retry(void *);
  114 
  115 void
  116 eco_ifattach(struct ifnet *ifp, const uint8_t *lla)
  117 {
  118         struct ecocom *ec = (void *)ifp;
  119 
  120         ifp->if_type = IFT_ECONET;
  121         ifp->if_addrlen = ECO_ADDR_LEN;
  122         ifp->if_hdrlen = ECO_HDR_LEN;
  123         ifp->if_dlt = DLT_ECONET;
  124         ifp->if_mtu = ECO_MTU;
  125 
  126         ifp->if_output   = eco_output;
  127         ifp->if_input    = eco_input;
  128         ifp->if_start    = eco_start;
  129         ifp->if_ioctl    = eco_ioctl;
  130 
  131 /*      ifp->if_baudrate...; */
  132         if_alloc_sadl(ifp);
  133         (void)sockaddr_dl_setaddr(ifp->if_sadl, ifp->if_sadl->sdl_len, lla,
  134             ifp->if_addrlen);
  135 
  136         ifp->if_broadcastaddr = eco_broadcastaddr;
  137 
  138         LIST_INIT(&ec->ec_retries);
  139 
  140 #if NBPFILTER > 0
  141         bpfattach(ifp, ifp->if_dlt, ECO_HDR_LEN);
  142 #endif
  143 }
  144 
  145 #define senderr(e) do {                                                 \
  146         error = (e);                                                    \
  147         goto bad;                                                       \
  148 } while (/*CONSTCOND*/0)
  149 
  150 int
  151 eco_init(struct ifnet *ifp) {
  152         struct ecocom *ec = (struct ecocom *)ifp;
  153 
  154         if ((ifp->if_flags & IFF_RUNNING) == 0)
  155                 ec->ec_state = ECO_UNKNOWN;
  156         return 0;
  157 }
  158 
  159 void
  160 eco_stop(struct ifnet *ifp, int disable)
  161 {
  162         struct ecocom *ec = (struct ecocom *)ifp;
  163 
  164         while (!LIST_EMPTY(&ec->ec_retries))
  165                 eco_retry_free(LIST_FIRST(&ec->ec_retries));
  166 }
  167 
  168 static int
  169 eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
  170     struct rtentry *rt0)
  171 {
  172         struct eco_header ehdr, *eh;
  173         int error;
  174         struct mbuf *m = m0, *mcopy = NULL;
  175         struct rtentry *rt;
  176         int hdrcmplt;
  177         int retry_delay, retry_count;
  178         struct m_tag *mtag;
  179         struct eco_retryparms *erp;
  180 #ifdef INET
  181         struct mbuf *m1;
  182         struct arphdr *ah;
  183         struct eco_arp *ecah;
  184 #endif
  185         ALTQ_DECL(struct altq_pktattr pktattr;)
  186 
  187         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  188                 senderr(ENETDOWN);
  189         if ((rt = rt0) != NULL) {
  190                 if ((rt->rt_flags & RTF_UP) == 0) {
  191                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
  192                                 rt->rt_refcnt--;
  193                                 if (rt->rt_ifp != ifp)
  194                                         return (*rt->rt_ifp->if_output)
  195                                                         (ifp, m0, dst, rt);
  196                         } else
  197                                 senderr(EHOSTUNREACH);
  198                 }
  199                 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
  200                         if (rt->rt_gwroute == 0)
  201                                 goto lookup;
  202                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  203                                 rtfree(rt); rt = rt0;
  204                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
  205                                 if ((rt = rt->rt_gwroute) == 0)
  206                                         senderr(EHOSTUNREACH);
  207                                 /* the "G" test below also prevents rt == rt0 */
  208                                 if ((rt->rt_flags & RTF_GATEWAY) ||
  209                                     (rt->rt_ifp != ifp)) {
  210                                         rt->rt_refcnt--;
  211                                         rt0->rt_gwroute = 0;
  212                                         senderr(EHOSTUNREACH);
  213                                 }
  214                         }
  215                 }
  216                 if (rt->rt_flags & RTF_REJECT)
  217                         if (rt->rt_rmx.rmx_expire == 0 ||
  218                             time_second < rt->rt_rmx.rmx_expire)
  219                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  220         }
  221         /*
  222          * If the queueing discipline needs packet classification,
  223          * do it before prepending link headers.
  224          */
  225         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  226 
  227         hdrcmplt = 0;
  228         retry_delay = hz / 16;
  229         retry_count = 16;
  230         switch (dst->sa_family) {
  231 #ifdef INET
  232         case AF_INET:
  233                 if (m->m_flags & M_BCAST)
  234                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  235                             ECO_ADDR_LEN);
  236 
  237                 else if (!arpresolve(ifp, rt, m, dst, ehdr.eco_dhost))
  238                         return (0);     /* if not yet resolved */
  239                 /* If broadcasting on a simplex interface, loopback a copy */
  240                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
  241                         mcopy = m_copy(m, 0, (int)M_COPYALL);
  242                 ehdr.eco_port = ECO_PORT_IP;
  243                 ehdr.eco_control = ECO_CTL_IP;
  244                 break;
  245 
  246         case AF_ARP:
  247                 ah = mtod(m, struct arphdr *);
  248 
  249                 if (ntohs(ah->ar_pro) != ETHERTYPE_IP)
  250                         return EAFNOSUPPORT;
  251                 ehdr.eco_port = ECO_PORT_IP;
  252                 switch (ntohs(ah->ar_op)) {
  253                 case ARPOP_REQUEST:
  254                         ehdr.eco_control = ECO_CTL_ARP_REQUEST;
  255                         break;
  256                 case ARPOP_REPLY:
  257                         ehdr.eco_control = ECO_CTL_ARP_REPLY;
  258                         break;
  259                 default:
  260                         return EOPNOTSUPP;
  261                 }
  262 
  263                 if (m->m_flags & M_BCAST)
  264                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  265                             ECO_ADDR_LEN);
  266                 else
  267                         memcpy(ehdr.eco_dhost, ar_tha(ah), ECO_ADDR_LEN);
  268 
  269                 MGETHDR(m1, M_DONTWAIT, MT_DATA);
  270                 if (m1 == NULL)
  271                         senderr(ENOBUFS);
  272                 M_MOVE_PKTHDR(m1, m);
  273                 m1->m_len = sizeof(*ecah);
  274                 m1->m_pkthdr.len = m1->m_len;
  275                 MH_ALIGN(m1, m1->m_len);
  276                 ecah = mtod(m1, struct eco_arp *);
  277                 memset(ecah, 0, m1->m_len);
  278                 memcpy(ecah->ecar_spa, ar_spa(ah), ah->ar_pln);
  279                 memcpy(ecah->ecar_tpa, ar_tpa(ah), ah->ar_pln);
  280                 m_freem(m);
  281                 m = m1;
  282                 break;
  283 #endif
  284         case pseudo_AF_HDRCMPLT:
  285                 hdrcmplt = 1;
  286                 /* FALLTHROUGH */
  287         case AF_UNSPEC:
  288                 eh = (struct eco_header *)dst->sa_data;
  289                 ehdr = *eh;
  290                 break;
  291         default:
  292                 log(LOG_ERR, "%s: can't handle af%d\n", ifp->if_xname,
  293                     dst->sa_family);
  294                 senderr(EAFNOSUPPORT);
  295         }
  296 
  297         if (mcopy)
  298                 (void) looutput(ifp, mcopy, dst, rt);
  299 
  300         /*
  301          * Add local net header.  If no space in first mbuf,
  302          * allocate another.
  303          */
  304         M_PREPEND(m, sizeof (struct eco_header), M_DONTWAIT);
  305         if (m == 0)
  306                 senderr(ENOBUFS);
  307         eh = mtod(m, struct eco_header *);
  308         *eh = ehdr;
  309         if (!hdrcmplt)
  310                 memcpy(eh->eco_shost, CLLADDR(ifp->if_sadl),
  311                     ECO_ADDR_LEN);
  312 
  313         if ((m->m_flags & M_BCAST) == 0) {
  314                 /* Attach retry info to packet. */
  315                 mtag = m_tag_get(PACKET_TAG_ECO_RETRYPARMS,
  316                     sizeof(struct eco_retryparms), M_NOWAIT);
  317                 if (mtag == NULL)
  318                         senderr(ENOBUFS);
  319                 erp = (struct eco_retryparms *)(mtag + 1);
  320                 erp->erp_delay = retry_delay;
  321                 erp->erp_count = retry_count;
  322         }
  323 
  324 #ifdef PFIL_HOOKS
  325         if ((error = pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
  326                 return (error);
  327         if (m == NULL)
  328                 return (0);
  329 #endif
  330 
  331         return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr));
  332 
  333 bad:
  334         if (m)
  335                 m_freem(m);
  336         return error;
  337 }
  338 
  339 /*
  340  * Given a scout, decide if we want the rest of the packet.
  341  */
  342 static int
  343 eco_interestingp(struct ifnet *ifp, struct mbuf *m)
  344 {
  345         struct eco_header *eh;
  346 
  347         eh = mtod(m, struct eco_header *);
  348         switch (eh->eco_port) {
  349 #ifdef INET
  350         case ECO_PORT_IP:
  351                 return 1;
  352 #endif
  353         }
  354         return 0;
  355 }
  356 
  357 static void
  358 eco_input(struct ifnet *ifp, struct mbuf *m)
  359 {
  360         struct ifqueue *inq;
  361         struct eco_header ehdr, *eh;
  362         int s, i;
  363 #ifdef INET
  364         struct arphdr *ah;
  365         struct eco_arp *ecah;
  366         struct mbuf *m1;
  367 #endif
  368 
  369 #ifdef PFIL_HOOKS
  370         if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
  371                 return;
  372         if (m == NULL)
  373                 return;
  374 #endif
  375 
  376         /* Copy the mbuf header and trim it off. */
  377         /* XXX use m_split? */
  378         eh = &ehdr;
  379         m_copydata(m, 0, ECO_HDR_LEN, (void *)eh);
  380         m_adj(m, ECO_HDR_LEN);
  381 
  382         switch (eh->eco_port) {
  383 #ifdef INET
  384         case ECO_PORT_IP:
  385                 switch (eh->eco_control) {
  386                 case ECO_CTL_IP:
  387                         schednetisr(NETISR_IP);
  388                         inq = &ipintrq;
  389                         break;
  390                 case ECO_CTL_ARP_REQUEST:
  391                 case ECO_CTL_ARP_REPLY:
  392                         /*
  393                          * ARP over Econet is strange, because Econet only
  394                          * supports 8 bytes of data in a broadcast packet.
  395                          * To cope with this, only the source and destination
  396                          * IP addresses are actually contained in the packet
  397                          * and we have to infer the rest and build a fake ARP
  398                          * packet to pass upwards.
  399                          */
  400                         if (m->m_pkthdr.len != sizeof(struct eco_arp))
  401                                 goto drop;
  402                         if (m->m_len < sizeof(struct eco_arp)) {
  403                                 m = m_pullup(m, sizeof(struct eco_arp));
  404                                 if (m == NULL) goto drop;
  405                         }
  406                         ecah = mtod(m, struct eco_arp *);
  407                         /* This code derived from arprequest() */
  408                         MGETHDR(m1, M_DONTWAIT, MT_DATA);
  409                         if (m1 == NULL)
  410                                 goto drop;
  411                         M_MOVE_PKTHDR(m1, m);
  412                         m1->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
  413                             2*ifp->if_data.ifi_addrlen;
  414                         m1->m_pkthdr.len = m1->m_len;
  415                         MH_ALIGN(m1, m1->m_len);
  416                         ah = mtod(m1, struct arphdr *);
  417                         bzero((void *)ah, m1->m_len);
  418                         ah->ar_pro = htons(ETHERTYPE_IP);
  419                         ah->ar_hln = ifp->if_data.ifi_addrlen;
  420                         ah->ar_pln = sizeof(struct in_addr);
  421                         if (eh->eco_control == ECO_CTL_ARP_REQUEST)
  422                                 ah->ar_op = htons(ARPOP_REQUEST);
  423                         else
  424                                 ah->ar_op = htons(ARPOP_REPLY);
  425                         memcpy(ar_sha(ah), eh->eco_shost, ah->ar_hln);
  426                         memcpy(ar_tha(ah), eh->eco_dhost, ah->ar_hln);
  427                         memcpy(ar_spa(ah), ecah->ecar_spa, ah->ar_pln);
  428                         memcpy(ar_tpa(ah), ecah->ecar_tpa, ah->ar_pln);
  429                         m_freem(m);
  430                         m = m1;
  431                         schednetisr(NETISR_ARP);
  432                         inq = &arpintrq;
  433                         break;
  434                 case ECO_CTL_IPBCAST_REQUEST:
  435                 {
  436                         struct sockaddr_storage dst_store;
  437                         struct sockaddr *dst = (struct sockaddr *)&dst_store;
  438 
  439                         /* Queue? */
  440                         memcpy(eh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  441                         eh->eco_control = ECO_CTL_IPBCAST_REPLY;
  442                         /* dst->sa_len??? */
  443                         dst->sa_family = AF_UNSPEC;
  444                         memcpy(dst->sa_data, eh, ECO_HDR_LEN);
  445                         ifp->if_output(ifp, m, dst, NULL);
  446                         return;
  447                 }
  448                 default:
  449                         printf("%s: unknown IP stn %s ctl 0x%02x len %d:",
  450                             ifp->if_xname, eco_sprintf(eh->eco_shost),
  451                             eh->eco_control, m->m_pkthdr.len);
  452                         if (m->m_len == 0) {
  453                                 m = m_pullup(m, 1);
  454                                 if (m == 0) {
  455                                         printf("\n");
  456                                         goto drop;
  457                                 }
  458                         }
  459                         for (i = 0; i < m->m_len; i++)
  460                                 printf(" %02x", mtod(m, uint8_t *)[i]);
  461                         printf("\n");
  462                         goto drop;
  463                 }
  464                 break;
  465 #endif
  466         default:
  467                 printf("%s: unknown port stn %s port 0x%02x ctl 0x%02x\n",
  468                     ifp->if_xname, eco_sprintf(eh->eco_shost),
  469                     eh->eco_port, eh->eco_control);
  470         drop:
  471                 m_freem(m);
  472                 return;
  473         }
  474 
  475         s = splnet();
  476         if (IF_QFULL(inq)) {
  477                 IF_DROP(inq);
  478                 m_freem(m);
  479         } else
  480                 IF_ENQUEUE(inq, m);
  481         splx(s);
  482 }
  483 
  484 static void
  485 eco_start(struct ifnet *ifp)
  486 {
  487         struct ecocom *ec = (void *)ifp;
  488         struct mbuf *m;
  489         struct eco_header *eh;
  490 
  491         if (ec->ec_state != ECO_IDLE) return;
  492         IFQ_DEQUEUE(&ifp->if_snd, m);
  493         if (m == NULL) return;
  494         if (ec->ec_claimwire(ifp) == 0) {
  495                 eh = mtod(m, struct eco_header *);
  496                 if (eh->eco_port == ECO_PORT_IMMEDIATE) {
  497                         ec->ec_txframe(ifp, m);
  498                         ec->ec_state = ECO_IMMED_SENT;
  499                 } else if (eh->eco_dhost[0] == 255) {
  500                         ec->ec_txframe(ifp, m);
  501                         ec->ec_state = ECO_DONE;
  502                 } else {
  503                         ec->ec_packet = m;
  504                         m = m_copym(m, 0, ECO_HDR_LEN, M_DONTWAIT);
  505                         if (m == NULL) {
  506                                 m_freem(ec->ec_packet);
  507                                 ec->ec_packet = NULL;
  508                                 return;
  509                         }
  510                         ec->ec_txframe(ifp, m);
  511                         ec->ec_state = ECO_SCOUT_SENT;
  512                 }
  513                 ifp->if_flags |= IFF_OACTIVE;
  514         } else {
  515                 log(LOG_ERR, "%s: line jammed\n", ifp->if_xname);
  516                 m_freem(m);
  517         }
  518 }
  519 
  520 static int
  521 eco_ioctl(struct ifnet *ifp, u_long cmd, void *data)
  522 {
  523         struct ifreq *ifr = (struct ifreq *)data;
  524         struct ifaddr *ifa = (struct ifaddr *)data;
  525         int error;
  526 
  527         switch (cmd) {
  528         case SIOCSIFADDR:
  529                 ifp->if_flags |= IFF_UP;
  530                 switch (ifa->ifa_addr->sa_family) {
  531 #ifdef INET
  532                 case AF_INET:
  533                         if ((ifp->if_flags & IFF_RUNNING) == 0 &&
  534                             (error = (*ifp->if_init)(ifp)) != 0)
  535                                 return error;
  536                         arp_ifinit(ifp, ifa);
  537                         break;
  538 #endif
  539                 default:
  540                         if ((ifp->if_flags & IFF_RUNNING) == 0)
  541                                 return (*ifp->if_init)(ifp);
  542                         break;
  543                 }
  544                 return 0;
  545         case SIOCSIFMTU:
  546                 if ((error = ifioctl_common(ifp, command, data)) != ENETRESET)
  547                         return error;
  548                 else if (ifp->if_flags & IFF_UP)
  549                         return (*ifp->if_init)(ifp);
  550                 else
  551                         return 0;
  552                 break;
  553         case SIOCSIFFLAGS:
  554                 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
  555                 case IFF_RUNNING:
  556                         /*
  557                          * If interface is marked down and it is running,
  558                          * then stop and disable it.
  559                          */
  560                         (*ifp->if_stop)(ifp, 1);
  561                         return 0;
  562                 case IFF_UP:
  563                         /*
  564                          * If interface is marked up and it is stopped, then
  565                          * start it.
  566                          */
  567                         return (*ifp->if_init)(ifp);
  568                 case IFF_UP|IFF_RUNNING:
  569                         /*
  570                          * Reset the interface to pick up changes in any other
  571                          * flags that affect the hardware state.
  572                          */
  573                         return (*ifp->if_init)(ifp);
  574                 case 0:
  575                         return 0;
  576                 }
  577                 break;
  578         default:
  579                 return ENOTTY;
  580         }
  581 
  582         return 0;
  583 }
  584 
  585 /*
  586  * Handle a raw Econet frame off the interface.  The interface may be
  587  * flag-filling for a response.
  588  *
  589  * May be called from IPL_NET or IPL_SOFTNET.
  590  */
  591 
  592 struct mbuf *
  593 eco_inputframe(struct ifnet *ifp, struct mbuf *m)
  594 {
  595         struct ecocom *ec = (void *)ifp;
  596         struct eco_header *eh, *eh0;
  597         struct mbuf *m0;
  598         struct mbuf *reply;
  599         int len;
  600 
  601         eh = mtod(m, struct eco_header *);
  602         switch (ec->ec_state) {
  603         case ECO_IDLE: /* Start of a packet (bcast, immed, scout) */
  604                 if (m->m_pkthdr.len < ECO_HDR_LEN) {
  605                         log(LOG_NOTICE, "%s: undersize scout\n",
  606                             ifp->if_xname);
  607                         goto drop;
  608                 }
  609                 if (memcmp(eh->eco_dhost, eco_broadcastaddr,
  610                     ECO_ADDR_LEN) == 0) {
  611                         /* Broadcast */
  612                         eco_input(ifp, m);
  613                 } else if (memcmp(eh->eco_dhost, CLLADDR(ifp->if_sadl),
  614                     ECO_ADDR_LEN) == 0) {
  615                         /* Unicast for us */
  616                         if (eh->eco_port == ECO_PORT_IMMEDIATE)
  617                                 return eco_immediate(ifp, m);
  618                         else {
  619                                 if (eco_interestingp(ifp, m)) {
  620                                         reply = eco_ack(ifp, m);
  621                                         if (reply == NULL) {
  622                                                 m_freem(m);
  623                                                 return NULL;
  624                                         }
  625                                         ec->ec_state = ECO_SCOUT_RCVD;
  626                                         ec->ec_scout = m;
  627                                         return reply;
  628                                 } else {
  629                                         m_freem(m);
  630                                         return NULL;
  631                                 }
  632                         }
  633                 } else
  634                         /* Not for us.  Throw it away. */
  635                         m_freem(m);
  636                 break;
  637         case ECO_SCOUT_RCVD: /* Packet data */
  638                 KASSERT(ec->ec_scout != NULL);
  639                 m0 = ec->ec_scout;
  640                 eh0 = mtod(m0, struct eco_header *);
  641                 if (m->m_pkthdr.len < ECO_SHDR_LEN ||
  642                     memcmp(eh->eco_shost, eh0->eco_shost, ECO_ADDR_LEN) != 0 ||
  643                     memcmp(eh->eco_dhost, eh0->eco_dhost, ECO_ADDR_LEN) != 0) {
  644                         log(LOG_NOTICE, "%s: garbled data packet header\n",
  645                             ifp->if_xname);
  646                         goto drop;
  647                 }
  648                 reply = eco_ack(ifp, m);
  649                 /*
  650                  * Chop off the small header from this frame, and put
  651                  * the scout (which holds the control byte and port)
  652                  * in its place.
  653                  */
  654                 ec->ec_scout = NULL;
  655                 m_adj(m, ECO_SHDR_LEN);
  656                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  657                 m_cat(m0, m);
  658                 m0->m_pkthdr.len = len;
  659                 ec->ec_state = ECO_DONE;
  660                 eco_input(ifp, m0);
  661                 return reply;
  662         case ECO_SCOUT_SENT: /* Scout ack */
  663                 KASSERT(ec->ec_packet != NULL);
  664                 m0 = ec->ec_packet;
  665                 eh0 = mtod(m0, struct eco_header *);
  666                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  667                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  668                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  669                         log(LOG_NOTICE, "%s: garbled scout ack\n",
  670                             ifp->if_xname);
  671                         goto drop;
  672                 }
  673                 m_freem(m);
  674                 /* Chop out the control and port bytes. */
  675                 m0 = m_copym(ec->ec_packet, 0, ECO_SHDR_LEN, M_DONTWAIT);
  676                 if (m0 == NULL) {
  677                         m_freem(ec->ec_packet);
  678                         return NULL;
  679                 }
  680                 m = ec->ec_packet;
  681                 ec->ec_packet = m_copypacket(m, M_DONTWAIT);
  682                 if (ec->ec_packet == NULL) {
  683                         m_freem(m0);
  684                         m_freem(m);
  685                         return NULL;
  686                 }
  687                 m_adj(m, ECO_HDR_LEN);
  688                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  689                 m_cat(m0, m); /* Doesn't update packet header */
  690                 m0->m_pkthdr.len = len;
  691                 ec->ec_state = ECO_DATA_SENT;
  692                 return m0;
  693         case ECO_DATA_SENT: /* Data ack */
  694                 KASSERT(ec->ec_packet != NULL);
  695                 m0 = ec->ec_packet;
  696                 eh0 = mtod(m0, struct eco_header *);
  697                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  698                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  699                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  700                         log(LOG_NOTICE, "%s: garbled data ack\n",
  701                             ifp->if_xname);
  702                         goto drop;
  703                 }
  704                 m_freem(m);
  705                 m_freem(ec->ec_packet);
  706                 ec->ec_packet = NULL;
  707                 ec->ec_state = ECO_DONE;
  708                 return NULL;
  709         default:
  710         drop:
  711                 m_freem(m);
  712                 break;
  713         }
  714         return NULL;
  715 }
  716 
  717 /*
  718  * Handle an immediate operation, and return the reply, or NULL not to reply.
  719  * Frees the incoming mbuf.
  720  */
  721 
  722 static struct mbuf *
  723 eco_immediate(struct ifnet *ifp, struct mbuf *m)
  724 {
  725         struct eco_header *eh, *reh;
  726         struct mbuf *n;
  727         static const uint8_t machinepeek_data[] = { 42, 0, 0, 1 };
  728 
  729         eh = mtod(m, struct eco_header *);
  730         switch (eh->eco_control) {
  731         case ECO_CTL_MACHINEPEEK:
  732                 MGETHDR(n, M_DONTWAIT, MT_DATA);
  733                 if (n == NULL)
  734                         goto bad;
  735                 n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN + 4;
  736                 reh = mtod(n, struct eco_header *);
  737                 memcpy(reh->eco_dhost, eh->eco_shost,
  738                     ECO_ADDR_LEN);
  739                 memcpy(reh->eco_shost, CLLADDR(ifp->if_sadl),
  740                     ECO_ADDR_LEN);
  741                 memcpy(mtod(n, void *) + ECO_SHDR_LEN, machinepeek_data,
  742                     sizeof(machinepeek_data));
  743                 m_freem(m);
  744                 return n;
  745         default:
  746         bad:
  747                 m_freem(m);
  748                 return NULL;
  749         }
  750 }
  751 
  752 /*
  753  * Generate (and return) an acknowledgement for a frame.  Doesn't free the
  754  * original frame, since it's probably needed elsewhere.
  755  */
  756 static struct mbuf *
  757 eco_ack(struct ifnet *ifp, struct mbuf *m)
  758 {
  759         struct eco_header *eh, *reh;
  760         struct mbuf *n;
  761 
  762         eh = mtod(m, struct eco_header *);
  763         MGETHDR(n, M_DONTWAIT, MT_DATA);
  764         if (n == NULL)
  765                 return NULL;
  766         n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN;
  767         reh = mtod(n, struct eco_header *);
  768         memcpy(reh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  769         memcpy(reh->eco_shost, CLLADDR(ifp->if_sadl), ECO_ADDR_LEN);
  770         return n;
  771 }
  772 
  773 void
  774 eco_inputidle(struct ifnet *ifp)
  775 {
  776         struct ecocom *ec = (void *)ifp;
  777         struct mbuf *m;
  778         struct m_tag *mtag;
  779         struct eco_retryparms *erp;
  780 
  781         switch (ec->ec_state) {
  782         case ECO_SCOUT_SENT:
  783         case ECO_DATA_SENT:
  784         case ECO_IMMED_SENT:
  785                 /* Outgoing packet failed.  Check if we should retry. */
  786                 m = ec->ec_packet;
  787                 ec->ec_packet = NULL;
  788                 mtag = m_tag_find(m, PACKET_TAG_ECO_RETRYPARMS, NULL);
  789                 if (mtag == NULL)
  790                         m_freem(m);
  791                 else {
  792                         erp = (struct eco_retryparms *)(mtag + 1);
  793                         if (--erp->erp_count > 0)
  794                                 eco_defer(ifp, m, erp->erp_delay);
  795                         else
  796                                 printf("%s: pkt failed\n", ifp->if_xname);
  797                 }
  798                 break;
  799         case ECO_SCOUT_RCVD:
  800                 m_freem(ec->ec_scout);
  801                 ec->ec_scout = NULL;
  802                 break;
  803         default:
  804                 break;
  805         }
  806         ec->ec_state = ECO_IDLE;
  807         ifp->if_start(ifp);
  808 }
  809 
  810 /*
  811  * Convert Econet address to printable (loggable) representation.
  812  */
  813 char *
  814 eco_sprintf(const uint8_t *ea)
  815 {
  816         static char buf[8];
  817 
  818         if (ea[1] == 0)
  819                 snprintf(buf, sizeof(buf), "%d", ea[0]);
  820         else
  821                 snprintf(buf, sizeof(buf), "%d.%d", ea[1], ea[0]);
  822         return buf;
  823 }
  824 
  825 /*
  826  * Econet retry handling.
  827  */
  828 static void
  829 eco_defer(struct ifnet *ifp, struct mbuf *m, int retry_delay)
  830 {
  831         struct ecocom *ec = (struct ecocom *)ifp;
  832         struct eco_retry *er;
  833         int s;
  834 
  835         MALLOC(er, struct eco_retry *, sizeof(*er), M_TEMP, M_NOWAIT);
  836         if (er == NULL) {
  837                 m_freem(m);
  838                 return;
  839         }
  840         callout_init(&er->er_callout, 0);
  841         er->er_packet = m;
  842         er->er_ifp = ifp;
  843         s = splnet();
  844         LIST_INSERT_HEAD(&ec->ec_retries, er, er_link);
  845         splx(s);
  846         callout_reset(&er->er_callout, retry_delay, eco_retry, er);
  847 }
  848 
  849 static void
  850 eco_retry_free(struct eco_retry *er)
  851 {
  852         int s;
  853 
  854         callout_stop(&er->er_callout);
  855         m_freem(er->er_packet);
  856         s = splnet();
  857         LIST_REMOVE(er, er_link);
  858         splx(s);
  859         callout_destroy(&er->er_callout);
  860         FREE(er, M_TEMP);
  861 }
  862 
  863 static void
  864 eco_retry(void *arg)
  865 {
  866         struct eco_retry *er = arg;
  867         struct mbuf *m;
  868         struct ifnet *ifp;
  869 
  870         ifp = er->er_ifp;
  871         m = er->er_packet;
  872         LIST_REMOVE(er, er_link);
  873         (void)ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(NULL));
  874         FREE(er, M_TEMP);
  875 }

Cache object: fa3153e0fff8473930be3c19c118260c


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