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/netinet/toecore.c

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

    1 /*-
    2  * Copyright (c) 2012 Chelsio Communications, Inc.
    3  * All rights reserved.
    4  * Written by: Navdeep Parhar <np@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/10.2/sys/netinet/toecore.c 245932 2013-01-26 00:57:29Z np $");
   30 
   31 #include "opt_inet.h"
   32 #include "opt_inet6.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/kernel.h>
   36 #include <sys/systm.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/module.h>
   39 #include <sys/types.h>
   40 #include <sys/sockopt.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/socket.h>
   43 
   44 #include <net/ethernet.h>
   45 #include <net/if.h>
   46 #include <net/if_types.h>
   47 #include <net/if_vlan_var.h>
   48 #include <net/if_llatbl.h>
   49 #include <net/route.h>
   50 
   51 #include <netinet/if_ether.h>
   52 #include <netinet/in.h>
   53 #include <netinet/in_pcb.h>
   54 #include <netinet/in_var.h>
   55 #include <netinet6/in6_var.h>
   56 #include <netinet6/in6_pcb.h>
   57 #include <netinet6/nd6.h>
   58 #define TCPSTATES
   59 #include <netinet/tcp.h>
   60 #include <netinet/tcp_fsm.h>
   61 #include <netinet/tcp_timer.h>
   62 #include <netinet/tcp_var.h>
   63 #include <netinet/tcp_syncache.h>
   64 #include <netinet/tcp_offload.h>
   65 #include <netinet/toecore.h>
   66 
   67 static struct mtx toedev_lock;
   68 static TAILQ_HEAD(, toedev) toedev_list;
   69 static eventhandler_tag listen_start_eh;
   70 static eventhandler_tag listen_stop_eh;
   71 static eventhandler_tag lle_event_eh;
   72 static eventhandler_tag route_redirect_eh;
   73 
   74 static int
   75 toedev_connect(struct toedev *tod __unused, struct socket *so __unused,
   76     struct rtentry *rt __unused, struct sockaddr *nam __unused)
   77 {
   78 
   79         return (ENOTSUP);
   80 }
   81 
   82 static int
   83 toedev_listen_start(struct toedev *tod __unused, struct tcpcb *tp __unused)
   84 {
   85 
   86         return (ENOTSUP);
   87 }
   88 
   89 static int
   90 toedev_listen_stop(struct toedev *tod __unused, struct tcpcb *tp __unused)
   91 {
   92 
   93         return (ENOTSUP);
   94 }
   95 
   96 static void
   97 toedev_input(struct toedev *tod __unused, struct tcpcb *tp __unused,
   98     struct mbuf *m)
   99 {
  100 
  101         m_freem(m);
  102         return;
  103 }
  104 
  105 static void
  106 toedev_rcvd(struct toedev *tod __unused, struct tcpcb *tp __unused)
  107 {
  108 
  109         return;
  110 }
  111 
  112 static int
  113 toedev_output(struct toedev *tod __unused, struct tcpcb *tp __unused)
  114 {
  115 
  116         return (ENOTSUP);
  117 }
  118 
  119 static void
  120 toedev_pcb_detach(struct toedev *tod __unused, struct tcpcb *tp __unused)
  121 {
  122 
  123         return;
  124 }
  125 
  126 static void
  127 toedev_l2_update(struct toedev *tod __unused, struct ifnet *ifp __unused,
  128     struct sockaddr *sa __unused, uint8_t *lladdr __unused,
  129     uint16_t vtag __unused)
  130 {
  131 
  132         return;
  133 }
  134 
  135 static void
  136 toedev_route_redirect(struct toedev *tod __unused, struct ifnet *ifp __unused,
  137     struct rtentry *rt0 __unused, struct rtentry *rt1 __unused)
  138 {
  139 
  140         return;
  141 }
  142 
  143 static void
  144 toedev_syncache_added(struct toedev *tod __unused, void *ctx __unused)
  145 {
  146 
  147         return;
  148 }
  149 
  150 static void
  151 toedev_syncache_removed(struct toedev *tod __unused, void *ctx __unused)
  152 {
  153 
  154         return;
  155 }
  156 
  157 static int
  158 toedev_syncache_respond(struct toedev *tod __unused, void *ctx __unused,
  159     struct mbuf *m)
  160 {
  161 
  162         m_freem(m);
  163         return (0);
  164 }
  165 
  166 static void
  167 toedev_offload_socket(struct toedev *tod __unused, void *ctx __unused,
  168     struct socket *so __unused)
  169 {
  170 
  171         return;
  172 }
  173 
  174 static void
  175 toedev_ctloutput(struct toedev *tod __unused, struct tcpcb *tp __unused,
  176     int sopt_dir __unused, int sopt_name __unused)
  177 {
  178 
  179         return;
  180 }
  181 
  182 /*
  183  * Inform one or more TOE devices about a listening socket.
  184  */
  185 static void
  186 toe_listen_start(struct inpcb *inp, void *arg)
  187 {
  188         struct toedev *t, *tod;
  189         struct tcpcb *tp;
  190 
  191         INP_WLOCK_ASSERT(inp);
  192         KASSERT(inp->inp_pcbinfo == &V_tcbinfo,
  193             ("%s: inp is not a TCP inp", __func__));
  194 
  195         if (inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))
  196                 return;
  197 
  198         tp = intotcpcb(inp);
  199         if (tp->t_state != TCPS_LISTEN)
  200                 return;
  201 
  202         t = arg;
  203         mtx_lock(&toedev_lock);
  204         TAILQ_FOREACH(tod, &toedev_list, link) {
  205                 if (t == NULL || t == tod)
  206                         tod->tod_listen_start(tod, tp);
  207         }
  208         mtx_unlock(&toedev_lock);
  209 }
  210 
  211 static void
  212 toe_listen_start_event(void *arg __unused, struct tcpcb *tp)
  213 {
  214         struct inpcb *inp = tp->t_inpcb;
  215 
  216         INP_WLOCK_ASSERT(inp);
  217         KASSERT(tp->t_state == TCPS_LISTEN,
  218             ("%s: t_state %s", __func__, tcpstates[tp->t_state]));
  219 
  220         toe_listen_start(inp, NULL);
  221 }
  222 
  223 static void
  224 toe_listen_stop_event(void *arg __unused, struct tcpcb *tp)
  225 {
  226         struct toedev *tod;
  227 #ifdef INVARIANTS
  228         struct inpcb *inp = tp->t_inpcb;
  229 #endif
  230 
  231         INP_WLOCK_ASSERT(inp);
  232         KASSERT(tp->t_state == TCPS_LISTEN,
  233             ("%s: t_state %s", __func__, tcpstates[tp->t_state]));
  234 
  235         mtx_lock(&toedev_lock);
  236         TAILQ_FOREACH(tod, &toedev_list, link)
  237             tod->tod_listen_stop(tod, tp);
  238         mtx_unlock(&toedev_lock);
  239 }
  240 
  241 /*
  242  * Fill up a freshly allocated toedev struct with reasonable defaults.
  243  */
  244 void
  245 init_toedev(struct toedev *tod)
  246 {
  247 
  248         tod->tod_softc = NULL;
  249 
  250         /*
  251          * Provide no-op defaults so that the kernel can call any toedev
  252          * function without having to check whether the TOE driver supplied one
  253          * or not.
  254          */
  255         tod->tod_connect = toedev_connect;
  256         tod->tod_listen_start = toedev_listen_start;
  257         tod->tod_listen_stop = toedev_listen_stop;
  258         tod->tod_input = toedev_input;
  259         tod->tod_rcvd = toedev_rcvd;
  260         tod->tod_output = toedev_output;
  261         tod->tod_send_rst = toedev_output;
  262         tod->tod_send_fin = toedev_output;
  263         tod->tod_pcb_detach = toedev_pcb_detach;
  264         tod->tod_l2_update = toedev_l2_update;
  265         tod->tod_route_redirect = toedev_route_redirect;
  266         tod->tod_syncache_added = toedev_syncache_added;
  267         tod->tod_syncache_removed = toedev_syncache_removed;
  268         tod->tod_syncache_respond = toedev_syncache_respond;
  269         tod->tod_offload_socket = toedev_offload_socket;
  270         tod->tod_ctloutput = toedev_ctloutput;
  271 }
  272 
  273 /*
  274  * Register an active TOE device with the system.  This allows it to receive
  275  * notifications from the kernel.
  276  */
  277 int
  278 register_toedev(struct toedev *tod)
  279 {
  280         struct toedev *t;
  281 
  282         mtx_lock(&toedev_lock);
  283         TAILQ_FOREACH(t, &toedev_list, link) {
  284                 if (t == tod) {
  285                         mtx_unlock(&toedev_lock);
  286                         return (EEXIST);
  287                 }
  288         }
  289 
  290         TAILQ_INSERT_TAIL(&toedev_list, tod, link);
  291         registered_toedevs++;
  292         mtx_unlock(&toedev_lock);
  293 
  294         inp_apply_all(toe_listen_start, tod);
  295 
  296         return (0);
  297 }
  298 
  299 /*
  300  * Remove the TOE device from the global list of active TOE devices.  It is the
  301  * caller's responsibility to ensure that the TOE device is quiesced prior to
  302  * this call.
  303  */
  304 int
  305 unregister_toedev(struct toedev *tod)
  306 {
  307         struct toedev *t, *t2;
  308         int rc = ENODEV;
  309 
  310         mtx_lock(&toedev_lock);
  311         TAILQ_FOREACH_SAFE(t, &toedev_list, link, t2) {
  312                 if (t == tod) {
  313                         TAILQ_REMOVE(&toedev_list, tod, link);
  314                         registered_toedevs--;
  315                         rc = 0;
  316                         break;
  317                 }
  318         }
  319         KASSERT(registered_toedevs >= 0,
  320             ("%s: registered_toedevs (%d) < 0", __func__, registered_toedevs));
  321         mtx_unlock(&toedev_lock);
  322         return (rc);
  323 }
  324 
  325 void
  326 toe_syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
  327     struct inpcb *inp, void *tod, void *todctx)
  328 {
  329         struct socket *lso = inp->inp_socket;
  330 
  331         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
  332         INP_WLOCK_ASSERT(inp);
  333 
  334         syncache_add(inc, to, th, inp, &lso, NULL, tod, todctx);
  335 }
  336 
  337 int
  338 toe_syncache_expand(struct in_conninfo *inc, struct tcpopt *to,
  339     struct tcphdr *th, struct socket **lsop)
  340 {
  341 
  342         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
  343 
  344         return (syncache_expand(inc, to, th, lsop, NULL));
  345 }
  346 
  347 /*
  348  * General purpose check to see if a 4-tuple is in use by the kernel.  If a TCP
  349  * header (presumably for an incoming SYN) is also provided, an existing 4-tuple
  350  * in TIME_WAIT may be assassinated freeing it up for re-use.
  351  *
  352  * Note that the TCP header must have been run through tcp_fields_to_host() or
  353  * equivalent.
  354  */
  355 int
  356 toe_4tuple_check(struct in_conninfo *inc, struct tcphdr *th, struct ifnet *ifp)
  357 {
  358         struct inpcb *inp;
  359 
  360         if (inc->inc_flags & INC_ISIPV6) {
  361                 inp = in6_pcblookup(&V_tcbinfo, &inc->inc6_faddr,
  362                     inc->inc_fport, &inc->inc6_laddr, inc->inc_lport,
  363                     INPLOOKUP_WLOCKPCB, ifp);
  364         } else {
  365                 inp = in_pcblookup(&V_tcbinfo, inc->inc_faddr, inc->inc_fport,
  366                     inc->inc_laddr, inc->inc_lport, INPLOOKUP_WLOCKPCB, ifp);
  367         }
  368         if (inp != NULL) {
  369                 INP_WLOCK_ASSERT(inp);
  370 
  371                 if ((inp->inp_flags & INP_TIMEWAIT) && th != NULL) {
  372 
  373                         INP_INFO_WLOCK_ASSERT(&V_tcbinfo); /* for twcheck */
  374                         if (!tcp_twcheck(inp, NULL, th, NULL, 0))
  375                                 return (EADDRINUSE);
  376                 } else {
  377                         INP_WUNLOCK(inp);
  378                         return (EADDRINUSE);
  379                 }
  380         }
  381 
  382         return (0);
  383 }
  384 
  385 static void
  386 toe_lle_event(void *arg __unused, struct llentry *lle, int evt)
  387 {
  388         struct toedev *tod;
  389         struct ifnet *ifp;
  390         struct sockaddr *sa;
  391         uint8_t *lladdr;
  392         uint16_t vtag;
  393 
  394         LLE_WLOCK_ASSERT(lle);
  395 
  396         ifp = lle->lle_tbl->llt_ifp;
  397         sa = L3_ADDR(lle);
  398 
  399         KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
  400             ("%s: lle_event %d for lle %p but sa %p !INET && !INET6",
  401             __func__, evt, lle, sa));
  402 
  403         /*
  404          * Not interested if the interface's TOE capability is not enabled.
  405          */
  406         if ((sa->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4)) ||
  407             (sa->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6)))
  408                 return;
  409 
  410         tod = TOEDEV(ifp);
  411         if (tod == NULL)
  412                 return;
  413 
  414         vtag = 0xfff;
  415         if (evt != LLENTRY_RESOLVED) {
  416 
  417                 /*
  418                  * LLENTRY_TIMEDOUT, LLENTRY_DELETED, LLENTRY_EXPIRED all mean
  419                  * this entry is going to be deleted.
  420                  */
  421 
  422                 lladdr = NULL;
  423         } else {
  424 
  425                 KASSERT(lle->la_flags & LLE_VALID,
  426                     ("%s: %p resolved but not valid?", __func__, lle));
  427 
  428                 lladdr = (uint8_t *)&lle->ll_addr;
  429 #ifdef VLAN_TAG
  430                 VLAN_TAG(ifp, &vtag);
  431 #endif
  432         }
  433 
  434         tod->tod_l2_update(tod, ifp, sa, lladdr, vtag);
  435 }
  436 
  437 /*
  438  * XXX: implement.
  439  */
  440 static void
  441 toe_route_redirect_event(void *arg __unused, struct rtentry *rt0,
  442     struct rtentry *rt1, struct sockaddr *sa)
  443 {
  444 
  445         return;
  446 }
  447 
  448 #ifdef INET6
  449 /*
  450  * XXX: no checks to verify that sa is really a neighbor because we assume it is
  451  * the result of a route lookup and is on-link on the given ifp.
  452  */
  453 static int
  454 toe_nd6_resolve(struct ifnet *ifp, struct sockaddr *sa, uint8_t *lladdr)
  455 {
  456         struct llentry *lle;
  457         struct sockaddr_in6 *sin6 = (void *)sa;
  458         int rc, flags = 0;
  459 
  460 restart:
  461         IF_AFDATA_RLOCK(ifp);
  462         lle = lla_lookup(LLTABLE6(ifp), flags, sa);
  463         IF_AFDATA_RUNLOCK(ifp);
  464         if (lle == NULL) {
  465                 IF_AFDATA_LOCK(ifp);
  466                 lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE,
  467                     ifp);
  468                 IF_AFDATA_UNLOCK(ifp);
  469                 if (lle == NULL)
  470                         return (ENOMEM); /* Couldn't create entry in cache. */
  471                 lle->ln_state = ND6_LLINFO_INCOMPLETE;
  472                 nd6_llinfo_settimer_locked(lle,
  473                     (long)ND_IFINFO(ifp)->retrans * hz / 1000);
  474                 LLE_WUNLOCK(lle);
  475 
  476                 nd6_ns_output(ifp, NULL, &sin6->sin6_addr, NULL, 0);
  477 
  478                 return (EWOULDBLOCK);
  479         }
  480 
  481         if (lle->ln_state == ND6_LLINFO_STALE) {
  482                 if ((flags & LLE_EXCLUSIVE) == 0) {
  483                         LLE_RUNLOCK(lle);
  484                         flags |= LLE_EXCLUSIVE;
  485                         goto restart;
  486                 }
  487 
  488                 LLE_WLOCK_ASSERT(lle);
  489 
  490                 lle->la_asked = 0;
  491                 lle->ln_state = ND6_LLINFO_DELAY;
  492                 nd6_llinfo_settimer_locked(lle, (long)V_nd6_delay * hz);
  493         }
  494 
  495         if (lle->la_flags & LLE_VALID) {
  496                 memcpy(lladdr, &lle->ll_addr, ifp->if_addrlen);
  497                 rc = 0;
  498         } else
  499                 rc = EWOULDBLOCK;
  500 
  501         if (flags & LLE_EXCLUSIVE)
  502                 LLE_WUNLOCK(lle);
  503         else
  504                 LLE_RUNLOCK(lle);
  505 
  506         return (rc);
  507 }
  508 #endif
  509 
  510 /*
  511  * Returns 0 or EWOULDBLOCK on success (any other value is an error).  0 means
  512  * lladdr and vtag are valid on return, EWOULDBLOCK means the TOE driver's
  513  * tod_l2_update will be called later, when the entry is resolved or times out.
  514  */
  515 int
  516 toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
  517     uint8_t *lladdr, uint16_t *vtag)
  518 {
  519 #ifdef INET
  520         struct llentry *lle;
  521 #endif
  522         int rc;
  523 
  524         switch (sa->sa_family) {
  525 #ifdef INET
  526         case AF_INET:
  527                 rc = arpresolve(ifp, NULL, NULL, sa, lladdr, &lle);
  528                 break;
  529 #endif
  530 #ifdef INET6
  531         case AF_INET6:
  532                 rc = toe_nd6_resolve(ifp, sa, lladdr);
  533                 break;
  534 #endif
  535         default:
  536                 return (EPROTONOSUPPORT);
  537         }
  538 
  539         if (rc == 0) {
  540 #ifdef VLAN_TAG
  541                 if (VLAN_TAG(ifp, vtag) != 0)
  542 #endif
  543                         *vtag = 0xfff;
  544         }
  545 
  546         return (rc);
  547 }
  548 
  549 void
  550 toe_connect_failed(struct toedev *tod, struct inpcb *inp, int err)
  551 {
  552 
  553         INP_WLOCK_ASSERT(inp);
  554 
  555         if (!(inp->inp_flags & INP_DROPPED)) {
  556                 struct tcpcb *tp = intotcpcb(inp);
  557 
  558                 KASSERT(tp->t_flags & TF_TOE,
  559                     ("%s: tp %p not offloaded.", __func__, tp));
  560 
  561                 if (err == EAGAIN) {
  562 
  563                         /*
  564                          * Temporary failure during offload, take this PCB back.
  565                          * Detach from the TOE driver and do the rest of what
  566                          * TCP's pru_connect would have done if the connection
  567                          * wasn't offloaded.
  568                          */
  569 
  570                         tod->tod_pcb_detach(tod, tp);
  571                         KASSERT(!(tp->t_flags & TF_TOE),
  572                             ("%s: tp %p still offloaded.", __func__, tp));
  573                         tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp));
  574                         (void) tcp_output(tp);
  575                 } else {
  576 
  577                         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
  578                         tp = tcp_drop(tp, err);
  579                         if (tp == NULL)
  580                                 INP_WLOCK(inp); /* re-acquire */
  581                 }
  582         }
  583         INP_WLOCK_ASSERT(inp);
  584 }
  585 
  586 static int
  587 toecore_load(void)
  588 {
  589 
  590         mtx_init(&toedev_lock, "toedev lock", NULL, MTX_DEF);
  591         TAILQ_INIT(&toedev_list);
  592 
  593         listen_start_eh = EVENTHANDLER_REGISTER(tcp_offload_listen_start,
  594             toe_listen_start_event, NULL, EVENTHANDLER_PRI_ANY);
  595         listen_stop_eh = EVENTHANDLER_REGISTER(tcp_offload_listen_stop,
  596             toe_listen_stop_event, NULL, EVENTHANDLER_PRI_ANY);
  597         lle_event_eh = EVENTHANDLER_REGISTER(lle_event, toe_lle_event, NULL,
  598             EVENTHANDLER_PRI_ANY);
  599         route_redirect_eh = EVENTHANDLER_REGISTER(route_redirect_event,
  600             toe_route_redirect_event, NULL, EVENTHANDLER_PRI_ANY);
  601 
  602         return (0);
  603 }
  604 
  605 static int
  606 toecore_unload(void)
  607 {
  608 
  609         mtx_lock(&toedev_lock);
  610         if (!TAILQ_EMPTY(&toedev_list)) {
  611                 mtx_unlock(&toedev_lock);
  612                 return (EBUSY);
  613         }
  614 
  615         EVENTHANDLER_DEREGISTER(tcp_offload_listen_start, listen_start_eh);
  616         EVENTHANDLER_DEREGISTER(tcp_offload_listen_stop, listen_stop_eh);
  617         EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
  618         EVENTHANDLER_DEREGISTER(route_redirect_event, route_redirect_eh);
  619 
  620         mtx_unlock(&toedev_lock);
  621         mtx_destroy(&toedev_lock);
  622 
  623         return (0);
  624 }
  625 
  626 static int
  627 toecore_mod_handler(module_t mod, int cmd, void *arg)
  628 {
  629 
  630         if (cmd == MOD_LOAD)
  631                 return (toecore_load());
  632 
  633         if (cmd == MOD_UNLOAD)
  634                 return (toecore_unload());
  635 
  636         return (EOPNOTSUPP);
  637 }
  638 
  639 static moduledata_t mod_data= {
  640         "toecore",
  641         toecore_mod_handler,
  642         0
  643 };
  644 
  645 MODULE_VERSION(toecore, 1);
  646 DECLARE_MODULE(toecore, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);

Cache object: 127d4b0f8b2e586302adb37a94a1439d


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