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.21 2006/06/07 22:33:42 kardel 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.21 2006/06/07 22:33:42 kardel 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 u_int8_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, caddr_t);
  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 u_int8_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         memcpy(LLADDR(ifp->if_sadl), lla, ifp->if_addrlen);
  134 
  135         ifp->if_broadcastaddr = eco_broadcastaddr;
  136 
  137         LIST_INIT(&ec->ec_retries);
  138 
  139 #if NBPFILTER > 0
  140         bpfattach(ifp, ifp->if_dlt, ECO_HDR_LEN);
  141 #endif
  142 }
  143 
  144 #define senderr(e) do {                                                 \
  145         error = (e);                                                    \
  146         goto bad;                                                       \
  147 } while (/*CONSTCOND*/0)
  148 
  149 int
  150 eco_init(struct ifnet *ifp) {
  151         struct ecocom *ec = (struct ecocom *)ifp;
  152 
  153         if ((ifp->if_flags & IFF_RUNNING) == 0)
  154                 ec->ec_state = ECO_UNKNOWN;
  155         return 0;
  156 }
  157 
  158 void
  159 eco_stop(struct ifnet *ifp, int disable)
  160 {
  161         struct ecocom *ec = (struct ecocom *)ifp;
  162 
  163         while (!LIST_EMPTY(&ec->ec_retries))
  164                 eco_retry_free(LIST_FIRST(&ec->ec_retries));
  165 }
  166 
  167 static int
  168 eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
  169     struct rtentry *rt0)
  170 {
  171         struct eco_header ehdr, *eh;
  172         int error;
  173         struct mbuf *m = m0, *mcopy = NULL;
  174         struct rtentry *rt;
  175         int hdrcmplt;
  176         int retry_delay, retry_count;
  177         struct m_tag *mtag;
  178         struct eco_retryparms *erp;
  179 #ifdef INET
  180         struct mbuf *m1;
  181         struct arphdr *ah;
  182         struct eco_arp *ecah;
  183 #endif
  184         ALTQ_DECL(struct altq_pktattr pktattr;)
  185 
  186         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  187                 senderr(ENETDOWN);
  188         if ((rt = rt0) != NULL) {
  189                 if ((rt->rt_flags & RTF_UP) == 0) {
  190                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
  191                                 rt->rt_refcnt--;
  192                                 if (rt->rt_ifp != ifp)
  193                                         return (*rt->rt_ifp->if_output)
  194                                                         (ifp, m0, dst, rt);
  195                         } else
  196                                 senderr(EHOSTUNREACH);
  197                 }
  198                 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
  199                         if (rt->rt_gwroute == 0)
  200                                 goto lookup;
  201                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  202                                 rtfree(rt); rt = rt0;
  203                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
  204                                 if ((rt = rt->rt_gwroute) == 0)
  205                                         senderr(EHOSTUNREACH);
  206                                 /* the "G" test below also prevents rt == rt0 */
  207                                 if ((rt->rt_flags & RTF_GATEWAY) ||
  208                                     (rt->rt_ifp != ifp)) {
  209                                         rt->rt_refcnt--;
  210                                         rt0->rt_gwroute = 0;
  211                                         senderr(EHOSTUNREACH);
  212                                 }
  213                         }
  214                 }
  215                 if (rt->rt_flags & RTF_REJECT)
  216                         if (rt->rt_rmx.rmx_expire == 0 ||
  217                             time_second < rt->rt_rmx.rmx_expire)
  218                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  219         }
  220         /*
  221          * If the queueing discipline needs packet classification,
  222          * do it before prepending link headers.
  223          */
  224         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  225 
  226         hdrcmplt = 0;
  227         retry_delay = hz / 16;
  228         retry_count = 16;
  229         switch (dst->sa_family) {
  230 #ifdef INET
  231         case AF_INET:
  232                 if (m->m_flags & M_BCAST)
  233                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  234                             ECO_ADDR_LEN);
  235 
  236                 else if (!arpresolve(ifp, rt, m, dst, ehdr.eco_dhost))
  237                         return (0);     /* if not yet resolved */
  238                 /* If broadcasting on a simplex interface, loopback a copy */
  239                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
  240                         mcopy = m_copy(m, 0, (int)M_COPYALL);
  241                 ehdr.eco_port = ECO_PORT_IP;
  242                 ehdr.eco_control = ECO_CTL_IP;
  243                 break;
  244 
  245         case AF_ARP:
  246                 ah = mtod(m, struct arphdr *);
  247 
  248                 if (ntohs(ah->ar_pro) != ETHERTYPE_IP)
  249                         return EAFNOSUPPORT;
  250                 ehdr.eco_port = ECO_PORT_IP;
  251                 switch (ntohs(ah->ar_op)) {
  252                 case ARPOP_REQUEST:
  253                         ehdr.eco_control = ECO_CTL_ARP_REQUEST;
  254                         break;
  255                 case ARPOP_REPLY:
  256                         ehdr.eco_control = ECO_CTL_ARP_REPLY;
  257                         break;
  258                 default:
  259                         return EOPNOTSUPP;
  260                 }
  261 
  262                 if (m->m_flags & M_BCAST)
  263                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  264                             ECO_ADDR_LEN);
  265                 else
  266                         memcpy(ehdr.eco_dhost, ar_tha(ah), ECO_ADDR_LEN);
  267 
  268                 MGETHDR(m1, M_DONTWAIT, MT_DATA);
  269                 if (m1 == NULL)
  270                         senderr(ENOBUFS);
  271                 M_MOVE_PKTHDR(m1, m);
  272                 m1->m_len = sizeof(*ecah);
  273                 m1->m_pkthdr.len = m1->m_len;
  274                 MH_ALIGN(m1, m1->m_len);
  275                 ecah = mtod(m1, struct eco_arp *);
  276                 memset(ecah, 0, m1->m_len);
  277                 memcpy(ecah->ecar_spa, ar_spa(ah), ah->ar_pln);
  278                 memcpy(ecah->ecar_tpa, ar_tpa(ah), ah->ar_pln);
  279                 m_freem(m);
  280                 m = m1;
  281                 break;
  282 #endif
  283         case pseudo_AF_HDRCMPLT:
  284                 hdrcmplt = 1;
  285                 /* FALLTHROUGH */
  286         case AF_UNSPEC:
  287                 eh = (struct eco_header *)dst->sa_data;
  288                 ehdr = *eh;
  289                 break;
  290         default:
  291                 log(LOG_ERR, "%s: can't handle af%d\n", ifp->if_xname,
  292                     dst->sa_family);
  293                 senderr(EAFNOSUPPORT);
  294         }
  295 
  296         if (mcopy)
  297                 (void) looutput(ifp, mcopy, dst, rt);
  298 
  299         /*
  300          * Add local net header.  If no space in first mbuf,
  301          * allocate another.
  302          */
  303         M_PREPEND(m, sizeof (struct eco_header), M_DONTWAIT);
  304         if (m == 0)
  305                 senderr(ENOBUFS);
  306         eh = mtod(m, struct eco_header *);
  307         *eh = ehdr;
  308         if (!hdrcmplt)
  309                 memcpy(eh->eco_shost, LLADDR(ifp->if_sadl),
  310                     ECO_ADDR_LEN);
  311 
  312         if ((m->m_flags & M_BCAST) == 0) {
  313                 /* Attach retry info to packet. */
  314                 mtag = m_tag_get(PACKET_TAG_ECO_RETRYPARMS,
  315                     sizeof(struct eco_retryparms), M_NOWAIT);
  316                 if (mtag == NULL)
  317                         senderr(ENOBUFS);
  318                 erp = (struct eco_retryparms *)(mtag + 1);
  319                 erp->erp_delay = retry_delay;
  320                 erp->erp_count = retry_count;
  321         }
  322 
  323 #ifdef PFIL_HOOKS
  324         if ((error = pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
  325                 return (error);
  326         if (m == NULL)
  327                 return (0);
  328 #endif
  329 
  330         return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr));
  331 
  332 bad:
  333         if (m)
  334                 m_freem(m);
  335         return error;
  336 }
  337 
  338 /*
  339  * Given a scout, decide if we want the rest of the packet.
  340  */
  341 static int
  342 eco_interestingp(struct ifnet *ifp, struct mbuf *m)
  343 {
  344         struct eco_header *eh;
  345 
  346         eh = mtod(m, struct eco_header *);
  347         switch (eh->eco_port) {
  348 #ifdef INET
  349         case ECO_PORT_IP:
  350                 return 1;
  351 #endif
  352         }
  353         return 0;
  354 }
  355 
  356 static void
  357 eco_input(struct ifnet *ifp, struct mbuf *m)
  358 {
  359         struct ifqueue *inq;
  360         struct eco_header ehdr, *eh;
  361         int s, i;
  362 #ifdef INET
  363         struct arphdr *ah;
  364         struct eco_arp *ecah;
  365         struct mbuf *m1;
  366 #endif
  367 
  368 #ifdef PFIL_HOOKS
  369         if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
  370                 return;
  371         if (m == NULL)
  372                 return;
  373 #endif
  374 
  375         /* Copy the mbuf header and trim it off. */
  376         /* XXX use m_split? */
  377         eh = &ehdr;
  378         m_copydata(m, 0, ECO_HDR_LEN, (caddr_t)eh);
  379         m_adj(m, ECO_HDR_LEN);
  380 
  381         switch (eh->eco_port) {
  382 #ifdef INET
  383         case ECO_PORT_IP:
  384                 switch (eh->eco_control) {
  385                 case ECO_CTL_IP:
  386                         schednetisr(NETISR_IP);
  387                         inq = &ipintrq;
  388                         break;
  389                 case ECO_CTL_ARP_REQUEST:
  390                 case ECO_CTL_ARP_REPLY:
  391                         /*
  392                          * ARP over Econet is strange, because Econet only
  393                          * supports 8 bytes of data in a broadcast packet.
  394                          * To cope with this, only the source and destination
  395                          * IP addresses are actually contained in the packet
  396                          * and we have to infer the rest and build a fake ARP
  397                          * packet to pass upwards.
  398                          */
  399                         if (m->m_pkthdr.len != sizeof(struct eco_arp))
  400                                 goto drop;
  401                         if (m->m_len < sizeof(struct eco_arp)) {
  402                                 m = m_pullup(m, sizeof(struct eco_arp));
  403                                 if (m == NULL) goto drop;
  404                         }
  405                         ecah = mtod(m, struct eco_arp *);
  406                         /* This code derived from arprequest() */
  407                         MGETHDR(m1, M_DONTWAIT, MT_DATA);
  408                         if (m1 == NULL)
  409                                 goto drop;
  410                         M_MOVE_PKTHDR(m1, m);
  411                         m1->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
  412                             2*ifp->if_data.ifi_addrlen;
  413                         m1->m_pkthdr.len = m1->m_len;
  414                         MH_ALIGN(m1, m1->m_len);
  415                         ah = mtod(m1, struct arphdr *);
  416                         bzero((caddr_t)ah, m1->m_len);
  417                         ah->ar_pro = htons(ETHERTYPE_IP);
  418                         ah->ar_hln = ifp->if_data.ifi_addrlen;
  419                         ah->ar_pln = sizeof(struct in_addr);
  420                         if (eh->eco_control == ECO_CTL_ARP_REQUEST)
  421                                 ah->ar_op = htons(ARPOP_REQUEST);
  422                         else
  423                                 ah->ar_op = htons(ARPOP_REPLY);
  424                         memcpy(ar_sha(ah), eh->eco_shost, ah->ar_hln);
  425                         memcpy(ar_tha(ah), eh->eco_dhost, ah->ar_hln);
  426                         memcpy(ar_spa(ah), ecah->ecar_spa, ah->ar_pln);
  427                         memcpy(ar_tpa(ah), ecah->ecar_tpa, ah->ar_pln);
  428                         m_freem(m);
  429                         m = m1;
  430                         schednetisr(NETISR_ARP);
  431                         inq = &arpintrq;
  432                         break;
  433                 case ECO_CTL_IPBCAST_REQUEST:
  434                 {
  435                         struct sockaddr_storage dst_store;
  436                         struct sockaddr *dst = (struct sockaddr *)&dst_store;
  437 
  438                         /* Queue? */
  439                         memcpy(eh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  440                         eh->eco_control = ECO_CTL_IPBCAST_REPLY;
  441                         /* dst->sa_len??? */
  442                         dst->sa_family = AF_UNSPEC;
  443                         memcpy(dst->sa_data, eh, ECO_HDR_LEN);
  444                         ifp->if_output(ifp, m, dst, NULL);
  445                         return;
  446                 }
  447                 default:
  448                         printf("%s: unknown IP stn %s ctl 0x%02x len %d:",
  449                             ifp->if_xname, eco_sprintf(eh->eco_shost),
  450                             eh->eco_control, m->m_pkthdr.len);
  451                         if (m->m_len == 0) {
  452                                 m = m_pullup(m, 1);
  453                                 if (m == 0) {
  454                                         printf("\n");
  455                                         goto drop;
  456                                 }
  457                         }
  458                         for (i = 0; i < m->m_len; i++)
  459                                 printf(" %02x", mtod(m, u_int8_t *)[i]);
  460                         printf("\n");
  461                         goto drop;
  462                 }
  463                 break;
  464 #endif
  465         default:
  466                 printf("%s: unknown port stn %s port 0x%02x ctl 0x%02x\n",
  467                     ifp->if_xname, eco_sprintf(eh->eco_shost),
  468                     eh->eco_port, eh->eco_control);
  469         drop:
  470                 m_freem(m);
  471                 return;
  472         }
  473 
  474         s = splnet();
  475         if (IF_QFULL(inq)) {
  476                 IF_DROP(inq);
  477                 m_freem(m);
  478         } else
  479                 IF_ENQUEUE(inq, m);
  480         splx(s);
  481 }
  482 
  483 static void
  484 eco_start(struct ifnet *ifp)
  485 {
  486         struct ecocom *ec = (void *)ifp;
  487         struct mbuf *m;
  488         struct eco_header *eh;
  489 
  490         if (ec->ec_state != ECO_IDLE) return;
  491         IFQ_DEQUEUE(&ifp->if_snd, m);
  492         if (m == NULL) return;
  493         if (ec->ec_claimwire(ifp) == 0) {
  494                 eh = mtod(m, struct eco_header *);
  495                 if (eh->eco_port == ECO_PORT_IMMEDIATE) {
  496                         ec->ec_txframe(ifp, m);
  497                         ec->ec_state = ECO_IMMED_SENT;
  498                 } else if (eh->eco_dhost[0] == 255) {
  499                         ec->ec_txframe(ifp, m);
  500                         ec->ec_state = ECO_DONE;
  501                 } else {
  502                         ec->ec_packet = m;
  503                         m = m_copym(m, 0, ECO_HDR_LEN, M_DONTWAIT);
  504                         if (m == NULL) {
  505                                 m_freem(ec->ec_packet);
  506                                 ec->ec_packet = NULL;
  507                                 return;
  508                         }
  509                         ec->ec_txframe(ifp, m);
  510                         ec->ec_state = ECO_SCOUT_SENT;
  511                 }
  512                 ifp->if_flags |= IFF_OACTIVE;
  513         } else {
  514                 log(LOG_ERR, "%s: line jammed\n", ifp->if_xname);
  515                 m_freem(m);
  516         }
  517 }
  518 
  519 static int
  520 eco_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  521 {
  522         struct ifreq *ifr = (struct ifreq *)data;
  523         struct ifaddr *ifa = (struct ifaddr *)data;
  524         int error = 0;
  525 
  526         switch (cmd) {
  527         case SIOCSIFADDR:
  528                 ifp->if_flags |= IFF_UP;
  529                 switch (ifa->ifa_addr->sa_family) {
  530 #ifdef INET
  531                 case AF_INET:
  532                         if ((ifp->if_flags & IFF_RUNNING) == 0 &&
  533                             (error = (*ifp->if_init)(ifp)) != 0)
  534                                 break;
  535                         arp_ifinit(ifp, ifa);
  536                         break;
  537 #endif
  538                 default:
  539                         if ((ifp->if_flags & IFF_RUNNING) == 0)
  540                                 error = (*ifp->if_init)(ifp);
  541                         break;
  542                 }
  543                 break;
  544         case SIOCSIFMTU:
  545                 ifp->if_mtu = ifr->ifr_mtu;
  546 
  547                 /* Make sure the device notices the MTU change. */
  548                 if (ifp->if_flags & IFF_UP)
  549                         error = (*ifp->if_init)(ifp);
  550                 break;
  551         case SIOCSIFFLAGS:
  552                 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
  553                         /*
  554                          * If interface is marked down and it is running,
  555                          * then stop and disable it.
  556                          */
  557                         (*ifp->if_stop)(ifp, 1);
  558                 } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
  559                         /*
  560                          * If interface is marked up and it is stopped, then
  561                          * start it.
  562                          */
  563                         error = (*ifp->if_init)(ifp);
  564                 } else if ((ifp->if_flags & IFF_UP) != 0) {
  565                         /*
  566                          * Reset the interface to pick up changes in any other
  567                          * flags that affect the hardware state.
  568                          */
  569                         error = (*ifp->if_init)(ifp);
  570                 }
  571                 break;
  572         default:
  573                 error = ENOTTY;
  574         }
  575 
  576         return error;
  577 }
  578 
  579 /*
  580  * Handle a raw Econet frame off the interface.  The interface may be
  581  * flag-filling for a response.
  582  *
  583  * May be called from IPL_NET or IPL_SOFTNET.
  584  */
  585 
  586 struct mbuf *
  587 eco_inputframe(struct ifnet *ifp, struct mbuf *m)
  588 {
  589         struct ecocom *ec = (void *)ifp;
  590         struct eco_header *eh, *eh0;
  591         struct mbuf *m0;
  592         struct mbuf *reply;
  593         int len;
  594 
  595         eh = mtod(m, struct eco_header *);
  596         switch (ec->ec_state) {
  597         case ECO_IDLE: /* Start of a packet (bcast, immed, scout) */
  598                 if (m->m_pkthdr.len < ECO_HDR_LEN) {
  599                         log(LOG_NOTICE, "%s: undersize scout\n",
  600                             ifp->if_xname);
  601                         goto drop;
  602                 }
  603                 if (memcmp(eh->eco_dhost, eco_broadcastaddr,
  604                     ECO_ADDR_LEN) == 0) {
  605                         /* Broadcast */
  606                         eco_input(ifp, m);
  607                 } else if (memcmp(eh->eco_dhost, LLADDR(ifp->if_sadl),
  608                     ECO_ADDR_LEN) == 0) {
  609                         /* Unicast for us */
  610                         if (eh->eco_port == ECO_PORT_IMMEDIATE)
  611                                 return eco_immediate(ifp, m);
  612                         else {
  613                                 if (eco_interestingp(ifp, m)) {
  614                                         reply = eco_ack(ifp, m);
  615                                         if (reply == NULL) {
  616                                                 m_freem(m);
  617                                                 return NULL;
  618                                         }
  619                                         ec->ec_state = ECO_SCOUT_RCVD;
  620                                         ec->ec_scout = m;
  621                                         return reply;
  622                                 } else {
  623                                         m_freem(m);
  624                                         return NULL;
  625                                 }
  626                         }
  627                 } else
  628                         /* Not for us.  Throw it away. */
  629                         m_freem(m);
  630                 break;
  631         case ECO_SCOUT_RCVD: /* Packet data */
  632                 KASSERT(ec->ec_scout != NULL);
  633                 m0 = ec->ec_scout;
  634                 eh0 = mtod(m0, struct eco_header *);
  635                 if (m->m_pkthdr.len < ECO_SHDR_LEN ||
  636                     memcmp(eh->eco_shost, eh0->eco_shost, ECO_ADDR_LEN) != 0 ||
  637                     memcmp(eh->eco_dhost, eh0->eco_dhost, ECO_ADDR_LEN) != 0) {
  638                         log(LOG_NOTICE, "%s: garbled data packet header\n",
  639                             ifp->if_xname);
  640                         goto drop;
  641                 }
  642                 reply = eco_ack(ifp, m);
  643                 /*
  644                  * Chop off the small header from this frame, and put
  645                  * the scout (which holds the control byte and port)
  646                  * in its place.
  647                  */
  648                 ec->ec_scout = NULL;
  649                 m_adj(m, ECO_SHDR_LEN);
  650                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  651                 m_cat(m0, m);
  652                 m0->m_pkthdr.len = len;
  653                 ec->ec_state = ECO_DONE;
  654                 eco_input(ifp, m0);
  655                 return reply;
  656         case ECO_SCOUT_SENT: /* Scout ack */
  657                 KASSERT(ec->ec_packet != NULL);
  658                 m0 = ec->ec_packet;
  659                 eh0 = mtod(m0, struct eco_header *);
  660                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  661                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  662                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  663                         log(LOG_NOTICE, "%s: garbled scout ack\n",
  664                             ifp->if_xname);
  665                         goto drop;
  666                 }
  667                 m_freem(m);
  668                 /* Chop out the control and port bytes. */
  669                 m0 = m_copym(ec->ec_packet, 0, ECO_SHDR_LEN, M_DONTWAIT);
  670                 if (m0 == NULL) {
  671                         m_freem(ec->ec_packet);
  672                         return NULL;
  673                 }
  674                 m = ec->ec_packet;
  675                 ec->ec_packet = m_copypacket(m, M_DONTWAIT);
  676                 if (ec->ec_packet == NULL) {
  677                         m_freem(m0);
  678                         m_freem(m);
  679                         return NULL;
  680                 }
  681                 m_adj(m, ECO_HDR_LEN);
  682                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  683                 m_cat(m0, m); /* Doesn't update packet header */
  684                 m0->m_pkthdr.len = len;
  685                 ec->ec_state = ECO_DATA_SENT;
  686                 return m0;
  687         case ECO_DATA_SENT: /* Data ack */
  688                 KASSERT(ec->ec_packet != NULL);
  689                 m0 = ec->ec_packet;
  690                 eh0 = mtod(m0, struct eco_header *);
  691                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  692                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  693                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  694                         log(LOG_NOTICE, "%s: garbled data ack\n",
  695                             ifp->if_xname);
  696                         goto drop;
  697                 }
  698                 m_freem(m);
  699                 m_freem(ec->ec_packet);
  700                 ec->ec_packet = NULL;
  701                 ec->ec_state = ECO_DONE;
  702                 return NULL;
  703         default:
  704         drop:
  705                 m_freem(m);
  706                 break;
  707         }
  708         return NULL;
  709 }
  710 
  711 /*
  712  * Handle an immediate operation, and return the reply, or NULL not to reply.
  713  * Frees the incoming mbuf.
  714  */
  715 
  716 static struct mbuf *
  717 eco_immediate(struct ifnet *ifp, struct mbuf *m)
  718 {
  719         struct eco_header *eh, *reh;
  720         struct mbuf *n;
  721         static const u_int8_t machinepeek_data[] = { 42, 0, 0, 1 };
  722 
  723         eh = mtod(m, struct eco_header *);
  724         switch (eh->eco_control) {
  725         case ECO_CTL_MACHINEPEEK:
  726                 MGETHDR(n, M_DONTWAIT, MT_DATA);
  727                 if (n == NULL)
  728                         goto bad;
  729                 n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN + 4;
  730                 reh = mtod(n, struct eco_header *);
  731                 memcpy(reh->eco_dhost, eh->eco_shost,
  732                     ECO_ADDR_LEN);
  733                 memcpy(reh->eco_shost, LLADDR(ifp->if_sadl),
  734                     ECO_ADDR_LEN);
  735                 memcpy(mtod(n, caddr_t) + ECO_SHDR_LEN, machinepeek_data,
  736                     sizeof(machinepeek_data));
  737                 m_freem(m);
  738                 return n;
  739         default:
  740         bad:
  741                 m_freem(m);
  742                 return NULL;
  743         }
  744 }
  745 
  746 /*
  747  * Generate (and return) an acknowledgement for a frame.  Doesn't free the
  748  * original frame, since it's probably needed elsewhere.
  749  */
  750 static struct mbuf *
  751 eco_ack(struct ifnet *ifp, struct mbuf *m)
  752 {
  753         struct eco_header *eh, *reh;
  754         struct mbuf *n;
  755 
  756         eh = mtod(m, struct eco_header *);
  757         MGETHDR(n, M_DONTWAIT, MT_DATA);
  758         if (n == NULL)
  759                 return NULL;
  760         n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN;
  761         reh = mtod(n, struct eco_header *);
  762         memcpy(reh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  763         memcpy(reh->eco_shost, LLADDR(ifp->if_sadl), ECO_ADDR_LEN);
  764         return n;
  765 }
  766 
  767 void
  768 eco_inputidle(struct ifnet *ifp)
  769 {
  770         struct ecocom *ec = (void *)ifp;
  771         struct mbuf *m;
  772         struct m_tag *mtag;
  773         struct eco_retryparms *erp;
  774 
  775         switch (ec->ec_state) {
  776         case ECO_SCOUT_SENT:
  777         case ECO_DATA_SENT:
  778         case ECO_IMMED_SENT:
  779                 /* Outgoing packet failed.  Check if we should retry. */
  780                 m = ec->ec_packet;
  781                 ec->ec_packet = NULL;
  782                 mtag = m_tag_find(m, PACKET_TAG_ECO_RETRYPARMS, NULL);
  783                 if (mtag == NULL)
  784                         m_freem(m);
  785                 else {
  786                         erp = (struct eco_retryparms *)(mtag + 1);
  787                         if (--erp->erp_count > 0)
  788                                 eco_defer(ifp, m, erp->erp_delay);
  789                         else
  790                                 printf("%s: pkt failed\n", ifp->if_xname);
  791                 }
  792                 break;
  793         case ECO_SCOUT_RCVD:
  794                 m_freem(ec->ec_scout);
  795                 ec->ec_scout = NULL;
  796                 break;
  797         default:
  798                 break;
  799         }
  800         ec->ec_state = ECO_IDLE;
  801         ifp->if_start(ifp);
  802 }
  803 
  804 /*
  805  * Convert Econet address to printable (loggable) representation.
  806  */
  807 char *
  808 eco_sprintf(const u_int8_t *ea)
  809 {
  810         static char buf[8];
  811 
  812         if (ea[1] == 0)
  813                 snprintf(buf, sizeof(buf), "%d", ea[0]);
  814         else
  815                 snprintf(buf, sizeof(buf), "%d.%d", ea[1], ea[0]);
  816         return buf;
  817 }
  818 
  819 /*
  820  * Econet retry handling.
  821  */
  822 static void
  823 eco_defer(struct ifnet *ifp, struct mbuf *m, int retry_delay)
  824 {
  825         struct ecocom *ec = (struct ecocom *)ifp;
  826         struct eco_retry *er;
  827         int s;
  828 
  829         MALLOC(er, struct eco_retry *, sizeof(*er), M_TEMP, M_NOWAIT);
  830         if (er == NULL) {
  831                 m_freem(m);
  832                 return;
  833         }
  834         callout_init(&er->er_callout);
  835         er->er_packet = m;
  836         er->er_ifp = ifp;
  837         s = splnet();
  838         LIST_INSERT_HEAD(&ec->ec_retries, er, er_link);
  839         splx(s);
  840         callout_reset(&er->er_callout, retry_delay, eco_retry, er);
  841 }
  842 
  843 static void
  844 eco_retry_free(struct eco_retry *er)
  845 {
  846         int s;
  847 
  848         callout_stop(&er->er_callout);
  849         m_freem(er->er_packet);
  850         s = splnet();
  851         LIST_REMOVE(er, er_link);
  852         splx(s);
  853         FREE(er, M_TEMP);
  854 }
  855 
  856 static void
  857 eco_retry(void *arg)
  858 {
  859         struct eco_retry *er = arg;
  860         struct mbuf *m;
  861         struct ifnet *ifp;
  862 
  863         ifp = er->er_ifp;
  864         m = er->er_packet;
  865         LIST_REMOVE(er, er_link);
  866         (void)ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(NULL));
  867         FREE(er, M_TEMP);
  868 }

Cache object: 5b5128540c944ed356b9c5455563f9f6


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