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.4/sys/netinet/toecore.c 309108 2016-11-24 14:48:46Z jch $");
   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_WLOCK_ASSERT(inp);
  332 
  333         syncache_add(inc, to, th, inp, &lso, NULL, tod, todctx);
  334 }
  335 
  336 int
  337 toe_syncache_expand(struct in_conninfo *inc, struct tcpopt *to,
  338     struct tcphdr *th, struct socket **lsop)
  339 {
  340 
  341         INP_INFO_RLOCK_ASSERT(&V_tcbinfo);
  342 
  343         return (syncache_expand(inc, to, th, lsop, NULL));
  344 }
  345 
  346 /*
  347  * General purpose check to see if a 4-tuple is in use by the kernel.  If a TCP
  348  * header (presumably for an incoming SYN) is also provided, an existing 4-tuple
  349  * in TIME_WAIT may be assassinated freeing it up for re-use.
  350  *
  351  * Note that the TCP header must have been run through tcp_fields_to_host() or
  352  * equivalent.
  353  */
  354 int
  355 toe_4tuple_check(struct in_conninfo *inc, struct tcphdr *th, struct ifnet *ifp)
  356 {
  357         struct inpcb *inp;
  358 
  359         if (inc->inc_flags & INC_ISIPV6) {
  360                 inp = in6_pcblookup(&V_tcbinfo, &inc->inc6_faddr,
  361                     inc->inc_fport, &inc->inc6_laddr, inc->inc_lport,
  362                     INPLOOKUP_WLOCKPCB, ifp);
  363         } else {
  364                 inp = in_pcblookup(&V_tcbinfo, inc->inc_faddr, inc->inc_fport,
  365                     inc->inc_laddr, inc->inc_lport, INPLOOKUP_WLOCKPCB, ifp);
  366         }
  367         if (inp != NULL) {
  368                 INP_WLOCK_ASSERT(inp);
  369 
  370                 if ((inp->inp_flags & INP_TIMEWAIT) && th != NULL) {
  371 
  372                         INP_INFO_RLOCK_ASSERT(&V_tcbinfo); /* for twcheck */
  373                         if (!tcp_twcheck(inp, NULL, th, NULL, 0))
  374                                 return (EADDRINUSE);
  375                 } else {
  376                         INP_WUNLOCK(inp);
  377                         return (EADDRINUSE);
  378                 }
  379         }
  380 
  381         return (0);
  382 }
  383 
  384 static void
  385 toe_lle_event(void *arg __unused, struct llentry *lle, int evt)
  386 {
  387         struct toedev *tod;
  388         struct ifnet *ifp;
  389         struct sockaddr *sa;
  390         uint8_t *lladdr;
  391         uint16_t vtag;
  392 
  393         LLE_WLOCK_ASSERT(lle);
  394 
  395         ifp = lle->lle_tbl->llt_ifp;
  396         sa = L3_ADDR(lle);
  397 
  398         KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
  399             ("%s: lle_event %d for lle %p but sa %p !INET && !INET6",
  400             __func__, evt, lle, sa));
  401 
  402         /*
  403          * Not interested if the interface's TOE capability is not enabled.
  404          */
  405         if ((sa->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4)) ||
  406             (sa->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6)))
  407                 return;
  408 
  409         tod = TOEDEV(ifp);
  410         if (tod == NULL)
  411                 return;
  412 
  413         vtag = 0xfff;
  414         if (evt != LLENTRY_RESOLVED) {
  415 
  416                 /*
  417                  * LLENTRY_TIMEDOUT, LLENTRY_DELETED, LLENTRY_EXPIRED all mean
  418                  * this entry is going to be deleted.
  419                  */
  420 
  421                 lladdr = NULL;
  422         } else {
  423 
  424                 KASSERT(lle->la_flags & LLE_VALID,
  425                     ("%s: %p resolved but not valid?", __func__, lle));
  426 
  427                 lladdr = (uint8_t *)&lle->ll_addr;
  428 #ifdef VLAN_TAG
  429                 VLAN_TAG(ifp, &vtag);
  430 #endif
  431         }
  432 
  433         tod->tod_l2_update(tod, ifp, sa, lladdr, vtag);
  434 }
  435 
  436 /*
  437  * XXX: implement.
  438  */
  439 static void
  440 toe_route_redirect_event(void *arg __unused, struct rtentry *rt0,
  441     struct rtentry *rt1, struct sockaddr *sa)
  442 {
  443 
  444         return;
  445 }
  446 
  447 #ifdef INET6
  448 /*
  449  * XXX: no checks to verify that sa is really a neighbor because we assume it is
  450  * the result of a route lookup and is on-link on the given ifp.
  451  */
  452 static int
  453 toe_nd6_resolve(struct ifnet *ifp, struct sockaddr *sa, uint8_t *lladdr)
  454 {
  455         struct llentry *lle;
  456         struct sockaddr_in6 *sin6 = (void *)sa;
  457         int rc, flags = 0;
  458 
  459 restart:
  460         IF_AFDATA_RLOCK(ifp);
  461         lle = lla_lookup(LLTABLE6(ifp), flags, sa);
  462         IF_AFDATA_RUNLOCK(ifp);
  463         if (lle == NULL) {
  464                 IF_AFDATA_LOCK(ifp);
  465                 lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE,
  466                     ifp);
  467                 IF_AFDATA_UNLOCK(ifp);
  468                 if (lle == NULL)
  469                         return (ENOMEM); /* Couldn't create entry in cache. */
  470                 lle->ln_state = ND6_LLINFO_INCOMPLETE;
  471                 nd6_llinfo_settimer_locked(lle,
  472                     (long)ND_IFINFO(ifp)->retrans * hz / 1000);
  473                 LLE_WUNLOCK(lle);
  474 
  475                 nd6_ns_output(ifp, NULL, &sin6->sin6_addr, NULL, 0);
  476 
  477                 return (EWOULDBLOCK);
  478         }
  479 
  480         if (lle->ln_state == ND6_LLINFO_STALE) {
  481                 if ((flags & LLE_EXCLUSIVE) == 0) {
  482                         LLE_RUNLOCK(lle);
  483                         flags |= LLE_EXCLUSIVE;
  484                         goto restart;
  485                 }
  486 
  487                 LLE_WLOCK_ASSERT(lle);
  488 
  489                 lle->la_asked = 0;
  490                 lle->ln_state = ND6_LLINFO_DELAY;
  491                 nd6_llinfo_settimer_locked(lle, (long)V_nd6_delay * hz);
  492         }
  493 
  494         if (lle->la_flags & LLE_VALID) {
  495                 memcpy(lladdr, &lle->ll_addr, ifp->if_addrlen);
  496                 rc = 0;
  497         } else
  498                 rc = EWOULDBLOCK;
  499 
  500         if (flags & LLE_EXCLUSIVE)
  501                 LLE_WUNLOCK(lle);
  502         else
  503                 LLE_RUNLOCK(lle);
  504 
  505         return (rc);
  506 }
  507 #endif
  508 
  509 /*
  510  * Returns 0 or EWOULDBLOCK on success (any other value is an error).  0 means
  511  * lladdr and vtag are valid on return, EWOULDBLOCK means the TOE driver's
  512  * tod_l2_update will be called later, when the entry is resolved or times out.
  513  */
  514 int
  515 toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
  516     uint8_t *lladdr, uint16_t *vtag)
  517 {
  518 #ifdef INET
  519         struct llentry *lle;
  520 #endif
  521         int rc;
  522 
  523         switch (sa->sa_family) {
  524 #ifdef INET
  525         case AF_INET:
  526                 rc = arpresolve(ifp, NULL, NULL, sa, lladdr, &lle);
  527                 break;
  528 #endif
  529 #ifdef INET6
  530         case AF_INET6:
  531                 rc = toe_nd6_resolve(ifp, sa, lladdr);
  532                 break;
  533 #endif
  534         default:
  535                 return (EPROTONOSUPPORT);
  536         }
  537 
  538         if (rc == 0) {
  539 #ifdef VLAN_TAG
  540                 if (VLAN_TAG(ifp, vtag) != 0)
  541 #endif
  542                         *vtag = 0xfff;
  543         }
  544 
  545         return (rc);
  546 }
  547 
  548 void
  549 toe_connect_failed(struct toedev *tod, struct inpcb *inp, int err)
  550 {
  551 
  552         INP_WLOCK_ASSERT(inp);
  553 
  554         if (!(inp->inp_flags & INP_DROPPED)) {
  555                 struct tcpcb *tp = intotcpcb(inp);
  556 
  557                 KASSERT(tp->t_flags & TF_TOE,
  558                     ("%s: tp %p not offloaded.", __func__, tp));
  559 
  560                 if (err == EAGAIN) {
  561 
  562                         /*
  563                          * Temporary failure during offload, take this PCB back.
  564                          * Detach from the TOE driver and do the rest of what
  565                          * TCP's pru_connect would have done if the connection
  566                          * wasn't offloaded.
  567                          */
  568 
  569                         tod->tod_pcb_detach(tod, tp);
  570                         KASSERT(!(tp->t_flags & TF_TOE),
  571                             ("%s: tp %p still offloaded.", __func__, tp));
  572                         tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp));
  573                         (void) tcp_output(tp);
  574                 } else {
  575 
  576                         INP_INFO_RLOCK_ASSERT(&V_tcbinfo);
  577                         tp = tcp_drop(tp, err);
  578                         if (tp == NULL)
  579                                 INP_WLOCK(inp); /* re-acquire */
  580                 }
  581         }
  582         INP_WLOCK_ASSERT(inp);
  583 }
  584 
  585 static int
  586 toecore_load(void)
  587 {
  588 
  589         mtx_init(&toedev_lock, "toedev lock", NULL, MTX_DEF);
  590         TAILQ_INIT(&toedev_list);
  591 
  592         listen_start_eh = EVENTHANDLER_REGISTER(tcp_offload_listen_start,
  593             toe_listen_start_event, NULL, EVENTHANDLER_PRI_ANY);
  594         listen_stop_eh = EVENTHANDLER_REGISTER(tcp_offload_listen_stop,
  595             toe_listen_stop_event, NULL, EVENTHANDLER_PRI_ANY);
  596         lle_event_eh = EVENTHANDLER_REGISTER(lle_event, toe_lle_event, NULL,
  597             EVENTHANDLER_PRI_ANY);
  598         route_redirect_eh = EVENTHANDLER_REGISTER(route_redirect_event,
  599             toe_route_redirect_event, NULL, EVENTHANDLER_PRI_ANY);
  600 
  601         return (0);
  602 }
  603 
  604 static int
  605 toecore_unload(void)
  606 {
  607 
  608         mtx_lock(&toedev_lock);
  609         if (!TAILQ_EMPTY(&toedev_list)) {
  610                 mtx_unlock(&toedev_lock);
  611                 return (EBUSY);
  612         }
  613 
  614         EVENTHANDLER_DEREGISTER(tcp_offload_listen_start, listen_start_eh);
  615         EVENTHANDLER_DEREGISTER(tcp_offload_listen_stop, listen_stop_eh);
  616         EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
  617         EVENTHANDLER_DEREGISTER(route_redirect_event, route_redirect_eh);
  618 
  619         mtx_unlock(&toedev_lock);
  620         mtx_destroy(&toedev_lock);
  621 
  622         return (0);
  623 }
  624 
  625 static int
  626 toecore_mod_handler(module_t mod, int cmd, void *arg)
  627 {
  628 
  629         if (cmd == MOD_LOAD)
  630                 return (toecore_load());
  631 
  632         if (cmd == MOD_UNLOAD)
  633                 return (toecore_unload());
  634 
  635         return (EOPNOTSUPP);
  636 }
  637 
  638 static moduledata_t mod_data= {
  639         "toecore",
  640         toecore_mod_handler,
  641         0
  642 };
  643 
  644 MODULE_VERSION(toecore, 1);
  645 DECLARE_MODULE(toecore, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);

Cache object: 40ae2f42b300a5574b1b8ae7742f8f61


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