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