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