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/netgraph/ng_l2tp.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) 2001-2002 Packet Design, LLC.
    3  * All rights reserved.
    4  * 
    5  * Subject to the following obligations and disclaimer of warranty,
    6  * use and redistribution of this software, in source or object code
    7  * forms, with or without modifications are expressly permitted by
    8  * Packet Design; provided, however, that:
    9  * 
   10  *    (i)  Any and all reproductions of the source or object code
   11  *         must include the copyright notice above and the following
   12  *         disclaimer of warranties; and
   13  *    (ii) No rights are granted, in any manner or form, to use
   14  *         Packet Design trademarks, including the mark "PACKET DESIGN"
   15  *         on advertising, endorsements, or otherwise except as such
   16  *         appears in the above copyright notice or in the software.
   17  * 
   18  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
   19  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
   20  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
   21  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
   22  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
   23  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
   24  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
   25  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
   26  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
   27  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
   28  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
   29  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
   30  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
   31  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
   32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
   34  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
   35  * THE POSSIBILITY OF SUCH DAMAGE.
   36  * 
   37  * Author: Archie Cobbs <archie@freebsd.org>
   38  *
   39  * $FreeBSD$
   40  */
   41 
   42 /*
   43  * L2TP netgraph node type.
   44  *
   45  * This node type implements the lower layer of the
   46  * L2TP protocol as specified in RFC 2661.
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/time.h>
   53 #include <sys/conf.h>
   54 #include <sys/mbuf.h>
   55 #include <sys/malloc.h>
   56 #include <sys/errno.h>
   57 #include <sys/libkern.h>
   58 
   59 #include <net/vnet.h>
   60 
   61 #include <netgraph/ng_message.h>
   62 #include <netgraph/netgraph.h>
   63 #include <netgraph/ng_parse.h>
   64 #include <netgraph/ng_l2tp.h>
   65 
   66 #ifdef NG_SEPARATE_MALLOC
   67 static MALLOC_DEFINE(M_NETGRAPH_L2TP, "netgraph_l2tp", "netgraph l2tp node");
   68 #else
   69 #define M_NETGRAPH_L2TP M_NETGRAPH
   70 #endif
   71 
   72 /* L2TP header format (first 2 bytes only) */
   73 #define L2TP_HDR_CTRL           0x8000                  /* control packet */
   74 #define L2TP_HDR_LEN            0x4000                  /* has length field */
   75 #define L2TP_HDR_SEQ            0x0800                  /* has ns, nr fields */
   76 #define L2TP_HDR_OFF            0x0200                  /* has offset field */
   77 #define L2TP_HDR_PRIO           0x0100                  /* give priority */
   78 #define L2TP_HDR_VERS_MASK      0x000f                  /* version field mask */
   79 #define L2TP_HDR_VERSION        0x0002                  /* version field */
   80 
   81 /* Bits that must be zero or one in first two bytes of header */
   82 #define L2TP_CTRL_0BITS         0x030d                  /* ctrl: must be 0 */
   83 #define L2TP_CTRL_1BITS         0xc802                  /* ctrl: must be 1 */
   84 #define L2TP_DATA_0BITS         0x800d                  /* data: must be 0 */
   85 #define L2TP_DATA_1BITS         0x0002                  /* data: must be 1 */
   86 
   87 /* Standard xmit ctrl and data header bits */
   88 #define L2TP_CTRL_HDR           (L2TP_HDR_CTRL | L2TP_HDR_LEN \
   89                                     | L2TP_HDR_SEQ | L2TP_HDR_VERSION)
   90 #define L2TP_DATA_HDR           (L2TP_HDR_VERSION)      /* optional: len, seq */
   91 
   92 /* Some hard coded values */
   93 #define L2TP_MAX_XWIN           128                     /* my max xmit window */
   94 #define L2TP_MAX_REXMIT         5                       /* default max rexmit */
   95 #define L2TP_MAX_REXMIT_TO      30                      /* default rexmit to */
   96 #define L2TP_DELAYED_ACK        ((hz + 19) / 20)        /* delayed ack: 50 ms */
   97 
   98 /* Default data sequence number configuration for new sessions */
   99 #define L2TP_CONTROL_DSEQ       1                       /* we are the lns */
  100 #define L2TP_ENABLE_DSEQ        1                       /* enable data seq # */
  101 
  102 /* Compare sequence numbers using circular math */
  103 #define L2TP_SEQ_DIFF(x, y)     ((int16_t)((x) - (y)))
  104 
  105 #define SESSHASHSIZE            0x0020
  106 #define SESSHASH(x)             (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
  107 
  108 /* Hook private data (data session hooks only) */
  109 struct ng_l2tp_hook_private {
  110         struct ng_l2tp_sess_config      conf;   /* hook/session config */
  111         struct ng_l2tp_session_stats    stats;  /* per sessions statistics */
  112         hook_p                          hook;   /* hook reference */
  113         u_int16_t                       ns;     /* data ns sequence number */
  114         u_int16_t                       nr;     /* data nr sequence number */
  115         LIST_ENTRY(ng_l2tp_hook_private) sessions;
  116 };
  117 typedef struct ng_l2tp_hook_private *hookpriv_p;
  118 
  119 /*
  120  * Sequence number state
  121  *
  122  * Invariants:
  123  *    - If cwnd < ssth, we're doing slow start, otherwise congestion avoidance
  124  *    - The number of unacknowledged xmit packets is (ns - rack) <= seq->wmax
  125  *    - The first (ns - rack) mbuf's in xwin[] array are copies of these
  126  *      unacknowledged packets; the remainder of xwin[] consists first of
  127  *      zero or more further untransmitted packets in the transmit queue
  128  *    - We try to keep the peer's receive window as full as possible.
  129  *      Therefore, (i < cwnd && xwin[i] != NULL) implies (ns - rack) > i.
  130  *    - rack_timer is running iff (ns - rack) > 0 (unack'd xmit'd pkts)
  131  *    - If xack != nr, there are unacknowledged recv packet(s) (delayed ack)
  132  *    - xack_timer is running iff xack != nr (unack'd rec'd pkts)
  133  */
  134 struct l2tp_seq {
  135         u_int16_t               ns;             /* next xmit seq we send */
  136         u_int16_t               nr;             /* next recv seq we expect */
  137         u_int16_t               inproc;         /* packet is in processing */
  138         u_int16_t               rack;           /* last 'nr' we rec'd */
  139         u_int16_t               xack;           /* last 'nr' we sent */
  140         u_int16_t               wmax;           /* peer's max recv window */
  141         u_int16_t               cwnd;           /* current congestion window */
  142         u_int16_t               ssth;           /* slow start threshold */
  143         u_int16_t               acks;           /* # consecutive acks rec'd */
  144         u_int16_t               rexmits;        /* # retransmits sent */
  145         struct callout          rack_timer;     /* retransmit timer */
  146         struct callout          xack_timer;     /* delayed ack timer */
  147         struct mbuf             *xwin[L2TP_MAX_XWIN];   /* transmit window */
  148         struct mtx              mtx;                    /* seq mutex */
  149 };
  150 
  151 /* Node private data */
  152 struct ng_l2tp_private {
  153         node_p                  node;           /* back pointer to node */
  154         hook_p                  ctrl;           /* hook to upper layers */
  155         hook_p                  lower;          /* hook to lower layers */
  156         struct ng_l2tp_config   conf;           /* node configuration */
  157         struct ng_l2tp_stats    stats;          /* node statistics */
  158         struct l2tp_seq         seq;            /* ctrl sequence number state */
  159         ng_ID_t                 ftarget;        /* failure message target */
  160         LIST_HEAD(, ng_l2tp_hook_private) sesshash[SESSHASHSIZE];
  161 };
  162 typedef struct ng_l2tp_private *priv_p;
  163 
  164 /* Netgraph node methods */
  165 static ng_constructor_t ng_l2tp_constructor;
  166 static ng_rcvmsg_t      ng_l2tp_rcvmsg;
  167 static ng_shutdown_t    ng_l2tp_shutdown;
  168 static ng_newhook_t     ng_l2tp_newhook;
  169 static ng_rcvdata_t     ng_l2tp_rcvdata;
  170 static ng_rcvdata_t     ng_l2tp_rcvdata_lower;
  171 static ng_rcvdata_t     ng_l2tp_rcvdata_ctrl;
  172 static ng_disconnect_t  ng_l2tp_disconnect;
  173 
  174 /* Internal functions */
  175 static int      ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns);
  176 
  177 static void     ng_l2tp_seq_init(priv_p priv);
  178 static int      ng_l2tp_seq_set(priv_p priv,
  179                         const struct ng_l2tp_seq_config *conf);
  180 static int      ng_l2tp_seq_adjust(priv_p priv,
  181                         const struct ng_l2tp_config *conf);
  182 static void     ng_l2tp_seq_reset(priv_p priv);
  183 static void     ng_l2tp_seq_failure(priv_p priv);
  184 static void     ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr);
  185 static void     ng_l2tp_seq_xack_timeout(void *);
  186 static void     ng_l2tp_seq_rack_timeout(void *);
  187 
  188 static hookpriv_p       ng_l2tp_find_session(priv_p privp, u_int16_t sid);
  189 static ng_fn_eachhook   ng_l2tp_reset_session;
  190 
  191 /* Parse type for struct ng_l2tp_seq_config. */
  192 static const struct ng_parse_struct_field
  193         ng_l2tp_seq_config_fields[] = NG_L2TP_SEQ_CONFIG_TYPE_INFO;
  194 static const struct ng_parse_type ng_l2tp_seq_config_type = {
  195         &ng_parse_struct_type,
  196         &ng_l2tp_seq_config_fields
  197 };
  198 
  199 /* Parse type for struct ng_l2tp_config */
  200 static const struct ng_parse_struct_field
  201         ng_l2tp_config_type_fields[] = NG_L2TP_CONFIG_TYPE_INFO;
  202 static const struct ng_parse_type ng_l2tp_config_type = {
  203         &ng_parse_struct_type,
  204         &ng_l2tp_config_type_fields,
  205 };
  206 
  207 /* Parse type for struct ng_l2tp_sess_config */
  208 static const struct ng_parse_struct_field
  209         ng_l2tp_sess_config_type_fields[] = NG_L2TP_SESS_CONFIG_TYPE_INFO;
  210 static const struct ng_parse_type ng_l2tp_sess_config_type = {
  211         &ng_parse_struct_type,
  212         &ng_l2tp_sess_config_type_fields,
  213 };
  214 
  215 /* Parse type for struct ng_l2tp_stats */
  216 static const struct ng_parse_struct_field
  217         ng_l2tp_stats_type_fields[] = NG_L2TP_STATS_TYPE_INFO;
  218 static const struct ng_parse_type ng_l2tp_stats_type = {
  219         &ng_parse_struct_type,
  220         &ng_l2tp_stats_type_fields
  221 };
  222 
  223 /* Parse type for struct ng_l2tp_session_stats. */
  224 static const struct ng_parse_struct_field
  225         ng_l2tp_session_stats_type_fields[] = NG_L2TP_SESSION_STATS_TYPE_INFO;
  226 static const struct ng_parse_type ng_l2tp_session_stats_type = {
  227         &ng_parse_struct_type,
  228         &ng_l2tp_session_stats_type_fields
  229 };
  230 
  231 /* List of commands and how to convert arguments to/from ASCII */
  232 static const struct ng_cmdlist ng_l2tp_cmdlist[] = {
  233         {
  234           NGM_L2TP_COOKIE,
  235           NGM_L2TP_SET_CONFIG,
  236           "setconfig",
  237           &ng_l2tp_config_type,
  238           NULL
  239         },
  240         {
  241           NGM_L2TP_COOKIE,
  242           NGM_L2TP_GET_CONFIG,
  243           "getconfig",
  244           NULL,
  245           &ng_l2tp_config_type
  246         },
  247         {
  248           NGM_L2TP_COOKIE,
  249           NGM_L2TP_SET_SESS_CONFIG,
  250           "setsessconfig",
  251           &ng_l2tp_sess_config_type,
  252           NULL
  253         },
  254         {
  255           NGM_L2TP_COOKIE,
  256           NGM_L2TP_GET_SESS_CONFIG,
  257           "getsessconfig",
  258           &ng_parse_hint16_type,
  259           &ng_l2tp_sess_config_type
  260         },
  261         {
  262           NGM_L2TP_COOKIE,
  263           NGM_L2TP_GET_STATS,
  264           "getstats",
  265           NULL,
  266           &ng_l2tp_stats_type
  267         },
  268         {
  269           NGM_L2TP_COOKIE,
  270           NGM_L2TP_CLR_STATS,
  271           "clrstats",
  272           NULL,
  273           NULL
  274         },
  275         {
  276           NGM_L2TP_COOKIE,
  277           NGM_L2TP_GETCLR_STATS,
  278           "getclrstats",
  279           NULL,
  280           &ng_l2tp_stats_type
  281         },
  282         {
  283           NGM_L2TP_COOKIE,
  284           NGM_L2TP_GET_SESSION_STATS,
  285           "getsessstats",
  286           &ng_parse_int16_type,
  287           &ng_l2tp_session_stats_type
  288         },
  289         {
  290           NGM_L2TP_COOKIE,
  291           NGM_L2TP_CLR_SESSION_STATS,
  292           "clrsessstats",
  293           &ng_parse_int16_type,
  294           NULL
  295         },
  296         {
  297           NGM_L2TP_COOKIE,
  298           NGM_L2TP_GETCLR_SESSION_STATS,
  299           "getclrsessstats",
  300           &ng_parse_int16_type,
  301           &ng_l2tp_session_stats_type
  302         },
  303         {
  304           NGM_L2TP_COOKIE,
  305           NGM_L2TP_ACK_FAILURE,
  306           "ackfailure",
  307           NULL,
  308           NULL
  309         },
  310         {
  311           NGM_L2TP_COOKIE,
  312           NGM_L2TP_SET_SEQ,
  313           "setsequence",
  314           &ng_l2tp_seq_config_type,
  315           NULL
  316         },
  317         { 0 }
  318 };
  319 
  320 /* Node type descriptor */
  321 static struct ng_type ng_l2tp_typestruct = {
  322         .version =      NG_ABI_VERSION,
  323         .name =         NG_L2TP_NODE_TYPE,
  324         .constructor =  ng_l2tp_constructor,
  325         .rcvmsg =       ng_l2tp_rcvmsg,
  326         .shutdown =     ng_l2tp_shutdown,
  327         .newhook =      ng_l2tp_newhook,
  328         .rcvdata =      ng_l2tp_rcvdata,
  329         .disconnect =   ng_l2tp_disconnect,
  330         .cmdlist =      ng_l2tp_cmdlist,
  331 };
  332 NETGRAPH_INIT(l2tp, &ng_l2tp_typestruct);
  333 
  334 /* Sequence number state locking & sanity checking */
  335 #ifdef INVARIANTS
  336 static void     ng_l2tp_seq_check(struct l2tp_seq *seq);
  337 #define SEQ_LOCK(seq)   do {                                    \
  338                                 mtx_lock(&(seq)->mtx);          \
  339                                 ng_l2tp_seq_check(seq);         \
  340 } while (0)
  341 #define SEQ_UNLOCK(seq) do {                                    \
  342                                 ng_l2tp_seq_check(seq);         \
  343                                 mtx_unlock(&(seq)->mtx);        \
  344 } while (0)
  345 #else
  346 #define SEQ_LOCK(seq)           mtx_lock(&(seq)->mtx)
  347 #define SEQ_UNLOCK(seq)         mtx_unlock(&(seq)->mtx)
  348 #endif
  349 #define SEQ_LOCK_ASSERT(seq)    mtx_assert(&(seq)->mtx, MA_OWNED)
  350 
  351 /* Whether to use m_copypacket() or m_dup() */
  352 #define L2TP_COPY_MBUF          m_copypacket
  353 
  354 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  355 
  356 /************************************************************************
  357                         NETGRAPH NODE STUFF
  358 ************************************************************************/
  359 
  360 /*
  361  * Node type constructor
  362  */
  363 static int
  364 ng_l2tp_constructor(node_p node)
  365 {
  366         priv_p priv;
  367         int     i;
  368 
  369         /* Allocate private structure */
  370         priv = malloc(sizeof(*priv), M_NETGRAPH_L2TP, M_WAITOK | M_ZERO);
  371         NG_NODE_SET_PRIVATE(node, priv);
  372         priv->node = node;
  373 
  374         /* Apply a semi-reasonable default configuration */
  375         priv->conf.peer_win = 1;
  376         priv->conf.rexmit_max = L2TP_MAX_REXMIT;
  377         priv->conf.rexmit_max_to = L2TP_MAX_REXMIT_TO;
  378 
  379         /* Initialize sequence number state */
  380         ng_l2tp_seq_init(priv);
  381 
  382         for (i = 0; i < SESSHASHSIZE; i++)
  383             LIST_INIT(&priv->sesshash[i]);
  384 
  385         /* Done */
  386         return (0);
  387 }
  388 
  389 /*
  390  * Give our OK for a hook to be added.
  391  */
  392 static int
  393 ng_l2tp_newhook(node_p node, hook_p hook, const char *name)
  394 {
  395         const priv_p priv = NG_NODE_PRIVATE(node);
  396 
  397         /* Check hook name */
  398         if (strcmp(name, NG_L2TP_HOOK_CTRL) == 0) {
  399                 if (priv->ctrl != NULL)
  400                         return (EISCONN);
  401                 priv->ctrl = hook;
  402                 NG_HOOK_SET_RCVDATA(hook, ng_l2tp_rcvdata_ctrl);
  403         } else if (strcmp(name, NG_L2TP_HOOK_LOWER) == 0) {
  404                 if (priv->lower != NULL)
  405                         return (EISCONN);
  406                 priv->lower = hook;
  407                 NG_HOOK_SET_RCVDATA(hook, ng_l2tp_rcvdata_lower);
  408         } else {
  409                 static const char hexdig[16] = "0123456789abcdef";
  410                 u_int16_t session_id;
  411                 hookpriv_p hpriv;
  412                 uint16_t hash;
  413                 const char *hex;
  414                 int i;
  415                 int j;
  416 
  417                 /* Parse hook name to get session ID */
  418                 if (strncmp(name, NG_L2TP_HOOK_SESSION_P,
  419                     sizeof(NG_L2TP_HOOK_SESSION_P) - 1) != 0)
  420                         return (EINVAL);
  421                 hex = name + sizeof(NG_L2TP_HOOK_SESSION_P) - 1;
  422                 for (session_id = i = 0; i < 4; i++) {
  423                         for (j = 0; j < 16 && hex[i] != hexdig[j]; j++);
  424                         if (j == 16)
  425                                 return (EINVAL);
  426                         session_id = (session_id << 4) | j;
  427                 }
  428                 if (hex[i] != '\0')
  429                         return (EINVAL);
  430 
  431                 /* Create hook private structure */
  432                 hpriv = malloc(sizeof(*hpriv),
  433                     M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO);
  434                 if (hpriv == NULL)
  435                         return (ENOMEM);
  436                 hpriv->conf.session_id = session_id;
  437                 hpriv->conf.control_dseq = L2TP_CONTROL_DSEQ;
  438                 hpriv->conf.enable_dseq = L2TP_ENABLE_DSEQ;
  439                 hpriv->hook = hook;
  440                 NG_HOOK_SET_PRIVATE(hook, hpriv);
  441                 hash = SESSHASH(hpriv->conf.session_id);
  442                 LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions);
  443         }
  444 
  445         /* Done */
  446         return (0);
  447 }
  448 
  449 /*
  450  * Receive a control message.
  451  */
  452 static int
  453 ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
  454 {
  455         const priv_p priv = NG_NODE_PRIVATE(node);
  456         struct ng_mesg *resp = NULL;
  457         struct ng_mesg *msg;
  458         int error = 0;
  459 
  460         NGI_GET_MSG(item, msg);
  461         switch (msg->header.typecookie) {
  462         case NGM_L2TP_COOKIE:
  463                 switch (msg->header.cmd) {
  464                 case NGM_L2TP_SET_CONFIG:
  465                     {
  466                         struct ng_l2tp_config *const conf =
  467                                 (struct ng_l2tp_config *)msg->data;
  468 
  469                         /* Check for invalid or illegal config */
  470                         if (msg->header.arglen != sizeof(*conf)) {
  471                                 error = EINVAL;
  472                                 break;
  473                         }
  474                         conf->enabled = !!conf->enabled;
  475                         conf->match_id = !!conf->match_id;
  476                         if (priv->conf.enabled
  477                             && ((priv->conf.tunnel_id != 0
  478                                && conf->tunnel_id != priv->conf.tunnel_id)
  479                               || ((priv->conf.peer_id != 0
  480                                && conf->peer_id != priv->conf.peer_id)))) {
  481                                 error = EBUSY;
  482                                 break;
  483                         }
  484 
  485                         /* Save calling node as failure target */
  486                         priv->ftarget = NGI_RETADDR(item);
  487 
  488                         /* Adjust sequence number state */
  489                         if ((error = ng_l2tp_seq_adjust(priv, conf)) != 0)
  490                                 break;
  491 
  492                         /* Update node's config */
  493                         priv->conf = *conf;
  494                         break;
  495                     }
  496                 case NGM_L2TP_GET_CONFIG:
  497                     {
  498                         struct ng_l2tp_config *conf;
  499 
  500                         NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT);
  501                         if (resp == NULL) {
  502                                 error = ENOMEM;
  503                                 break;
  504                         }
  505                         conf = (struct ng_l2tp_config *)resp->data;
  506                         *conf = priv->conf;
  507                         break;
  508                     }
  509                 case NGM_L2TP_SET_SESS_CONFIG:
  510                     {
  511                         struct ng_l2tp_sess_config *const conf =
  512                             (struct ng_l2tp_sess_config *)msg->data;
  513                         hookpriv_p hpriv;
  514 
  515                         /* Check for invalid or illegal config. */
  516                         if (msg->header.arglen != sizeof(*conf)) {
  517                                 error = EINVAL;
  518                                 break;
  519                         }
  520 
  521                         /* Find matching hook */
  522                         hpriv = ng_l2tp_find_session(priv, conf->session_id);
  523                         if (hpriv == NULL) {
  524                                 error = ENOENT;
  525                                 break;
  526                         }
  527 
  528                         /* Update hook's config */
  529                         hpriv->conf = *conf;
  530                         break;
  531                     }
  532                 case NGM_L2TP_GET_SESS_CONFIG:
  533                     {
  534                         struct ng_l2tp_sess_config *conf;
  535                         u_int16_t session_id;
  536                         hookpriv_p hpriv;
  537 
  538                         /* Get session ID */
  539                         if (msg->header.arglen != sizeof(session_id)) {
  540                                 error = EINVAL;
  541                                 break;
  542                         }
  543                         memcpy(&session_id, msg->data, 2);
  544 
  545                         /* Find matching hook */
  546                         hpriv = ng_l2tp_find_session(priv, session_id);
  547                         if (hpriv == NULL) {
  548                                 error = ENOENT;
  549                                 break;
  550                         }
  551 
  552                         /* Send response */
  553                         NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT);
  554                         if (resp == NULL) {
  555                                 error = ENOMEM;
  556                                 break;
  557                         }
  558                         conf = (struct ng_l2tp_sess_config *)resp->data;
  559                         *conf = hpriv->conf;
  560                         break;
  561                     }
  562                 case NGM_L2TP_GET_STATS:
  563                 case NGM_L2TP_CLR_STATS:
  564                 case NGM_L2TP_GETCLR_STATS:
  565                     {
  566                         if (msg->header.cmd != NGM_L2TP_CLR_STATS) {
  567                                 NG_MKRESPONSE(resp, msg,
  568                                     sizeof(priv->stats), M_NOWAIT);
  569                                 if (resp == NULL) {
  570                                         error = ENOMEM;
  571                                         break;
  572                                 }
  573                                 memcpy(resp->data,
  574                                     &priv->stats, sizeof(priv->stats));
  575                         }
  576                         if (msg->header.cmd != NGM_L2TP_GET_STATS)
  577                                 memset(&priv->stats, 0, sizeof(priv->stats));
  578                         break;
  579                     }
  580                 case NGM_L2TP_GET_SESSION_STATS:
  581                 case NGM_L2TP_CLR_SESSION_STATS:
  582                 case NGM_L2TP_GETCLR_SESSION_STATS:
  583                     {
  584                         uint16_t session_id;
  585                         hookpriv_p hpriv;
  586 
  587                         /* Get session ID. */
  588                         if (msg->header.arglen != sizeof(session_id)) {
  589                                 error = EINVAL;
  590                                 break;
  591                         }
  592                         bcopy(msg->data, &session_id, sizeof(uint16_t));
  593 
  594                         /* Find matching hook. */
  595                         hpriv = ng_l2tp_find_session(priv, session_id);
  596                         if (hpriv == NULL) {
  597                                 error = ENOENT;
  598                                 break;
  599                         }
  600 
  601                         if (msg->header.cmd != NGM_L2TP_CLR_SESSION_STATS) {
  602                                 NG_MKRESPONSE(resp, msg,
  603                                     sizeof(hpriv->stats), M_NOWAIT);
  604                                 if (resp == NULL) {
  605                                         error = ENOMEM;
  606                                         break;
  607                                 }
  608                                 bcopy(&hpriv->stats, resp->data,
  609                                         sizeof(hpriv->stats));
  610                         }
  611                         if (msg->header.cmd != NGM_L2TP_GET_SESSION_STATS)
  612                                 bzero(&hpriv->stats, sizeof(hpriv->stats));
  613                         break;
  614                     }
  615                 case NGM_L2TP_SET_SEQ:
  616                     {
  617                         struct ng_l2tp_seq_config *const conf =
  618                                 (struct ng_l2tp_seq_config *)msg->data;
  619 
  620                         /* Check for invalid or illegal seq config. */
  621                         if (msg->header.arglen != sizeof(*conf)) {
  622                                 error = EINVAL;
  623                                 break;
  624                         }
  625                         conf->ns = htons(conf->ns);
  626                         conf->nr = htons(conf->nr);
  627                         conf->rack = htons(conf->rack);
  628                         conf->xack = htons(conf->xack);
  629 
  630                         /* Set sequence numbers. */
  631                         error = ng_l2tp_seq_set(priv, conf);
  632                         break;
  633                     }
  634                 default:
  635                         error = EINVAL;
  636                         break;
  637                 }
  638                 break;
  639         default:
  640                 error = EINVAL;
  641                 break;
  642         }
  643 
  644         /* Done */
  645         NG_RESPOND_MSG(error, node, item, resp);
  646         NG_FREE_MSG(msg);
  647         return (error);
  648 }
  649 
  650 /*
  651  * Destroy node
  652  */
  653 static int
  654 ng_l2tp_shutdown(node_p node)
  655 {
  656         const priv_p priv = NG_NODE_PRIVATE(node);
  657         struct l2tp_seq *const seq = &priv->seq;
  658 
  659         /* Reset sequence number state */
  660         SEQ_LOCK(seq);
  661         ng_l2tp_seq_reset(priv);
  662         SEQ_UNLOCK(seq);
  663 
  664         /* Free private data if neither timer is running */
  665         callout_drain(&seq->rack_timer);
  666         callout_drain(&seq->xack_timer);
  667 
  668         mtx_destroy(&seq->mtx);
  669 
  670         free(priv, M_NETGRAPH_L2TP);
  671 
  672         /* Unref node */
  673         NG_NODE_UNREF(node);
  674         return (0);
  675 }
  676 
  677 /*
  678  * Hook disconnection
  679  */
  680 static int
  681 ng_l2tp_disconnect(hook_p hook)
  682 {
  683         const node_p node = NG_HOOK_NODE(hook);
  684         const priv_p priv = NG_NODE_PRIVATE(node);
  685 
  686         /* Zero out hook pointer */
  687         if (hook == priv->ctrl)
  688                 priv->ctrl = NULL;
  689         else if (hook == priv->lower)
  690                 priv->lower = NULL;
  691         else {
  692                 const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook);
  693                 LIST_REMOVE(hpriv, sessions);
  694                 free(hpriv, M_NETGRAPH_L2TP);
  695                 NG_HOOK_SET_PRIVATE(hook, NULL);
  696         }
  697 
  698         /* Go away if no longer connected to anything */
  699         if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node))
  700                 ng_rmnode_self(node);
  701         return (0);
  702 }
  703 
  704 /*************************************************************************
  705                         INTERNAL FUNCTIONS
  706 *************************************************************************/
  707 
  708 /*
  709  * Find the hook with a given session ID.
  710  */
  711 static hookpriv_p
  712 ng_l2tp_find_session(priv_p privp, u_int16_t sid)
  713 {
  714         uint16_t        hash = SESSHASH(sid);
  715         hookpriv_p      hpriv = NULL;
  716 
  717         LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) {
  718                 if (hpriv->conf.session_id == sid)
  719                         break;
  720         }
  721 
  722         return (hpriv);
  723 }
  724 
  725 /*
  726  * Reset a hook's session state.
  727  */
  728 static int
  729 ng_l2tp_reset_session(hook_p hook, void *arg)
  730 {
  731         const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook);
  732 
  733         if (hpriv != NULL) {
  734                 hpriv->conf.control_dseq = 0;
  735                 hpriv->conf.enable_dseq = 0;
  736                 bzero(&hpriv->stats, sizeof(struct ng_l2tp_session_stats));
  737                 hpriv->nr = 0;
  738                 hpriv->ns = 0;
  739         }
  740         return (-1);
  741 }
  742 
  743 /*
  744  * Handle an incoming frame from below.
  745  */
  746 static int
  747 ng_l2tp_rcvdata_lower(hook_p h, item_p item)
  748 {
  749         static const u_int16_t req_bits[2][2] = {
  750                 { L2TP_DATA_0BITS, L2TP_DATA_1BITS },
  751                 { L2TP_CTRL_0BITS, L2TP_CTRL_1BITS },
  752         };
  753         const node_p node = NG_HOOK_NODE(h);
  754         const priv_p priv = NG_NODE_PRIVATE(node);
  755         hookpriv_p hpriv = NULL;
  756         hook_p hook = NULL;
  757         struct mbuf *m;
  758         u_int16_t tid, sid;
  759         u_int16_t hdr;
  760         u_int16_t ns, nr;
  761         int is_ctrl;
  762         int error;
  763         int len, plen;
  764 
  765         /* If not configured, reject */
  766         if (!priv->conf.enabled) {
  767                 NG_FREE_ITEM(item);
  768                 ERROUT(ENXIO);
  769         }
  770 
  771         /* Grab mbuf */
  772         NGI_GET_M(item, m);
  773 
  774         /* Remember full packet length; needed for per session accounting. */
  775         plen = m->m_pkthdr.len;
  776 
  777         /* Update stats */
  778         priv->stats.recvPackets++;
  779         priv->stats.recvOctets += plen;
  780 
  781         /* Get initial header */
  782         if (m->m_pkthdr.len < 6) {
  783                 priv->stats.recvRunts++;
  784                 NG_FREE_ITEM(item);
  785                 NG_FREE_M(m);
  786                 ERROUT(EINVAL);
  787         }
  788         if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) {
  789                 priv->stats.memoryFailures++;
  790                 NG_FREE_ITEM(item);
  791                 ERROUT(EINVAL);
  792         }
  793         hdr = (mtod(m, uint8_t *)[0] << 8) + mtod(m, uint8_t *)[1];
  794         m_adj(m, 2);
  795 
  796         /* Check required header bits and minimum length */
  797         is_ctrl = (hdr & L2TP_HDR_CTRL) != 0;
  798         if ((hdr & req_bits[is_ctrl][0]) != 0
  799             || (~hdr & req_bits[is_ctrl][1]) != 0) {
  800                 priv->stats.recvInvalid++;
  801                 NG_FREE_ITEM(item);
  802                 NG_FREE_M(m);
  803                 ERROUT(EINVAL);
  804         }
  805         if (m->m_pkthdr.len < 4                         /* tunnel, session id */
  806             + (2 * ((hdr & L2TP_HDR_LEN) != 0))         /* length field */
  807             + (4 * ((hdr & L2TP_HDR_SEQ) != 0))         /* seq # fields */
  808             + (2 * ((hdr & L2TP_HDR_OFF) != 0))) {      /* offset field */
  809                 priv->stats.recvRunts++;
  810                 NG_FREE_ITEM(item);
  811                 NG_FREE_M(m);
  812                 ERROUT(EINVAL);
  813         }
  814 
  815         /* Get and validate length field if present */
  816         if ((hdr & L2TP_HDR_LEN) != 0) {
  817                 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) {
  818                         priv->stats.memoryFailures++;
  819                         NG_FREE_ITEM(item);
  820                         ERROUT(EINVAL);
  821                 }
  822                 len = (mtod(m, uint8_t *)[0] << 8) + mtod(m, uint8_t *)[1] - 4;
  823                 m_adj(m, 2);
  824                 if (len < 0 || len > m->m_pkthdr.len) {
  825                         priv->stats.recvInvalid++;
  826                         NG_FREE_ITEM(item);
  827                         NG_FREE_M(m);
  828                         ERROUT(EINVAL);
  829                 }
  830                 if (len < m->m_pkthdr.len)              /* trim extra bytes */
  831                         m_adj(m, -(m->m_pkthdr.len - len));
  832         }
  833 
  834         /* Get tunnel ID and session ID */
  835         if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
  836                 priv->stats.memoryFailures++;
  837                 NG_FREE_ITEM(item);
  838                 ERROUT(EINVAL);
  839         }
  840         tid = (mtod(m, u_int8_t *)[0] << 8) + mtod(m, u_int8_t *)[1];
  841         sid = (mtod(m, u_int8_t *)[2] << 8) + mtod(m, u_int8_t *)[3];
  842         m_adj(m, 4);
  843 
  844         /* Check tunnel ID */
  845         if (tid != priv->conf.tunnel_id &&
  846             (priv->conf.match_id || tid != 0)) {
  847                 priv->stats.recvWrongTunnel++;
  848                 NG_FREE_ITEM(item);
  849                 NG_FREE_M(m);
  850                 ERROUT(EADDRNOTAVAIL);
  851         }
  852 
  853         /* Check session ID (for data packets only) */
  854         if ((hdr & L2TP_HDR_CTRL) == 0) {
  855                 hpriv = ng_l2tp_find_session(priv, sid);
  856                 if (hpriv == NULL) {
  857                         priv->stats.recvUnknownSID++;
  858                         NG_FREE_ITEM(item);
  859                         NG_FREE_M(m);
  860                         ERROUT(ENOTCONN);
  861                 }
  862                 hook = hpriv->hook;
  863         }
  864 
  865         /* Get Ns, Nr fields if present */
  866         if ((hdr & L2TP_HDR_SEQ) != 0) {
  867                 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
  868                         priv->stats.memoryFailures++;
  869                         NG_FREE_ITEM(item);
  870                         ERROUT(EINVAL);
  871                 }
  872                 ns = (mtod(m, u_int8_t *)[0] << 8) + mtod(m, u_int8_t *)[1];
  873                 nr = (mtod(m, u_int8_t *)[2] << 8) + mtod(m, u_int8_t *)[3];
  874                 m_adj(m, 4);
  875         } else
  876                 ns = nr = 0;
  877 
  878         /* Strip offset padding if present */
  879         if ((hdr & L2TP_HDR_OFF) != 0) {
  880                 u_int16_t offset;
  881 
  882                 /* Get length of offset padding */
  883                 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) {
  884                         priv->stats.memoryFailures++;
  885                         NG_FREE_ITEM(item);
  886                         ERROUT(EINVAL);
  887                 }
  888                 offset = (mtod(m, u_int8_t *)[0] << 8) + mtod(m, u_int8_t *)[1];
  889 
  890                 /* Trim offset padding */
  891                 if ((2+offset) > m->m_pkthdr.len) {
  892                         priv->stats.recvInvalid++;
  893                         NG_FREE_ITEM(item);
  894                         NG_FREE_M(m);
  895                         ERROUT(EINVAL);
  896                 }
  897                 m_adj(m, 2+offset);
  898         }
  899 
  900         /* Handle control packets */
  901         if ((hdr & L2TP_HDR_CTRL) != 0) {
  902                 struct l2tp_seq *const seq = &priv->seq;
  903 
  904                 SEQ_LOCK(seq);
  905 
  906                 /* Handle receive ack sequence number Nr */
  907                 ng_l2tp_seq_recv_nr(priv, nr);
  908 
  909                 /* Discard ZLB packets */
  910                 if (m->m_pkthdr.len == 0) {
  911                         SEQ_UNLOCK(seq);
  912                         priv->stats.recvZLBs++;
  913                         NG_FREE_ITEM(item);
  914                         NG_FREE_M(m);
  915                         ERROUT(0);
  916                 }
  917 
  918                 /*
  919                  * If not what we expect or we are busy, drop packet and
  920                  * send an immediate ZLB ack.
  921                  */
  922                 if (ns != seq->nr || seq->inproc) {
  923                         if (L2TP_SEQ_DIFF(ns, seq->nr) <= 0)
  924                                 priv->stats.recvDuplicates++;
  925                         else
  926                                 priv->stats.recvOutOfOrder++;
  927                         ng_l2tp_xmit_ctrl(priv, NULL, seq->ns);
  928                         NG_FREE_ITEM(item);
  929                         NG_FREE_M(m);
  930                         ERROUT(0);
  931                 }
  932 
  933                 /* Prepend session ID to packet. */
  934                 M_PREPEND(m, 2, M_NOWAIT);
  935                 if (m == NULL) {
  936                         SEQ_UNLOCK(seq);
  937                         priv->stats.memoryFailures++;
  938                         NG_FREE_ITEM(item);
  939                         ERROUT(ENOBUFS);
  940                 }
  941                 mtod(m, u_int8_t *)[0] = sid >> 8;
  942                 mtod(m, u_int8_t *)[1] = sid & 0xff;
  943 
  944                 /*
  945                  * Until we deliver this packet we can't receive next one as
  946                  * we have no information for sending ack.
  947                  */
  948                 seq->inproc = 1;
  949                 SEQ_UNLOCK(seq);
  950 
  951                 /* Deliver packet to upper layers */
  952                 NG_FWD_NEW_DATA(error, item, priv->ctrl, m);
  953                 
  954                 SEQ_LOCK(seq);
  955                 /* Ready to process next packet. */
  956                 seq->inproc = 0;
  957 
  958                 /* If packet was successfully delivered send ack. */
  959                 if (error == 0) {
  960                         /* Update recv sequence number */
  961                         seq->nr++;
  962                         /* Start receive ack timer, if not already running */
  963                         if (!callout_active(&seq->xack_timer)) {
  964                                 callout_reset(&seq->xack_timer,
  965                                     L2TP_DELAYED_ACK, ng_l2tp_seq_xack_timeout,
  966                                     node);
  967                         }
  968                 }
  969                 SEQ_UNLOCK(seq);
  970 
  971                 ERROUT(error);
  972         }
  973 
  974         /* Per session packet, account it. */
  975         hpriv->stats.recvPackets++;
  976         hpriv->stats.recvOctets += plen;
  977 
  978         /* Follow peer's lead in data sequencing, if configured to do so */
  979         if (!hpriv->conf.control_dseq)
  980                 hpriv->conf.enable_dseq = ((hdr & L2TP_HDR_SEQ) != 0);
  981 
  982         /* Handle data sequence numbers if present and enabled */
  983         if ((hdr & L2TP_HDR_SEQ) != 0) {
  984                 if (hpriv->conf.enable_dseq
  985                     && L2TP_SEQ_DIFF(ns, hpriv->nr) < 0) {
  986                         NG_FREE_ITEM(item);     /* duplicate or out of order */
  987                         NG_FREE_M(m);
  988                         priv->stats.recvDataDrops++;
  989                         ERROUT(0);
  990                 }
  991                 hpriv->nr = ns + 1;
  992         }
  993 
  994         /* Drop empty data packets */
  995         if (m->m_pkthdr.len == 0) {
  996                 NG_FREE_ITEM(item);
  997                 NG_FREE_M(m);
  998                 ERROUT(0);
  999         }
 1000 
 1001         /* Deliver data */
 1002         NG_FWD_NEW_DATA(error, item, hook, m);
 1003 done:
 1004         return (error);
 1005 }
 1006 
 1007 /*
 1008  * Handle an outgoing control frame.
 1009  */
 1010 static int
 1011 ng_l2tp_rcvdata_ctrl(hook_p hook, item_p item)
 1012 {
 1013         const node_p node = NG_HOOK_NODE(hook);
 1014         const priv_p priv = NG_NODE_PRIVATE(node);
 1015         struct l2tp_seq *const seq = &priv->seq;
 1016         struct mbuf *m;
 1017         int error;
 1018         int i;
 1019         u_int16_t       ns;
 1020 
 1021         /* If not configured, reject */
 1022         if (!priv->conf.enabled) {
 1023                 NG_FREE_ITEM(item);
 1024                 ERROUT(ENXIO);
 1025         }
 1026 
 1027         /* Grab mbuf and discard other stuff XXX */
 1028         NGI_GET_M(item, m);
 1029         NG_FREE_ITEM(item);
 1030 
 1031         /* Packet should have session ID prepended */
 1032         if (m->m_pkthdr.len < 2) {
 1033                 priv->stats.xmitInvalid++;
 1034                 m_freem(m);
 1035                 ERROUT(EINVAL);
 1036         }
 1037 
 1038         /* Check max length */
 1039         if (m->m_pkthdr.len >= 0x10000 - 14) {
 1040                 priv->stats.xmitTooBig++;
 1041                 m_freem(m);
 1042                 ERROUT(EOVERFLOW);
 1043         }
 1044 
 1045         SEQ_LOCK(seq);
 1046 
 1047         /* Find next empty slot in transmit queue */
 1048         for (i = 0; i < L2TP_MAX_XWIN && seq->xwin[i] != NULL; i++);
 1049         if (i == L2TP_MAX_XWIN) {
 1050                 SEQ_UNLOCK(seq);
 1051                 priv->stats.xmitDrops++;
 1052                 m_freem(m);
 1053                 ERROUT(ENOBUFS);
 1054         }
 1055         seq->xwin[i] = m;
 1056 
 1057         /* If peer's receive window is already full, nothing else to do */
 1058         if (i >= seq->cwnd) {
 1059                 SEQ_UNLOCK(seq);
 1060                 ERROUT(0);
 1061         }
 1062 
 1063         /* Start retransmit timer if not already running */
 1064         if (!callout_active(&seq->rack_timer))
 1065                 callout_reset(&seq->rack_timer, hz, ng_l2tp_seq_rack_timeout,
 1066                     node);
 1067 
 1068         ns = seq->ns++;
 1069 
 1070         /* Copy packet */
 1071         if ((m = L2TP_COPY_MBUF(m, M_NOWAIT)) == NULL) {
 1072                 SEQ_UNLOCK(seq);
 1073                 priv->stats.memoryFailures++;
 1074                 ERROUT(ENOBUFS);
 1075         }
 1076 
 1077         /* Send packet and increment xmit sequence number */
 1078         error = ng_l2tp_xmit_ctrl(priv, m, ns);
 1079 done:
 1080         return (error);
 1081 }
 1082 
 1083 /*
 1084  * Handle an outgoing data frame.
 1085  */
 1086 static int
 1087 ng_l2tp_rcvdata(hook_p hook, item_p item)
 1088 {
 1089         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
 1090         const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook);
 1091         struct mbuf *m;
 1092         uint8_t *p;
 1093         u_int16_t hdr;
 1094         int error;
 1095         int i = 2;
 1096 
 1097         /* If not configured, reject */
 1098         if (!priv->conf.enabled) {
 1099                 NG_FREE_ITEM(item);
 1100                 ERROUT(ENXIO);
 1101         }
 1102 
 1103         /* Get mbuf */
 1104         NGI_GET_M(item, m);
 1105 
 1106         /* Check max length */
 1107         if (m->m_pkthdr.len >= 0x10000 - 12) {
 1108                 priv->stats.xmitDataTooBig++;
 1109                 NG_FREE_ITEM(item);
 1110                 NG_FREE_M(m);
 1111                 ERROUT(EOVERFLOW);
 1112         }
 1113 
 1114         /* Prepend L2TP header */
 1115         M_PREPEND(m, 6
 1116             + (2 * (hpriv->conf.include_length != 0))
 1117             + (4 * (hpriv->conf.enable_dseq != 0)),
 1118             M_NOWAIT);
 1119         if (m == NULL) {
 1120                 priv->stats.memoryFailures++;
 1121                 NG_FREE_ITEM(item);
 1122                 ERROUT(ENOBUFS);
 1123         }
 1124         p = mtod(m, uint8_t *);
 1125         hdr = L2TP_DATA_HDR;
 1126         if (hpriv->conf.include_length) {
 1127                 hdr |= L2TP_HDR_LEN;
 1128                 p[i++] = m->m_pkthdr.len >> 8;
 1129                 p[i++] = m->m_pkthdr.len & 0xff;
 1130         }
 1131         p[i++] = priv->conf.peer_id >> 8;
 1132         p[i++] = priv->conf.peer_id & 0xff;
 1133         p[i++] = hpriv->conf.peer_id >> 8;
 1134         p[i++] = hpriv->conf.peer_id & 0xff;
 1135         if (hpriv->conf.enable_dseq) {
 1136                 hdr |= L2TP_HDR_SEQ;
 1137                 p[i++] = hpriv->ns >> 8;
 1138                 p[i++] = hpriv->ns & 0xff;
 1139                 p[i++] = hpriv->nr >> 8;
 1140                 p[i++] = hpriv->nr & 0xff;
 1141                 hpriv->ns++;
 1142         }
 1143         p[0] = hdr >> 8;
 1144         p[1] = hdr & 0xff;
 1145 
 1146         /* Update per session stats. */
 1147         hpriv->stats.xmitPackets++;
 1148         hpriv->stats.xmitOctets += m->m_pkthdr.len;
 1149 
 1150         /* And the global one. */
 1151         priv->stats.xmitPackets++;
 1152         priv->stats.xmitOctets += m->m_pkthdr.len;
 1153 
 1154         /* Send packet */
 1155         NG_FWD_NEW_DATA(error, item, priv->lower, m);
 1156 done:
 1157         return (error);
 1158 }
 1159 
 1160 /*
 1161  * Send a message to our controlling node that we've failed.
 1162  */
 1163 static void
 1164 ng_l2tp_seq_failure(priv_p priv)
 1165 {
 1166         struct ng_mesg *msg;
 1167         int error;
 1168 
 1169         NG_MKMESSAGE(msg, NGM_L2TP_COOKIE, NGM_L2TP_ACK_FAILURE, 0, M_NOWAIT);
 1170         if (msg == NULL)
 1171                 return;
 1172         NG_SEND_MSG_ID(error, priv->node, msg, priv->ftarget, 0);
 1173 }
 1174 
 1175 /************************************************************************
 1176                         SEQUENCE NUMBER HANDLING
 1177 ************************************************************************/
 1178 
 1179 /*
 1180  * Initialize sequence number state.
 1181  */
 1182 static void
 1183 ng_l2tp_seq_init(priv_p priv)
 1184 {
 1185         struct l2tp_seq *const seq = &priv->seq;
 1186 
 1187         KASSERT(priv->conf.peer_win >= 1,
 1188             ("%s: peer_win is zero", __func__));
 1189         memset(seq, 0, sizeof(*seq));
 1190         seq->cwnd = 1;
 1191         seq->wmax = priv->conf.peer_win;
 1192         if (seq->wmax > L2TP_MAX_XWIN)
 1193                 seq->wmax = L2TP_MAX_XWIN;
 1194         seq->ssth = seq->wmax;
 1195         mtx_init(&seq->mtx, "ng_l2tp", NULL, MTX_DEF);
 1196         callout_init_mtx(&seq->rack_timer, &seq->mtx, CALLOUT_RETURNUNLOCKED);
 1197         callout_init_mtx(&seq->xack_timer, &seq->mtx, CALLOUT_RETURNUNLOCKED);
 1198 }
 1199 
 1200 /*
 1201  * Set sequence number state as given from user.
 1202  */
 1203 static int
 1204 ng_l2tp_seq_set(priv_p priv, const struct ng_l2tp_seq_config *conf)
 1205 {
 1206         struct l2tp_seq *const seq = &priv->seq;
 1207 
 1208         /* If node is enabled, deny update to sequence numbers. */
 1209         if (priv->conf.enabled)
 1210                 return (EBUSY);
 1211 
 1212         /* We only can handle the simple cases. */
 1213         if (conf->xack != conf->nr || conf->ns != conf->rack)
 1214                 return (EINVAL);
 1215 
 1216         /* Set ns,nr,rack,xack parameters. */
 1217         seq->ns = conf->ns;
 1218         seq->nr = conf->nr;
 1219         seq->rack = conf->rack;
 1220         seq->xack = conf->xack;
 1221 
 1222         return (0);
 1223 }
 1224 
 1225 /*
 1226  * Adjust sequence number state accordingly after reconfiguration.
 1227  */
 1228 static int
 1229 ng_l2tp_seq_adjust(priv_p priv, const struct ng_l2tp_config *conf)
 1230 {
 1231         struct l2tp_seq *const seq = &priv->seq;
 1232         u_int16_t new_wmax;
 1233         int error = 0;
 1234 
 1235         SEQ_LOCK(seq);
 1236         /* If disabling node, reset state sequence number */
 1237         if (!conf->enabled) {
 1238                 ng_l2tp_seq_reset(priv);
 1239                 SEQ_UNLOCK(seq);
 1240                 return (0);
 1241         }
 1242 
 1243         /* Adjust peer's max recv window; it can only increase */
 1244         new_wmax = conf->peer_win;
 1245         if (new_wmax > L2TP_MAX_XWIN)
 1246                 new_wmax = L2TP_MAX_XWIN;
 1247         if (new_wmax == 0)
 1248                 ERROUT(EINVAL);
 1249         if (new_wmax < seq->wmax)
 1250                 ERROUT(EBUSY);
 1251         seq->wmax = new_wmax;
 1252 
 1253 done:
 1254         SEQ_UNLOCK(seq);
 1255         return (error);
 1256 }
 1257 
 1258 /*
 1259  * Reset sequence number state.
 1260  */
 1261 static void
 1262 ng_l2tp_seq_reset(priv_p priv)
 1263 {
 1264         struct l2tp_seq *const seq = &priv->seq;
 1265         hook_p hook;
 1266         int i;
 1267 
 1268         SEQ_LOCK_ASSERT(seq);
 1269 
 1270         /* Stop timers */
 1271         (void )callout_stop(&seq->rack_timer);
 1272         (void )callout_stop(&seq->xack_timer);
 1273 
 1274         /* Free retransmit queue */
 1275         for (i = 0; i < L2TP_MAX_XWIN; i++) {
 1276                 if (seq->xwin[i] == NULL)
 1277                         break;
 1278                 m_freem(seq->xwin[i]);
 1279         }
 1280 
 1281         /* Reset session hooks' sequence number states */
 1282         NG_NODE_FOREACH_HOOK(priv->node, ng_l2tp_reset_session, NULL, hook);
 1283 
 1284         /* Reset node's sequence number state */
 1285         seq->ns = 0;
 1286         seq->nr = 0;
 1287         seq->rack = 0;
 1288         seq->xack = 0;
 1289         seq->wmax = L2TP_MAX_XWIN;
 1290         seq->cwnd = 1;
 1291         seq->ssth = seq->wmax;
 1292         seq->acks = 0;
 1293         seq->rexmits = 0;
 1294         bzero(seq->xwin, sizeof(seq->xwin));
 1295 }
 1296 
 1297 /*
 1298  * Handle receipt of an acknowledgement value (Nr) from peer.
 1299  */
 1300 static void
 1301 ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr)
 1302 {
 1303         struct l2tp_seq *const seq = &priv->seq;
 1304         struct mbuf     *xwin[L2TP_MAX_XWIN];   /* partial local copy */
 1305         int             nack;
 1306         int             i, j;
 1307         uint16_t        ns;
 1308 
 1309         SEQ_LOCK_ASSERT(seq);
 1310 
 1311         /* Verify peer's ACK is in range */
 1312         if ((nack = L2TP_SEQ_DIFF(nr, seq->rack)) <= 0)
 1313                 return;                         /* duplicate ack */
 1314         if (L2TP_SEQ_DIFF(nr, seq->ns) > 0) {
 1315                 priv->stats.recvBadAcks++;      /* ack for packet not sent */
 1316                 return;
 1317         }
 1318         KASSERT(nack <= L2TP_MAX_XWIN,
 1319             ("%s: nack=%d > %d", __func__, nack, L2TP_MAX_XWIN));
 1320 
 1321         /* Update receive ack stats */
 1322         seq->rack = nr;
 1323         seq->rexmits = 0;
 1324 
 1325         /* Free acknowledged packets and shift up packets in the xmit queue */
 1326         for (i = 0; i < nack; i++)
 1327                 m_freem(seq->xwin[i]);
 1328         memmove(seq->xwin, seq->xwin + nack,
 1329             (L2TP_MAX_XWIN - nack) * sizeof(*seq->xwin));
 1330         memset(seq->xwin + (L2TP_MAX_XWIN - nack), 0,
 1331             nack * sizeof(*seq->xwin));
 1332 
 1333         /*
 1334          * Do slow-start/congestion avoidance windowing algorithm described
 1335          * in RFC 2661, Appendix A. Here we handle a multiple ACK as if each
 1336          * ACK had arrived separately.
 1337          */
 1338         if (seq->cwnd < seq->wmax) {
 1339                 /* Handle slow start phase */
 1340                 if (seq->cwnd < seq->ssth) {
 1341                         seq->cwnd += nack;
 1342                         nack = 0;
 1343                         if (seq->cwnd > seq->ssth) {    /* into cg.av. phase */
 1344                                 nack = seq->cwnd - seq->ssth;
 1345                                 seq->cwnd = seq->ssth;
 1346                         }
 1347                 }
 1348 
 1349                 /* Handle congestion avoidance phase */
 1350                 if (seq->cwnd >= seq->ssth) {
 1351                         seq->acks += nack;
 1352                         while (seq->acks >= seq->cwnd) {
 1353                                 seq->acks -= seq->cwnd;
 1354                                 if (seq->cwnd < seq->wmax)
 1355                                         seq->cwnd++;
 1356                         }
 1357                 }
 1358         }
 1359 
 1360         /* Stop xmit timer */
 1361         if (callout_active(&seq->rack_timer))
 1362                 (void )callout_stop(&seq->rack_timer);
 1363 
 1364         /* If transmit queue is empty, we're done for now */
 1365         if (seq->xwin[0] == NULL)
 1366                 return;
 1367 
 1368         /* Start restransmit timer again */
 1369         callout_reset(&seq->rack_timer, hz, ng_l2tp_seq_rack_timeout,
 1370             priv->node);
 1371 
 1372         /*
 1373          * Send more packets, trying to keep peer's receive window full.
 1374          * Make copy of everything we need before lock release.
 1375          */
 1376         ns = seq->ns;
 1377         j = 0;
 1378         while ((i = L2TP_SEQ_DIFF(seq->ns, seq->rack)) < seq->cwnd
 1379             && seq->xwin[i] != NULL) {
 1380                 xwin[j++] = seq->xwin[i];
 1381                 seq->ns++;
 1382         }
 1383 
 1384         /*
 1385          * Send prepared.
 1386          * If there is a memory error, pretend packet was sent, as it
 1387          * will get retransmitted later anyway.
 1388          */
 1389         for (i = 0; i < j; i++) {
 1390                 struct mbuf     *m;
 1391                 if ((m = L2TP_COPY_MBUF(xwin[i], M_NOWAIT)) == NULL)
 1392                         priv->stats.memoryFailures++;
 1393                 else {
 1394                         ng_l2tp_xmit_ctrl(priv, m, ns);
 1395                         SEQ_LOCK(seq);
 1396                 }
 1397                 ns++;
 1398         }
 1399 }
 1400 
 1401 /*
 1402  * Handle an ack timeout. We have an outstanding ack that we
 1403  * were hoping to piggy-back, but haven't, so send a ZLB.
 1404  */
 1405 static void
 1406 ng_l2tp_seq_xack_timeout(void *arg)
 1407 {
 1408         const node_p node = arg;
 1409         const priv_p priv = NG_NODE_PRIVATE(node);
 1410         struct l2tp_seq *const seq = &priv->seq;
 1411 
 1412         SEQ_LOCK_ASSERT(seq);
 1413         MPASS(!callout_pending(&seq->xack_timer));
 1414         MPASS(callout_active(&seq->xack_timer));
 1415 
 1416         CURVNET_SET(node->nd_vnet);
 1417         /* Send a ZLB */
 1418         ng_l2tp_xmit_ctrl(priv, NULL, seq->ns);
 1419         CURVNET_RESTORE();
 1420 
 1421         /* callout_deactivate() is not needed here 
 1422             as callout_stop() was called by ng_l2tp_xmit_ctrl() */
 1423 }
 1424 
 1425 /* 
 1426  * Handle a transmit timeout. The peer has failed to respond
 1427  * with an ack for our packet, so retransmit it.
 1428  */
 1429 static void
 1430 ng_l2tp_seq_rack_timeout(void *arg)
 1431 {
 1432         const node_p node = arg;
 1433         const priv_p priv = NG_NODE_PRIVATE(node);
 1434         struct l2tp_seq *const seq = &priv->seq;
 1435         struct mbuf *m;
 1436         u_int delay;
 1437 
 1438         SEQ_LOCK_ASSERT(seq);
 1439         MPASS(seq->xwin[0]);
 1440         MPASS(!callout_pending(&seq->rack_timer));
 1441         MPASS(callout_active(&seq->rack_timer));
 1442 
 1443         CURVNET_SET(node->nd_vnet);
 1444 
 1445         priv->stats.xmitRetransmits++;
 1446 
 1447         /* Have we reached the retransmit limit? If so, notify owner. */
 1448         if (seq->rexmits++ >= priv->conf.rexmit_max)
 1449                 ng_l2tp_seq_failure(priv);
 1450 
 1451         /* Restart timer, this time with an increased delay */
 1452         delay = (seq->rexmits > 12) ? (1 << 12) : (1 << seq->rexmits);
 1453         if (delay > priv->conf.rexmit_max_to)
 1454                 delay = priv->conf.rexmit_max_to;
 1455         callout_reset(&seq->rack_timer, hz * delay, ng_l2tp_seq_rack_timeout,
 1456             node);
 1457 
 1458         /* Do slow-start/congestion algorithm windowing algorithm */
 1459         seq->ns = seq->rack;
 1460         seq->ssth = (seq->cwnd + 1) / 2;
 1461         seq->cwnd = 1;
 1462         seq->acks = 0;
 1463 
 1464         /* Retransmit oldest unack'd packet */
 1465         m = L2TP_COPY_MBUF(seq->xwin[0], M_NOWAIT);
 1466         if (m == NULL) {
 1467                 SEQ_UNLOCK(seq);
 1468                 priv->stats.memoryFailures++;
 1469         } else
 1470                 ng_l2tp_xmit_ctrl(priv, m, seq->ns++);
 1471 
 1472         CURVNET_RESTORE();
 1473 
 1474         /* callout_deactivate() is not needed here 
 1475             as ng_callout() is getting called each time */
 1476 }
 1477 
 1478 /*
 1479  * Transmit a control stream packet, payload optional.
 1480  * The transmit sequence number is not incremented.
 1481  * Requires seq lock, returns unlocked.
 1482  */
 1483 static int
 1484 ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
 1485 {
 1486         struct l2tp_seq *const seq = &priv->seq;
 1487         uint8_t *p;
 1488         uint16_t nr, session_id = 0;
 1489         int error;
 1490 
 1491         SEQ_LOCK_ASSERT(seq);
 1492 
 1493         /* Stop ack timer: we're sending an ack with this packet.
 1494            Doing this before to keep state predictable after error. */
 1495         if (callout_active(&seq->xack_timer))
 1496                 (void )callout_stop(&seq->xack_timer);
 1497 
 1498         nr = seq->xack = seq->nr;
 1499 
 1500         SEQ_UNLOCK(seq);
 1501 
 1502         /* If no mbuf passed, send an empty packet (ZLB) */
 1503         if (m == NULL) {
 1504                 /* Create a new mbuf for ZLB packet */
 1505                 MGETHDR(m, M_NOWAIT, MT_DATA);
 1506                 if (m == NULL) {
 1507                         priv->stats.memoryFailures++;
 1508                         return (ENOBUFS);
 1509                 }
 1510                 m->m_len = m->m_pkthdr.len = 12;
 1511                 m->m_pkthdr.rcvif = NULL;
 1512                 priv->stats.xmitZLBs++;
 1513         } else {
 1514                 /* Strip off session ID */
 1515                 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) {
 1516                         priv->stats.memoryFailures++;
 1517                         return (ENOBUFS);
 1518                 }
 1519                 session_id = (mtod(m, u_int8_t *)[0] << 8) + mtod(m, u_int8_t *)[1];
 1520 
 1521                 /* Make room for L2TP header */
 1522                 M_PREPEND(m, 10, M_NOWAIT);     /* - 2 + 12 = 10 */
 1523                 if (m == NULL) {
 1524                         priv->stats.memoryFailures++;
 1525                         return (ENOBUFS);
 1526                 }
 1527 
 1528                 /*
 1529                  * The below requires 12 contiguous bytes for the L2TP header
 1530                  * to be written into.
 1531                  */
 1532                 m = m_pullup(m, 12);
 1533                 if (m == NULL) {
 1534                         priv->stats.memoryFailures++;
 1535                         return (ENOBUFS);
 1536                 }
 1537         }
 1538 
 1539         /* Fill in L2TP header */
 1540         p = mtod(m, u_int8_t *);
 1541         p[0] = L2TP_CTRL_HDR >> 8;
 1542         p[1] = L2TP_CTRL_HDR & 0xff;
 1543         p[2] = m->m_pkthdr.len >> 8;
 1544         p[3] = m->m_pkthdr.len & 0xff;
 1545         p[4] = priv->conf.peer_id >> 8;
 1546         p[5] = priv->conf.peer_id & 0xff;
 1547         p[6] = session_id >> 8;
 1548         p[7] = session_id & 0xff;
 1549         p[8] = ns >> 8;
 1550         p[9] = ns & 0xff;
 1551         p[10] = nr >> 8;
 1552         p[11] = nr & 0xff;
 1553 
 1554         /* Update sequence number info and stats */
 1555         priv->stats.xmitPackets++;
 1556         priv->stats.xmitOctets += m->m_pkthdr.len;
 1557 
 1558         /* Send packet */
 1559         NG_SEND_DATA_ONLY(error, priv->lower, m);
 1560         return (error);
 1561 }
 1562 
 1563 #ifdef INVARIANTS
 1564 /*
 1565  * Sanity check sequence number state.
 1566  */
 1567 static void
 1568 ng_l2tp_seq_check(struct l2tp_seq *seq)
 1569 {
 1570         int self_unack, peer_unack;
 1571         int i;
 1572 
 1573 #define CHECK(p)        KASSERT((p), ("%s: not: %s", __func__, #p))
 1574 
 1575         SEQ_LOCK_ASSERT(seq);
 1576 
 1577         self_unack = L2TP_SEQ_DIFF(seq->nr, seq->xack);
 1578         peer_unack = L2TP_SEQ_DIFF(seq->ns, seq->rack);
 1579         CHECK(seq->wmax <= L2TP_MAX_XWIN);
 1580         CHECK(seq->cwnd >= 1);
 1581         CHECK(seq->cwnd <= seq->wmax);
 1582         CHECK(seq->ssth >= 1);
 1583         CHECK(seq->ssth <= seq->wmax);
 1584         if (seq->cwnd < seq->ssth)
 1585                 CHECK(seq->acks == 0);
 1586         else
 1587                 CHECK(seq->acks <= seq->cwnd);
 1588         CHECK(self_unack >= 0);
 1589         CHECK(peer_unack >= 0);
 1590         CHECK(peer_unack <= seq->wmax);
 1591         CHECK((self_unack == 0) ^ callout_active(&seq->xack_timer));
 1592         CHECK((peer_unack == 0) ^ callout_active(&seq->rack_timer));
 1593         for (i = 0; i < peer_unack; i++)
 1594                 CHECK(seq->xwin[i] != NULL);
 1595         for ( ; i < seq->cwnd; i++)         /* verify peer's recv window full */
 1596                 CHECK(seq->xwin[i] == NULL);
 1597 
 1598 #undef CHECK
 1599 }
 1600 #endif  /* INVARIANTS */

Cache object: 678aebbf7676c7dd7140990445d388e9


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