Deleted Added
sdiff udiff text old ( 68876 ) new ( 69922 )
full compact
1
2/*
3 * ng_pptpgre.c
4 *
5 * Copyright (c) 1996-1999 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
39 * $FreeBSD: head/sys/netgraph/ng_pptpgre.c 68876 2000-11-18 15:17:43Z dwmalone $
40 * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $
41 */
42
43/*
44 * PPTP/GRE netgraph node type.
45 *
46 * This node type does the GRE encapsulation as specified for the PPTP
47 * protocol (RFC 2637, section 4). This includes sequencing and
48 * retransmission of frames, but not the actual packet delivery nor
49 * any of the TCP control stream protocol.
50 *
51 * The "upper" hook of this node is suitable for attaching to a "ppp"
52 * node link hook. The "lower" hook of this node is suitable for attaching
53 * to a "ksocket" node on hook "inet/raw/gre".
54 */
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/kernel.h>
59#include <sys/time.h>
60#include <sys/mbuf.h>
61#include <sys/malloc.h>
62#include <sys/errno.h>
63
64#include <netinet/in.h>
65#include <netinet/in_systm.h>
66#include <netinet/ip.h>
67
68#include <netgraph/ng_message.h>
69#include <netgraph/netgraph.h>
70#include <netgraph/ng_parse.h>
71#include <netgraph/ng_pptpgre.h>
72
73/* GRE packet format, as used by PPTP */
74struct greheader {
75#if BYTE_ORDER == LITTLE_ENDIAN
76 u_char recursion:3; /* recursion control */
77 u_char ssr:1; /* strict source route */
78 u_char hasSeq:1; /* sequence number present */
79 u_char hasKey:1; /* key present */
80 u_char hasRoute:1; /* routing present */
81 u_char hasSum:1; /* checksum present */
82 u_char vers:3; /* version */
83 u_char flags:4; /* flags */
84 u_char hasAck:1; /* acknowlege number present */
85#elif BYTE_ORDER == BIG_ENDIAN
86 u_char hasSum:1; /* checksum present */
87 u_char hasRoute:1; /* routing present */
88 u_char hasKey:1; /* key present */
89 u_char hasSeq:1; /* sequence number present */
90 u_char ssr:1; /* strict source route */
91 u_char recursion:3; /* recursion control */
92 u_char hasAck:1; /* acknowlege number present */
93 u_char flags:4; /* flags */
94 u_char vers:3; /* version */
95#else
96#error BYTE_ORDER is not defined properly
97#endif
98 u_int16_t proto; /* protocol (ethertype) */
99 u_int16_t length; /* payload length */
100 u_int16_t cid; /* call id */
101 u_int32_t data[0]; /* opt. seq, ack, then data */
102};
103
104/* The PPTP protocol ID used in the GRE 'proto' field */
105#define PPTP_GRE_PROTO 0x880b
106
107/* Bits that must be set a certain way in all PPTP/GRE packets */
108#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
109#define PPTP_INIT_MASK 0xef7fffff
110
111/* Min and max packet length */
112#define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8)
113
114/* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
115#define PPTP_TIME_SCALE 1000 /* milliseconds */
116typedef u_int64_t pptptime_t;
117
118/* Acknowledgment timeout parameters and functions */
119#define PPTP_XMIT_WIN 16 /* max xmit window */
120#define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 100 milliseconds */
121#define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
122#define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */
123
124/* When we recieve a packet, we wait to see if there's an outgoing packet
125 we can piggy-back the ACK off of. These parameters determine the mimimum
126 and maxmimum length of time we're willing to wait in order to do that.
127 These have no effect unless "enableDelayedAck" is turned on. */
128#define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
129#define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */
130
131/* See RFC 2637 section 4.4 */
132#define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */
133#define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */
134#define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */
135#define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */
136
137#define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y))
138
139/* We keep packet retransmit and acknowlegement state in this struct */
140struct ng_pptpgre_ackp {
141 int32_t ato; /* adaptive time-out value */
142 int32_t rtt; /* round trip time estimate */
143 int32_t dev; /* deviation estimate */
144 u_int16_t xmitWin; /* size of xmit window */
145 struct callout_handle sackTimer; /* send ack timer */
146 struct callout_handle rackTimer; /* recv ack timer */
147 node_p *sackTimerPtr; /* send ack timer pointer */
148 node_p *rackTimerPtr; /* recv ack timer pointer */
149 u_int32_t winAck; /* seq when xmitWin will grow */
150 pptptime_t timeSent[PPTP_XMIT_WIN];
151#ifdef DEBUG_RAT
152 pptptime_t timerStart; /* when rackTimer started */
153 pptptime_t timerLength; /* rackTimer duration */
154#endif
155};
156
157/* Node private data */
158struct ng_pptpgre_private {
159 hook_p upper; /* hook to upper layers */
160 hook_p lower; /* hook to lower layers */
161 struct ng_pptpgre_conf conf; /* configuration info */
162 struct ng_pptpgre_ackp ackp; /* packet transmit ack state */
163 u_int32_t recvSeq; /* last seq # we rcv'd */
164 u_int32_t xmitSeq; /* last seq # we sent */
165 u_int32_t recvAck; /* last seq # peer ack'd */
166 u_int32_t xmitAck; /* last seq # we ack'd */
167 struct timeval startTime; /* time node was created */
168 struct ng_pptpgre_stats stats; /* node statistics */
169};
170typedef struct ng_pptpgre_private *priv_p;
171
172/* Netgraph node methods */
173static ng_constructor_t ng_pptpgre_constructor;
174static ng_rcvmsg_t ng_pptpgre_rcvmsg;
175static ng_shutdown_t ng_pptpgre_rmnode;
176static ng_newhook_t ng_pptpgre_newhook;
177static ng_rcvdata_t ng_pptpgre_rcvdata;
178static ng_disconnect_t ng_pptpgre_disconnect;
179
180/* Helper functions */
181static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta);
182static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta);
183static void ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
184static void ng_pptpgre_start_recv_ack_timer(node_p node);
185static void ng_pptpgre_recv_ack_timeout(void *arg);
186static void ng_pptpgre_send_ack_timeout(void *arg);
187static void ng_pptpgre_reset(node_p node);
188static pptptime_t ng_pptpgre_time(node_p node);
189
190/* Parse type for struct ng_pptpgre_conf */
191static const struct ng_parse_struct_info
192 ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO;
193static const struct ng_parse_type ng_pptpgre_conf_type = {
194 &ng_parse_struct_type,
195 &ng_pptpgre_conf_type_info,
196};
197
198/* Parse type for struct ng_pptpgre_stats */
199static const struct ng_parse_struct_info
200 ng_pptpgre_stats_type_info = NG_PPTPGRE_STATS_TYPE_INFO;
201static const struct ng_parse_type ng_pptp_stats_type = {
202 &ng_parse_struct_type,
203 &ng_pptpgre_stats_type_info
204};
205
206/* List of commands and how to convert arguments to/from ASCII */
207static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
208 {
209 NGM_PPTPGRE_COOKIE,
210 NGM_PPTPGRE_SET_CONFIG,
211 "setconfig",
212 &ng_pptpgre_conf_type,
213 NULL
214 },
215 {
216 NGM_PPTPGRE_COOKIE,
217 NGM_PPTPGRE_GET_CONFIG,
218 "getconfig",
219 NULL,
220 &ng_pptpgre_conf_type
221 },
222 {
223 NGM_PPTPGRE_COOKIE,
224 NGM_PPTPGRE_GET_STATS,
225 "getstats",
226 NULL,
227 &ng_pptp_stats_type
228 },
229 {
230 NGM_PPTPGRE_COOKIE,
231 NGM_PPTPGRE_CLR_STATS,
232 "clrstats",
233 NULL,
234 NULL
235 },
236 {
237 NGM_PPTPGRE_COOKIE,
238 NGM_PPTPGRE_GETCLR_STATS,
239 "getclrstats",
240 NULL,
241 &ng_pptp_stats_type
242 },
243 { 0 }
244};
245
246/* Node type descriptor */
247static struct ng_type ng_pptpgre_typestruct = {
248 NG_VERSION,
249 NG_PPTPGRE_NODE_TYPE,
250 NULL,
251 ng_pptpgre_constructor,
252 ng_pptpgre_rcvmsg,
253 ng_pptpgre_rmnode,
254 ng_pptpgre_newhook,
255 NULL,
256 NULL,
257 ng_pptpgre_rcvdata,
258 ng_pptpgre_rcvdata,
259 ng_pptpgre_disconnect,
260 ng_pptpgre_cmdlist
261};
262NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
263
264#define ERROUT(x) do { error = (x); goto done; } while (0)
265
266/************************************************************************
267 NETGRAPH NODE STUFF
268 ************************************************************************/
269
270/*
271 * Node type constructor
272 */
273static int
274ng_pptpgre_constructor(node_p *nodep)
275{
276 priv_p priv;
277 int error;
278
279 /* Allocate private structure */
280 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
281 if (priv == NULL)
282 return (ENOMEM);
283
284 /* Call generic node constructor */
285 if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) {
286 FREE(priv, M_NETGRAPH);
287 return (error);
288 }
289 (*nodep)->private = priv;
290
291 /* Initialize state */
292 callout_handle_init(&priv->ackp.sackTimer);
293 callout_handle_init(&priv->ackp.rackTimer);
294
295 /* Done */
296 return (0);
297}
298
299/*
300 * Give our OK for a hook to be added.
301 */
302static int
303ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
304{
305 const priv_p priv = node->private;
306 hook_p *hookPtr;
307
308 /* Check hook name */
309 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
310 hookPtr = &priv->upper;
311 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
312 hookPtr = &priv->lower;
313 else
314 return (EINVAL);
315
316 /* See if already connected */
317 if (*hookPtr != NULL)
318 return (EISCONN);
319
320 /* OK */
321 *hookPtr = hook;
322 return (0);
323}
324
325/*
326 * Receive a control message.
327 */
328static int
329ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg,
330 const char *raddr, struct ng_mesg **rptr, hook_p lasthook)
331{
332 const priv_p priv = node->private;
333 struct ng_mesg *resp = NULL;
334 int error = 0;
335
336 switch (msg->header.typecookie) {
337 case NGM_PPTPGRE_COOKIE:
338 switch (msg->header.cmd) {
339 case NGM_PPTPGRE_SET_CONFIG:
340 {
341 struct ng_pptpgre_conf *const newConf =
342 (struct ng_pptpgre_conf *) msg->data;
343
344 /* Check for invalid or illegal config */
345 if (msg->header.arglen != sizeof(*newConf))
346 ERROUT(EINVAL);
347 ng_pptpgre_reset(node); /* reset on configure */
348 priv->conf = *newConf;
349 break;
350 }
351 case NGM_PPTPGRE_GET_CONFIG:
352 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
353 if (resp == NULL)
354 ERROUT(ENOMEM);
355 bcopy(&priv->conf, resp->data, sizeof(priv->conf));
356 break;
357 case NGM_PPTPGRE_GET_STATS:
358 case NGM_PPTPGRE_CLR_STATS:
359 case NGM_PPTPGRE_GETCLR_STATS:
360 {
361 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
362 NG_MKRESPONSE(resp, msg,
363 sizeof(priv->stats), M_NOWAIT);
364 if (resp == NULL)
365 ERROUT(ENOMEM);
366 bcopy(&priv->stats,
367 resp->data, sizeof(priv->stats));
368 }
369 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
370 bzero(&priv->stats, sizeof(priv->stats));
371 break;
372 }
373 default:
374 error = EINVAL;
375 break;
376 }
377 break;
378 default:
379 error = EINVAL;
380 break;
381 }
382 if (rptr)
383 *rptr = resp;
384 else if (resp)
385 FREE(resp, M_NETGRAPH);
386
387done:
388 FREE(msg, M_NETGRAPH);
389 return (error);
390}
391
392/*
393 * Receive incoming data on a hook.
394 */
395static int
396ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
397 struct mbuf **ret_m, meta_p *ret_meta)
398{
399 const node_p node = hook->node;
400 const priv_p priv = node->private;
401
402 /* If not configured, reject */
403 if (!priv->conf.enabled) {
404 NG_FREE_DATA(m, meta);
405 return (ENXIO);
406 }
407
408 /* Treat as xmit or recv data */
409 if (hook == priv->upper)
410 return ng_pptpgre_xmit(node, m, meta);
411 if (hook == priv->lower)
412 return ng_pptpgre_recv(node, m, meta);
413 panic("%s: weird hook", __FUNCTION__);
414}
415
416/*
417 * Destroy node
418 */
419static int
420ng_pptpgre_rmnode(node_p node)
421{
422 const priv_p priv = node->private;
423
424 /* Reset node */
425 ng_pptpgre_reset(node);
426
427 /* Take down netgraph node */
428 node->flags |= NG_INVALID;
429 ng_cutlinks(node);
430 ng_unname(node);
431 bzero(priv, sizeof(*priv));
432 FREE(priv, M_NETGRAPH);
433 node->private = NULL;
434 ng_unref(node);
435 return (0);
436}
437
438/*
439 * Hook disconnection
440 */
441static int
442ng_pptpgre_disconnect(hook_p hook)
443{
444 const node_p node = hook->node;
445 const priv_p priv = node->private;
446
447 /* Zero out hook pointer */
448 if (hook == priv->upper)
449 priv->upper = NULL;
450 else if (hook == priv->lower)
451 priv->lower = NULL;
452 else
453 panic("%s: unknown hook", __FUNCTION__);
454
455 /* Go away if no longer connected to anything */
456 if (node->numhooks == 0)
457 ng_rmnode(node);
458 return (0);
459}
460
461/*************************************************************************
462 TRANSMIT AND RECEIVE FUNCTIONS
463*************************************************************************/
464
465/*
466 * Transmit an outgoing frame, or just an ack if m is NULL.
467 */
468static int
469ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
470{
471 const priv_p priv = node->private;
472 struct ng_pptpgre_ackp *const a = &priv->ackp;
473 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
474 struct greheader *const gre = (struct greheader *)buf;
475 int grelen, error;
476
477 /* Check if there's data */
478 if (m != NULL) {
479
480 /* Is our transmit window full? */
481 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck)
482 >= a->xmitWin) {
483 priv->stats.xmitDrops++;
484 NG_FREE_DATA(m, meta);
485 return (ENOBUFS);
486 }
487
488 /* Sanity check frame length */
489 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
490 priv->stats.xmitTooBig++;
491 NG_FREE_DATA(m, meta);
492 return (EMSGSIZE);
493 }
494 } else
495 priv->stats.xmitLoneAcks++;
496
497 /* Build GRE header */
498 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
499 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
500 gre->cid = htons(priv->conf.peerCid);
501
502 /* Include sequence number if packet contains any data */
503 if (m != NULL) {
504 gre->hasSeq = 1;
505 a->timeSent[priv->xmitSeq - priv->recvAck]
506 = ng_pptpgre_time(node);
507 priv->xmitSeq++;
508 gre->data[0] = htonl(priv->xmitSeq);
509 }
510
511 /* Include acknowledgement (and stop send ack timer) if needed */
512 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
513 gre->hasAck = 1;
514 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
515 priv->xmitAck = priv->recvSeq;
516 a->sackTimerPtr = NULL; /* "stop" timer */
517 }
518
519 /* Prepend GRE header to outgoing frame */
520 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
521 if (m == NULL) {
522 MGETHDR(m, M_DONTWAIT, MT_DATA);
523 if (m == NULL) {
524 priv->stats.memoryFailures++;
525 NG_FREE_META(meta);
526 return (ENOBUFS);
527 }
528 m->m_len = m->m_pkthdr.len = grelen;
529 m->m_pkthdr.rcvif = NULL;
530 } else {
531 M_PREPEND(m, grelen, M_NOWAIT);
532 if (m == NULL || (m->m_len < grelen
533 && (m = m_pullup(m, grelen)) == NULL)) {
534 priv->stats.memoryFailures++;
535 NG_FREE_META(meta);
536 return (ENOBUFS);
537 }
538 }
539 bcopy(gre, mtod(m, u_char *), grelen);
540
541 /* Update stats */
542 priv->stats.xmitPackets++;
543 priv->stats.xmitOctets += m->m_pkthdr.len;
544
545 /* Deliver packet */
546 NG_SEND_DATA(error, priv->lower, m, meta);
547
548 /* Start receive ACK timer if data was sent and not already running */
549 if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
550 ng_pptpgre_start_recv_ack_timer(node);
551 return (error);
552}
553
554/*
555 * Handle an incoming packet. The packet includes the IP header.
556 */
557static int
558ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta)
559{
560 const priv_p priv = node->private;
561 int iphlen, grelen, extralen;
562 struct greheader *gre;
563 struct ip *ip;
564 int error = 0;
565
566 /* Update stats */
567 priv->stats.recvPackets++;
568 priv->stats.recvOctets += m->m_pkthdr.len;
569
570 /* Sanity check packet length */
571 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
572 priv->stats.recvRunts++;
573bad:
574 NG_FREE_DATA(m, meta);
575 return (EINVAL);
576 }
577
578 /* Safely pull up the complete IP+GRE headers */
579 if (m->m_len < sizeof(*ip) + sizeof(*gre)
580 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
581 priv->stats.memoryFailures++;
582 NG_FREE_META(meta);
583 return (ENOBUFS);
584 }
585 ip = mtod(m, struct ip *);
586 iphlen = ip->ip_hl << 2;
587 if (m->m_len < iphlen + sizeof(*gre)) {
588 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
589 priv->stats.memoryFailures++;
590 NG_FREE_META(meta);
591 return (ENOBUFS);
592 }
593 ip = mtod(m, struct ip *);
594 }
595 gre = (struct greheader *)((u_char *)ip + iphlen);
596 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
597 if (m->m_pkthdr.len < iphlen + grelen) {
598 priv->stats.recvRunts++;
599 goto bad;
600 }
601 if (m->m_len < iphlen + grelen) {
602 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
603 priv->stats.memoryFailures++;
604 NG_FREE_META(meta);
605 return (ENOBUFS);
606 }
607 ip = mtod(m, struct ip *);
608 gre = (struct greheader *)((u_char *)ip + iphlen);
609 }
610
611 /* Sanity check packet length and GRE header bits */
612 extralen = m->m_pkthdr.len
613 - (iphlen + grelen + (u_int16_t)ntohs(gre->length));
614 if (extralen < 0) {
615 priv->stats.recvBadGRE++;
616 goto bad;
617 }
618 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
619 priv->stats.recvBadGRE++;
620 goto bad;
621 }
622 if (ntohs(gre->cid) != priv->conf.cid) {
623 priv->stats.recvBadCID++;
624 goto bad;
625 }
626
627 /* Look for peer ack */
628 if (gre->hasAck) {
629 struct ng_pptpgre_ackp *const a = &priv->ackp;
630 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
631 const int index = ack - priv->recvAck - 1;
632 const long sample = ng_pptpgre_time(node) - a->timeSent[index];
633 long diff;
634
635 /* Sanity check ack value */
636 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
637 priv->stats.recvBadAcks++;
638 goto badAck; /* we never sent it! */
639 }
640 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
641 goto badAck; /* ack already timed out */
642 priv->recvAck = ack;
643
644 /* Update adaptive timeout stuff */
645 diff = sample - a->rtt;
646 a->rtt += PPTP_ACK_ALPHA(diff);
647 if (diff < 0)
648 diff = -diff;
649 a->dev += PPTP_ACK_BETA(diff - a->dev);
650 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
651 if (a->ato > PPTP_MAX_TIMEOUT)
652 a->ato = PPTP_MAX_TIMEOUT;
653 if (a->ato < PPTP_MIN_TIMEOUT)
654 a->ato = PPTP_MIN_TIMEOUT;
655
656 /* Shift packet transmit times in our transmit window */
657 ovbcopy(a->timeSent + index + 1, a->timeSent,
658 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
659
660 /* If we sent an entire window, increase window size by one */
661 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
662 && a->xmitWin < PPTP_XMIT_WIN) {
663 a->xmitWin++;
664 a->winAck = ack + a->xmitWin;
665 }
666
667 /* Stop/(re)start receive ACK timer as necessary */
668 a->rackTimerPtr = NULL;
669 if (priv->recvAck != priv->xmitSeq)
670 ng_pptpgre_start_recv_ack_timer(node);
671 }
672badAck:
673
674 /* See if frame contains any data */
675 if (gre->hasSeq) {
676 struct ng_pptpgre_ackp *const a = &priv->ackp;
677 const u_int32_t seq = ntohl(gre->data[0]);
678
679 /* Sanity check sequence number */
680 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
681 if (seq == priv->recvSeq)
682 priv->stats.recvDuplicates++;
683 else
684 priv->stats.recvOutOfOrder++;
685 goto bad; /* out-of-order or dup */
686 }
687 priv->recvSeq = seq;
688
689 /* We need to acknowledge this packet; do it soon... */
690 if (a->sackTimerPtr == NULL) {
691 int maxWait;
692
693 /* Take 1/4 of the estimated round trip time */
694 maxWait = (a->rtt >> 2);
695
696 /* If delayed ACK is disabled, send it now */
697 if (!priv->conf.enableDelayedAck
698 || maxWait < PPTP_MIN_ACK_DELAY)
699 ng_pptpgre_xmit(node, NULL, NULL);
700 else { /* send the ack later */
701 if (maxWait > PPTP_MAX_ACK_DELAY)
702 maxWait = PPTP_MAX_ACK_DELAY;
703 ng_pptpgre_start_send_ack_timer(node, maxWait);
704 }
705 }
706
707 /* Trim mbuf down to internal payload */
708 m_adj(m, iphlen + grelen);
709 if (extralen > 0)
710 m_adj(m, -extralen);
711
712 /* Deliver frame to upper layers */
713 NG_SEND_DATA(error, priv->upper, m, meta);
714 } else {
715 priv->stats.recvLoneAcks++;
716 NG_FREE_DATA(m, meta); /* no data to deliver */
717 }
718 return (error);
719}
720
721/*************************************************************************
722 TIMER RELATED FUNCTIONS
723*************************************************************************/
724
725/*
726 * Start a timer for the peer's acknowledging our oldest unacknowledged
727 * sequence number. If we get an ack for this sequence number before
728 * the timer goes off, we cancel the timer. Resets currently running
729 * recv ack timer, if any.
730 */
731static void
732ng_pptpgre_start_recv_ack_timer(node_p node)
733{
734 const priv_p priv = node->private;
735 struct ng_pptpgre_ackp *const a = &priv->ackp;
736 int remain, ticks;
737
738 /* Compute how long until oldest unack'd packet times out,
739 and reset the timer to that time. */
740 KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __FUNCTION__));
741 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
742 if (remain < 0)
743 remain = 0;
744#ifdef DEBUG_RAT
745 a->timerLength = remain;
746 a->timerStart = ng_pptpgre_time(node);
747#endif
748
749 /* Start new timer */
750 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
751 if (a->rackTimerPtr == NULL) {
752 priv->stats.memoryFailures++;
753 return; /* XXX potential hang here */
754 }
755 *a->rackTimerPtr = node; /* insures the correct timeout event */
756 node->refs++;
757
758 /* Be conservative: timeout() can return up to 1 tick early */
759 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
760 a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout,
761 a->rackTimerPtr, ticks);
762}
763
764/*
765 * The peer has failed to acknowledge the oldest unacknowledged sequence
766 * number within the time allotted. Update our adaptive timeout parameters
767 * and reset/restart the recv ack timer.
768 */
769static void
770ng_pptpgre_recv_ack_timeout(void *arg)
771{
772 int s = splnet();
773 const node_p node = *((node_p *)arg);
774 const priv_p priv = node->private;
775 struct ng_pptpgre_ackp *const a = &priv->ackp;
776
777 /* This complicated stuff is needed to avoid race conditions */
778 FREE(arg, M_NETGRAPH);
779 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__));
780 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */
781 ng_unref(node);
782 splx(s);
783 return;
784 }
785 ng_unref(node);
786 if (arg != a->rackTimerPtr) { /* timer stopped race condition */
787 splx(s);
788 return;
789 }
790 a->rackTimerPtr = NULL;
791
792 /* Update adaptive timeout stuff */
793 priv->stats.recvAckTimeouts++;
794 a->rtt = PPTP_ACK_DELTA(a->rtt);
795 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
796 if (a->ato > PPTP_MAX_TIMEOUT)
797 a->ato = PPTP_MAX_TIMEOUT;
798 if (a->ato < PPTP_MIN_TIMEOUT)
799 a->ato = PPTP_MIN_TIMEOUT;
800
801#ifdef DEBUG_RAT
802 log(LOG_DEBUG,
803 "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
804 (int)ng_pptpgre_time(node), priv->recvAck + 1,
805 (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
806#endif
807
808 /* Reset ack and sliding window */
809 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */
810 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */
811 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
812 splx(s);
813}
814
815/*
816 * Start the send ack timer. This assumes the timer is not
817 * already running.
818 */
819static void
820ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
821{
822 const priv_p priv = node->private;
823 struct ng_pptpgre_ackp *const a = &priv->ackp;
824 int ticks;
825
826 /* Start new timer */
827 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __FUNCTION__));
828 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
829 if (a->sackTimerPtr == NULL) {
830 priv->stats.memoryFailures++;
831 return; /* XXX potential hang here */
832 }
833 *a->sackTimerPtr = node;
834 node->refs++;
835
836 /* Be conservative: timeout() can return up to 1 tick early */
837 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
838 a->sackTimer = timeout(ng_pptpgre_send_ack_timeout,
839 a->sackTimerPtr, ticks);
840}
841
842/*
843 * We've waited as long as we're willing to wait before sending an
844 * acknowledgement to the peer for received frames. We had hoped to
845 * be able to piggy back our acknowledgement on an outgoing data frame,
846 * but apparently there haven't been any since. So send the ack now.
847 */
848static void
849ng_pptpgre_send_ack_timeout(void *arg)
850{
851 int s = splnet();
852 const node_p node = *((node_p *)arg);
853 const priv_p priv = node->private;
854 struct ng_pptpgre_ackp *const a = &priv->ackp;
855
856 /* This complicated stuff is needed to avoid race conditions */
857 FREE(arg, M_NETGRAPH);
858 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__));
859 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */
860 ng_unref(node);
861 splx(s);
862 return;
863 }
864 ng_unref(node);
865 if (a->sackTimerPtr != arg) { /* timer stopped race condition */
866 splx(s);
867 return;
868 }
869 a->sackTimerPtr = NULL;
870
871 /* Send a frame with an ack but no payload */
872 ng_pptpgre_xmit(node, NULL, NULL);
873 splx(s);
874}
875
876/*************************************************************************
877 MISC FUNCTIONS
878*************************************************************************/
879
880/*
881 * Reset state
882 */
883static void
884ng_pptpgre_reset(node_p node)
885{
886 const priv_p priv = node->private;
887 struct ng_pptpgre_ackp *const a = &priv->ackp;
888
889 /* Reset adaptive timeout state */
890 a->ato = PPTP_MAX_TIMEOUT;
891 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */
892 if (a->rtt < PPTP_MIN_RTT)
893 a->rtt = PPTP_MIN_RTT;
894 a->dev = 0;
895 a->xmitWin = (priv->conf.recvWin + 1) / 2;
896 if (a->xmitWin < 2) /* often the first packet is lost */
897 a->xmitWin = 2; /* because the peer isn't ready */
898 if (a->xmitWin > PPTP_XMIT_WIN)
899 a->xmitWin = PPTP_XMIT_WIN;
900 a->winAck = a->xmitWin;
901
902 /* Reset sequence numbers */
903 priv->recvSeq = ~0;
904 priv->recvAck = ~0;
905 priv->xmitSeq = ~0;
906 priv->xmitAck = ~0;
907
908 /* Reset start time */
909 getmicrouptime(&priv->startTime);
910
911 /* Reset stats */
912 bzero(&priv->stats, sizeof(priv->stats));
913
914 /* "Stop" timers */
915 a->sackTimerPtr = NULL;
916 a->rackTimerPtr = NULL;
917}
918
919/*
920 * Return the current time scaled & translated to our internally used format.
921 */
922static pptptime_t
923ng_pptpgre_time(node_p node)
924{
925 const priv_p priv = node->private;
926 struct timeval tv;
927 pptptime_t t;
928
929 microuptime(&tv);
930 if (tv.tv_sec < priv->startTime.tv_sec
931 || (tv.tv_sec == priv->startTime.tv_sec
932 && tv.tv_usec < priv->startTime.tv_usec))
933 return (0);
934 timevalsub(&tv, &priv->startTime);
935 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
936 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
937 return(t);
938}
939