Deleted Added
full compact
ng_pptpgre.c (68876) ng_pptpgre.c (69922)
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 *
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 $
39 * $FreeBSD: head/sys/netgraph/ng_pptpgre.c 69922 2000-12-12 18:52:14Z julian $
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,
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,
258 ng_pptpgre_disconnect,
259 ng_pptpgre_cmdlist
260};
261NETGRAPH_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 */
272static int
273ng_pptpgre_constructor(node_p *nodep)
274{
275 priv_p priv;
276 int error;
277
278 /* Allocate private structure */
279 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
280 if (priv == NULL)
281 return (ENOMEM);
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 */
301static int
302ng_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 */
327static int
328ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg,
329 const char *raddr, struct ng_mesg **rptr, hook_p lasthook)
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
386done:
387 FREE(msg, M_NETGRAPH);
388 return (error);
389}
390
391/*
392 * Receive incoming data on a hook.
393 */
394static int
395ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
397 struct mbuf **ret_m, meta_p *ret_meta)
396 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
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
397{
398 const node_p node = hook->node;
399 const priv_p priv = node->private;
400
401 /* If not configured, reject */
402 if (!priv->conf.enabled) {
403 NG_FREE_DATA(m, meta);
404 return (ENXIO);
405 }
406
407 /* Treat as xmit or recv data */
408 if (hook == priv->upper)
409 return ng_pptpgre_xmit(node, m, meta);
410 if (hook == priv->lower)
411 return ng_pptpgre_recv(node, m, meta);
412 panic("%s: weird hook", __FUNCTION__);
413}
414
415/*
416 * Destroy node
417 */
418static int
419ng_pptpgre_rmnode(node_p node)
420{
421 const priv_p priv = node->private;
422
423 /* Reset node */
424 ng_pptpgre_reset(node);
425
426 /* Take down netgraph node */
427 node->flags |= NG_INVALID;
428 ng_cutlinks(node);
429 ng_unname(node);
430 bzero(priv, sizeof(*priv));
431 FREE(priv, M_NETGRAPH);
432 node->private = NULL;
433 ng_unref(node);
434 return (0);
435}
436
437/*
438 * Hook disconnection
439 */
440static int
441ng_pptpgre_disconnect(hook_p hook)
442{
443 const node_p node = hook->node;
444 const priv_p priv = node->private;
445
446 /* Zero out hook pointer */
447 if (hook == priv->upper)
448 priv->upper = NULL;
449 else if (hook == priv->lower)
450 priv->lower = NULL;
451 else
452 panic("%s: unknown hook", __FUNCTION__);
453
454 /* Go away if no longer connected to anything */
455 if (node->numhooks == 0)
456 ng_rmnode(node);
457 return (0);
458}
459
460/*************************************************************************
461 TRANSMIT AND RECEIVE FUNCTIONS
462*************************************************************************/
463
464/*
465 * Transmit an outgoing frame, or just an ack if m is NULL.
466 */
467static int
468ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
469{
470 const priv_p priv = node->private;
471 struct ng_pptpgre_ackp *const a = &priv->ackp;
472 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
473 struct greheader *const gre = (struct greheader *)buf;
474 int grelen, error;
475
476 /* Check if there's data */
477 if (m != NULL) {
478
479 /* Is our transmit window full? */
480 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck)
481 >= a->xmitWin) {
482 priv->stats.xmitDrops++;
483 NG_FREE_DATA(m, meta);
484 return (ENOBUFS);
485 }
486
487 /* Sanity check frame length */
488 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
489 priv->stats.xmitTooBig++;
490 NG_FREE_DATA(m, meta);
491 return (EMSGSIZE);
492 }
493 } else
494 priv->stats.xmitLoneAcks++;
495
496 /* Build GRE header */
497 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
498 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
499 gre->cid = htons(priv->conf.peerCid);
500
501 /* Include sequence number if packet contains any data */
502 if (m != NULL) {
503 gre->hasSeq = 1;
504 a->timeSent[priv->xmitSeq - priv->recvAck]
505 = ng_pptpgre_time(node);
506 priv->xmitSeq++;
507 gre->data[0] = htonl(priv->xmitSeq);
508 }
509
510 /* Include acknowledgement (and stop send ack timer) if needed */
511 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
512 gre->hasAck = 1;
513 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
514 priv->xmitAck = priv->recvSeq;
515 a->sackTimerPtr = NULL; /* "stop" timer */
516 }
517
518 /* Prepend GRE header to outgoing frame */
519 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
520 if (m == NULL) {
521 MGETHDR(m, M_DONTWAIT, MT_DATA);
522 if (m == NULL) {
523 priv->stats.memoryFailures++;
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 priv->stats.memoryFailures++;
534 NG_FREE_META(meta);
535 return (ENOBUFS);
536 }
537 }
538 bcopy(gre, mtod(m, u_char *), grelen);
539
540 /* Update stats */
541 priv->stats.xmitPackets++;
542 priv->stats.xmitOctets += m->m_pkthdr.len;
543
544 /* Deliver packet */
545 NG_SEND_DATA(error, priv->lower, m, meta);
546
547 /* Start receive ACK timer if data was sent and not already running */
548 if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
549 ng_pptpgre_start_recv_ack_timer(node);
550 return (error);
551}
552
553/*
554 * Handle an incoming packet. The packet includes the IP header.
555 */
556static int
557ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta)
558{
559 const priv_p priv = node->private;
560 int iphlen, grelen, extralen;
561 struct greheader *gre;
562 struct ip *ip;
563 int error = 0;
564
565 /* Update stats */
566 priv->stats.recvPackets++;
567 priv->stats.recvOctets += m->m_pkthdr.len;
568
569 /* Sanity check packet length */
570 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
571 priv->stats.recvRunts++;
572bad:
573 NG_FREE_DATA(m, meta);
574 return (EINVAL);
575 }
576
577 /* Safely pull up the complete IP+GRE headers */
578 if (m->m_len < sizeof(*ip) + sizeof(*gre)
579 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
580 priv->stats.memoryFailures++;
581 NG_FREE_META(meta);
582 return (ENOBUFS);
583 }
584 ip = mtod(m, struct ip *);
585 iphlen = ip->ip_hl << 2;
586 if (m->m_len < iphlen + sizeof(*gre)) {
587 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
588 priv->stats.memoryFailures++;
589 NG_FREE_META(meta);
590 return (ENOBUFS);
591 }
592 ip = mtod(m, struct ip *);
593 }
594 gre = (struct greheader *)((u_char *)ip + iphlen);
595 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
596 if (m->m_pkthdr.len < iphlen + grelen) {
597 priv->stats.recvRunts++;
598 goto bad;
599 }
600 if (m->m_len < iphlen + grelen) {
601 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
602 priv->stats.memoryFailures++;
603 NG_FREE_META(meta);
604 return (ENOBUFS);
605 }
606 ip = mtod(m, struct ip *);
607 gre = (struct greheader *)((u_char *)ip + iphlen);
608 }
609
610 /* Sanity check packet length and GRE header bits */
611 extralen = m->m_pkthdr.len
612 - (iphlen + grelen + (u_int16_t)ntohs(gre->length));
613 if (extralen < 0) {
614 priv->stats.recvBadGRE++;
615 goto bad;
616 }
617 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
618 priv->stats.recvBadGRE++;
619 goto bad;
620 }
621 if (ntohs(gre->cid) != priv->conf.cid) {
622 priv->stats.recvBadCID++;
623 goto bad;
624 }
625
626 /* Look for peer ack */
627 if (gre->hasAck) {
628 struct ng_pptpgre_ackp *const a = &priv->ackp;
629 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
630 const int index = ack - priv->recvAck - 1;
631 const long sample = ng_pptpgre_time(node) - a->timeSent[index];
632 long diff;
633
634 /* Sanity check ack value */
635 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
636 priv->stats.recvBadAcks++;
637 goto badAck; /* we never sent it! */
638 }
639 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
640 goto badAck; /* ack already timed out */
641 priv->recvAck = ack;
642
643 /* Update adaptive timeout stuff */
644 diff = sample - a->rtt;
645 a->rtt += PPTP_ACK_ALPHA(diff);
646 if (diff < 0)
647 diff = -diff;
648 a->dev += PPTP_ACK_BETA(diff - a->dev);
649 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
650 if (a->ato > PPTP_MAX_TIMEOUT)
651 a->ato = PPTP_MAX_TIMEOUT;
652 if (a->ato < PPTP_MIN_TIMEOUT)
653 a->ato = PPTP_MIN_TIMEOUT;
654
655 /* Shift packet transmit times in our transmit window */
656 ovbcopy(a->timeSent + index + 1, a->timeSent,
657 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
658
659 /* If we sent an entire window, increase window size by one */
660 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
661 && a->xmitWin < PPTP_XMIT_WIN) {
662 a->xmitWin++;
663 a->winAck = ack + a->xmitWin;
664 }
665
666 /* Stop/(re)start receive ACK timer as necessary */
667 a->rackTimerPtr = NULL;
668 if (priv->recvAck != priv->xmitSeq)
669 ng_pptpgre_start_recv_ack_timer(node);
670 }
671badAck:
672
673 /* See if frame contains any data */
674 if (gre->hasSeq) {
675 struct ng_pptpgre_ackp *const a = &priv->ackp;
676 const u_int32_t seq = ntohl(gre->data[0]);
677
678 /* Sanity check sequence number */
679 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
680 if (seq == priv->recvSeq)
681 priv->stats.recvDuplicates++;
682 else
683 priv->stats.recvOutOfOrder++;
684 goto bad; /* out-of-order or dup */
685 }
686 priv->recvSeq = seq;
687
688 /* We need to acknowledge this packet; do it soon... */
689 if (a->sackTimerPtr == NULL) {
690 int maxWait;
691
692 /* Take 1/4 of the estimated round trip time */
693 maxWait = (a->rtt >> 2);
694
695 /* If delayed ACK is disabled, send it now */
696 if (!priv->conf.enableDelayedAck
697 || maxWait < PPTP_MIN_ACK_DELAY)
698 ng_pptpgre_xmit(node, NULL, NULL);
699 else { /* send the ack later */
700 if (maxWait > PPTP_MAX_ACK_DELAY)
701 maxWait = PPTP_MAX_ACK_DELAY;
702 ng_pptpgre_start_send_ack_timer(node, maxWait);
703 }
704 }
705
706 /* Trim mbuf down to internal payload */
707 m_adj(m, iphlen + grelen);
708 if (extralen > 0)
709 m_adj(m, -extralen);
710
711 /* Deliver frame to upper layers */
712 NG_SEND_DATA(error, priv->upper, m, meta);
713 } else {
714 priv->stats.recvLoneAcks++;
715 NG_FREE_DATA(m, meta); /* no data to deliver */
716 }
717 return (error);
718}
719
720/*************************************************************************
721 TIMER RELATED FUNCTIONS
722*************************************************************************/
723
724/*
725 * Start a timer for the peer's acknowledging our oldest unacknowledged
726 * sequence number. If we get an ack for this sequence number before
727 * the timer goes off, we cancel the timer. Resets currently running
728 * recv ack timer, if any.
729 */
730static void
731ng_pptpgre_start_recv_ack_timer(node_p node)
732{
733 const priv_p priv = node->private;
734 struct ng_pptpgre_ackp *const a = &priv->ackp;
735 int remain, ticks;
736
737 /* Compute how long until oldest unack'd packet times out,
738 and reset the timer to that time. */
739 KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __FUNCTION__));
740 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
741 if (remain < 0)
742 remain = 0;
743#ifdef DEBUG_RAT
744 a->timerLength = remain;
745 a->timerStart = ng_pptpgre_time(node);
746#endif
747
748 /* Start new timer */
749 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
750 if (a->rackTimerPtr == NULL) {
751 priv->stats.memoryFailures++;
752 return; /* XXX potential hang here */
753 }
754 *a->rackTimerPtr = node; /* insures the correct timeout event */
755 node->refs++;
756
757 /* Be conservative: timeout() can return up to 1 tick early */
758 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
759 a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout,
760 a->rackTimerPtr, ticks);
761}
762
763/*
764 * The peer has failed to acknowledge the oldest unacknowledged sequence
765 * number within the time allotted. Update our adaptive timeout parameters
766 * and reset/restart the recv ack timer.
767 */
768static void
769ng_pptpgre_recv_ack_timeout(void *arg)
770{
771 int s = splnet();
772 const node_p node = *((node_p *)arg);
773 const priv_p priv = node->private;
774 struct ng_pptpgre_ackp *const a = &priv->ackp;
775
776 /* This complicated stuff is needed to avoid race conditions */
777 FREE(arg, M_NETGRAPH);
778 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__));
779 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */
780 ng_unref(node);
781 splx(s);
782 return;
783 }
784 ng_unref(node);
785 if (arg != a->rackTimerPtr) { /* timer stopped race condition */
786 splx(s);
787 return;
788 }
789 a->rackTimerPtr = NULL;
790
791 /* Update adaptive timeout stuff */
792 priv->stats.recvAckTimeouts++;
793 a->rtt = PPTP_ACK_DELTA(a->rtt);
794 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
795 if (a->ato > PPTP_MAX_TIMEOUT)
796 a->ato = PPTP_MAX_TIMEOUT;
797 if (a->ato < PPTP_MIN_TIMEOUT)
798 a->ato = PPTP_MIN_TIMEOUT;
799
800#ifdef DEBUG_RAT
801 log(LOG_DEBUG,
802 "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
803 (int)ng_pptpgre_time(node), priv->recvAck + 1,
804 (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
805#endif
806
807 /* Reset ack and sliding window */
808 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */
809 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */
810 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
811 splx(s);
812}
813
814/*
815 * Start the send ack timer. This assumes the timer is not
816 * already running.
817 */
818static void
819ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
820{
821 const priv_p priv = node->private;
822 struct ng_pptpgre_ackp *const a = &priv->ackp;
823 int ticks;
824
825 /* Start new timer */
826 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __FUNCTION__));
827 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
828 if (a->sackTimerPtr == NULL) {
829 priv->stats.memoryFailures++;
830 return; /* XXX potential hang here */
831 }
832 *a->sackTimerPtr = node;
833 node->refs++;
834
835 /* Be conservative: timeout() can return up to 1 tick early */
836 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
837 a->sackTimer = timeout(ng_pptpgre_send_ack_timeout,
838 a->sackTimerPtr, ticks);
839}
840
841/*
842 * We've waited as long as we're willing to wait before sending an
843 * acknowledgement to the peer for received frames. We had hoped to
844 * be able to piggy back our acknowledgement on an outgoing data frame,
845 * but apparently there haven't been any since. So send the ack now.
846 */
847static void
848ng_pptpgre_send_ack_timeout(void *arg)
849{
850 int s = splnet();
851 const node_p node = *((node_p *)arg);
852 const priv_p priv = node->private;
853 struct ng_pptpgre_ackp *const a = &priv->ackp;
854
855 /* This complicated stuff is needed to avoid race conditions */
856 FREE(arg, M_NETGRAPH);
857 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__));
858 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */
859 ng_unref(node);
860 splx(s);
861 return;
862 }
863 ng_unref(node);
864 if (a->sackTimerPtr != arg) { /* timer stopped race condition */
865 splx(s);
866 return;
867 }
868 a->sackTimerPtr = NULL;
869
870 /* Send a frame with an ack but no payload */
871 ng_pptpgre_xmit(node, NULL, NULL);
872 splx(s);
873}
874
875/*************************************************************************
876 MISC FUNCTIONS
877*************************************************************************/
878
879/*
880 * Reset state
881 */
882static void
883ng_pptpgre_reset(node_p node)
884{
885 const priv_p priv = node->private;
886 struct ng_pptpgre_ackp *const a = &priv->ackp;
887
888 /* Reset adaptive timeout state */
889 a->ato = PPTP_MAX_TIMEOUT;
890 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */
891 if (a->rtt < PPTP_MIN_RTT)
892 a->rtt = PPTP_MIN_RTT;
893 a->dev = 0;
894 a->xmitWin = (priv->conf.recvWin + 1) / 2;
895 if (a->xmitWin < 2) /* often the first packet is lost */
896 a->xmitWin = 2; /* because the peer isn't ready */
897 if (a->xmitWin > PPTP_XMIT_WIN)
898 a->xmitWin = PPTP_XMIT_WIN;
899 a->winAck = a->xmitWin;
900
901 /* Reset sequence numbers */
902 priv->recvSeq = ~0;
903 priv->recvAck = ~0;
904 priv->xmitSeq = ~0;
905 priv->xmitAck = ~0;
906
907 /* Reset start time */
908 getmicrouptime(&priv->startTime);
909
910 /* Reset stats */
911 bzero(&priv->stats, sizeof(priv->stats));
912
913 /* "Stop" timers */
914 a->sackTimerPtr = NULL;
915 a->rackTimerPtr = NULL;
916}
917
918/*
919 * Return the current time scaled & translated to our internally used format.
920 */
921static pptptime_t
922ng_pptpgre_time(node_p node)
923{
924 const priv_p priv = node->private;
925 struct timeval tv;
926 pptptime_t t;
927
928 microuptime(&tv);
929 if (tv.tv_sec < priv->startTime.tv_sec
930 || (tv.tv_sec == priv->startTime.tv_sec
931 && tv.tv_usec < priv->startTime.tv_usec))
932 return (0);
933 timevalsub(&tv, &priv->startTime);
934 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
935 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
936 return(t);
937}
938