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