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