usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / pptpd / ctrlpacket.c
blob65d38d295dc9729509893974133ad6eb0a8d5306
1 /*
2 * ctrlpacket.c
4 * PPTP Control Message packet reading, formatting and writing.
6 * $Id: ctrlpacket.c,v 1.6 2005/08/03 09:10:59 quozl Exp $
7 */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
13 #if HAVE_SYSLOG_H
14 #include <syslog.h>
15 #else
16 #include "our_syslog.h"
17 #endif
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <time.h>
24 #include <sys/time.h>
25 #include <netinet/in.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
30 #include "pptpdefs.h"
31 #include "pptpctrl.h"
32 #include "ctrlpacket.h"
34 #ifndef HAVE_STRERROR
35 #include "compat.h"
36 #endif
38 /* Local function prototypes */
39 static ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *ctrl_message_type);
40 static void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
41 static void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
42 static void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
43 static void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
44 static void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
45 static void deal_set_link_info(unsigned char *packet);
46 static u_int16_t getcall();
47 static u_int16_t freecall();
49 #if notyet
50 static int make_out_call_rqst(unsigned char *rply_packet, ssize_t * rply_size);
51 #endif
54 * read_pptp_packet
56 * Sees if a packet can be read and if so what type of packet it is. The
57 * method then calls the appropriate function to examine the details of the
58 * packet and form a suitable reply packet.
60 * args: clientFd (IN) - Client socket to read from.
61 * packet (OUT) - Packet read from the client.
62 * rply_packet (OUT) - Reply packet for the client.
63 * rply_size (OUT) - Size of the reply packet.
65 * retn: PPTP control message type of the packet on success.
66 * -1 on retryable error.
67 * 0 on error to abort on.
69 int read_pptp_packet(int clientFd, unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
72 size_t bytes_read;
73 int pptp_ctrl_type = 0; /* Control Message Type */
75 /* read a packet and parse header */
76 if ((bytes_read = read_pptp_header(clientFd, packet, &pptp_ctrl_type)) <= 0) {
77 /* error reading packet */
78 syslog(LOG_ERR, "CTRL: couldn't read packet header (%s)", bytes_read ? "retry" : "exit");
79 return bytes_read;
82 /* launch appropriate method to form suitable reply to the packet */
83 switch (pptp_ctrl_type) {
84 case START_CTRL_CONN_RQST: /* Start Control Connection Request */
85 deal_start_ctrl_conn(packet, rply_packet, rply_size);
86 break;
88 case STOP_CTRL_CONN_RQST:
89 deal_stop_ctrl_conn(packet, rply_packet, rply_size);
90 break;
92 case OUT_CALL_RQST: /* Outgoing Call Request */
93 deal_out_call(packet, rply_packet, rply_size);
94 break;
96 case ECHO_RQST: /* Echo Request */
97 deal_echo(packet, rply_packet, rply_size);
98 break;
100 case CALL_CLR_RQST: /* Call Clear Request (Disconnect Request) */
101 deal_call_clr(packet, rply_packet, rply_size);
102 break;
104 case SET_LINK_INFO: /* Set Link Info */
105 /* no reply packet but process it */
106 deal_set_link_info(packet);
107 break;
109 case ECHO_RPLY: /* Echo Reply */
110 case STOP_CTRL_CONN_RPLY: /* Stop Control Connection Reply */
111 case CALL_DISCONN_NTFY: /* Call Disconnect Notify */
112 /* no reply packet */
113 break;
115 default:
116 syslog(LOG_ERR, "CTRL: PPTP Control Message type %d not supported.", pptp_ctrl_type);
117 pptp_ctrl_type = -1;
120 return pptp_ctrl_type;
125 * send_pptp_packet
127 * Sends a PPTP packet to a file descriptor.
129 * args: clientFd (IN) - file descriptor to write the packet to.
130 * packet (IN) - the packet data to write.
131 * packet_size (IN) - the packet size.
133 * retn: Number of bytes written on success.
134 * -1 on write failure.
136 size_t send_pptp_packet(int clientFd, unsigned char *packet, size_t packet_size)
139 size_t bytes_written;
141 if ((bytes_written = write(clientFd, packet, packet_size)) == -1) {
142 /* write failed */
143 syslog(LOG_ERR, "CTRL: Couldn't write packet to client.");
144 return -1;
146 } else {
147 /* debugging */
148 if (pptpctrl_debug) {
149 syslog(LOG_DEBUG, "CTRL: I wrote %d bytes to the client.", packet_size);
150 syslog(LOG_DEBUG, "CTRL: Sent packet to client");
152 return bytes_written;
157 * ignoreErrno
159 * Check if an errno represents a read error which should be ignored, and
160 * put back to be select()ed on again later.
162 * Very similar to the function in Squid by Duane Wessels (under GPL).
164 * args: an errno value
166 * retn: 1 if the error is unimportant
167 * 0 if the error is important
169 static int ignoreErrno(int ierrno) {
170 switch (ierrno) {
171 case EAGAIN: /* nothing to read */
172 case EINTR: /* signal received */
173 #ifdef ERESTART
174 #if ERESTART != EINTR
175 case ERESTART: /* signal received, should restart syscall */
176 #endif
177 #endif
178 #if EWOULDBLOCK != EAGAIN
179 case EWOULDBLOCK: /* shouldn't get this one but anyway, just in case */
180 #endif
181 return 1;
182 default:
183 return 0;
188 * read_pptp_header
190 * Reads a packet from a file descriptor and determines whether it is a
191 * valid PPTP Control Message. If a valid PPTP Control Message is detected
192 * it extracts the Control Message type from the packet header.
194 * args: clientFd (IN) - Clients file descriptor.
195 * packet (OUT) - Packet we read from the client.
196 * pptp_ctrl_type (OUT) - PPTP Control Message type of the packet.
198 * retn: Number of bytes read on success.
199 * -1 on retryable error.
200 * 0 on error to exit on.
202 ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *pptp_ctrl_type)
205 ssize_t bytes_ttl, bytes_this; /* quantities read (total and this read) */
206 u_int16_t length; /* length of this packet */
207 struct pptp_header *header; /* the received header */
209 static char *buffer = NULL; /* buffer between calls */
210 static int buffered = 0; /* size of buffer */
212 *pptp_ctrl_type = 0; /* initialise return arg */
214 /* read any previously buffered data */
215 if (buffered) {
216 memcpy(packet, buffer, buffered);
217 free(buffer);
218 buffer = NULL;
219 bytes_ttl = buffered;
220 buffered = 0;
221 if (pptpctrl_debug)
222 syslog(LOG_DEBUG, "CTRL: Read in previous incomplete ctrl packet");
223 } else
224 bytes_ttl = 0;
226 /* try and get the length in */
227 if (bytes_ttl < 2) {
228 bytes_this = read(clientFd, packet + bytes_ttl, 2 - bytes_ttl);
229 switch (bytes_this) {
230 case -1:
231 if (ignoreErrno(errno)) {
232 /* re-tryable error, re-buffer and return */
233 if (bytes_ttl) {
234 buffered = bytes_ttl;
235 buffer = malloc(bytes_ttl);
236 if (!buffer)
237 return(0);
238 memcpy(buffer, packet, bytes_ttl);
240 syslog(LOG_ERR, "CTRL: Error reading ctrl packet length (bytes_ttl=%d): %s", bytes_ttl, strerror(errno));
241 return -1;
243 /* FALLTHRU */
244 case 0:
245 syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet length.");
246 return 0;
247 default:
248 bytes_ttl += bytes_this;
249 /* Not enough data to proceed */
250 if (bytes_ttl == 1) {
251 buffered = bytes_ttl;
252 buffer = malloc(bytes_ttl);
253 if (!buffer)
254 return(0);
255 memcpy(buffer, packet, bytes_ttl);
256 if (pptpctrl_debug)
257 syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet length, retry later");
258 return -1;
262 /* OK, we have (at least) the first 2 bytes, and there is data waiting
264 * length includes the header, so a length less than 2 is someone
265 * trying to hack into us or a badly corrupted packet.
266 * Why not require length to be at least 10? Since we later cast
267 * packet to struct pptp_header and use at least the 10 first bytes..
268 * Thanks to Timo Sirainen for mentioning this.
270 length = htons(*(u_int16_t *) packet);
271 if (length <= 10 || length > PPTP_MAX_CTRL_PCKT_SIZE) {
272 syslog(LOG_ERR, "CTRL: 11 < Control packet (length=%d) < "
273 "PPTP_MAX_CTRL_PCKT_SIZE (%d)",
274 length, PPTP_MAX_CTRL_PCKT_SIZE);
275 /* we loose sync (unless we malloc something big, which isn't a good
276 * idea - potential DoS) so we must close connection (draft states that
277 * if you loose sync you must close the control connection immediately)
279 return 0;
281 /* Now read the actual control packet */
282 bytes_this = read(clientFd, packet + bytes_ttl, length - bytes_ttl);
283 switch (bytes_this) {
284 case -1:
285 if(ignoreErrno(errno)) {
286 /* re-tryable error, re-buffer and return */
287 if (bytes_ttl) {
288 buffered = bytes_ttl;
289 buffer = malloc(bytes_ttl);
290 if (!buffer)
291 return(0);
292 memcpy(buffer, packet, bytes_ttl);
294 syslog(LOG_ERR, "CTRL: Error reading ctrl packet (bytes_ttl=%d,length=%d): %s", bytes_ttl, length, strerror(errno));
295 return -1;
297 /* FALLTHRU */
298 case 0:
299 syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet.");
300 return 0;
301 default:
302 bytes_ttl += bytes_this;
303 /* not enough data to proceed */
304 if (bytes_ttl != length) {
305 buffered = bytes_ttl;
306 buffer = malloc(bytes_ttl);
307 if (!buffer)
308 return(0);
309 memcpy(buffer, packet, bytes_ttl);
310 if (pptpctrl_debug)
311 syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet, retry later");
312 return -1;
316 /* We got one :-) */
318 /* Cast the packet into the PPTP Control Message format */
319 header = (struct pptp_header *) packet;
321 /* Packet sanity check on magic cookie */
322 if (ntohl(header->magic) != PPTP_MAGIC_COOKIE) {
323 /* Oops! Not a valid Control Message */
324 syslog(LOG_ERR, "CTRL: Bad magic cookie - lost syncronization, closing control connection.");
325 /* draft states loss of syncronization must result in
326 * immediate closing of the control connection
328 return 0;
330 /* Woohoo! Looks like we got a valid PPTP packet */
331 *pptp_ctrl_type = (int) (ntohs(header->ctrl_type));
332 if (pptpctrl_debug)
333 syslog(LOG_DEBUG, "CTRL: Received PPTP Control Message (type: %d)", *pptp_ctrl_type);
334 return bytes_ttl;
337 /* Macros to use in making response packets */
339 #define MAKE_CTRL_HEADER(where, what) \
340 where.header.length = htons(sizeof(where)); \
341 where.header.pptp_type = htons(PPTP_CTRL_MESSAGE); \
342 where.header.magic = htonl(PPTP_MAGIC_COOKIE); \
343 where.header.ctrl_type = htons(what); \
344 where.header.reserved0 = htons(RESERVED)
346 #define COPY_CTRL_PACKET(from, to, size) \
347 memcpy(to, &from, ((*size) = sizeof(from)))
349 #define DEBUG_PACKET(what) \
350 if(pptpctrl_debug) \
351 syslog(LOG_DEBUG, "CTRL: Made a " what " packet")
354 * deal_start_ctrl_conn
356 * This method 'deals' with a START-CONTROL-CONNECTION-REQUEST. After
357 * stripping down the connection request a suitable reply is formed and
358 * stored in 'rply_packet' ready for sending.
360 * args: packet (IN) - the packet that we have to deal with (should be a
361 * START-CONTROL-CONNECTION-REQUEST packet)
362 * rply_packet (OUT) - suitable reply to the 'packet' we got.
363 * rply_size (OUT) - size of the reply packet
365 void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
367 struct pptp_start_ctrl_conn_rqst *start_ctrl_conn_rqst;
368 struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply;
370 start_ctrl_conn_rqst = (struct pptp_start_ctrl_conn_rqst *) packet;
372 MAKE_CTRL_HEADER(start_ctrl_conn_rply, START_CTRL_CONN_RPLY);
373 start_ctrl_conn_rply.version = htons(PPTP_VERSION);
374 start_ctrl_conn_rply.result_code = CONNECTED;
375 start_ctrl_conn_rply.error_code = NO_ERROR;
376 start_ctrl_conn_rply.framing_cap = htons(OUR_FRAMING);
377 start_ctrl_conn_rply.bearer_cap = htons(OUR_BEARER);
378 start_ctrl_conn_rply.max_channels = htons(MAX_CHANNELS);
379 start_ctrl_conn_rply.firmware_rev = htons(PPTP_FIRMWARE_VERSION);
380 bzero(start_ctrl_conn_rply.hostname, MAX_HOSTNAME_SIZE);
381 strncpy((char *)start_ctrl_conn_rply.hostname, PPTP_HOSTNAME, MAX_HOSTNAME_SIZE);
382 bzero(start_ctrl_conn_rply.vendor, MAX_VENDOR_SIZE);
383 strncpy((char *)start_ctrl_conn_rply.vendor, PPTP_VENDOR, MAX_VENDOR_SIZE);
384 COPY_CTRL_PACKET(start_ctrl_conn_rply, rply_packet, rply_size);
385 DEBUG_PACKET("START CTRL CONN RPLY");
389 * deal_stop_ctrl_conn
391 * This method response to a STOP-CONTROL-CONNECTION-REQUEST with a
392 * STOP-CONTROL-CONNECTION-REPLY.
394 void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
396 struct pptp_stop_ctrl_conn_rply stop_ctrl_conn_rply;
398 MAKE_CTRL_HEADER(stop_ctrl_conn_rply, STOP_CTRL_CONN_RPLY);
399 stop_ctrl_conn_rply.result_code = DISCONNECTED;
400 stop_ctrl_conn_rply.error_code = NO_ERROR;
401 stop_ctrl_conn_rply.reserved1 = htons(RESERVED);
402 COPY_CTRL_PACKET(stop_ctrl_conn_rply, rply_packet, rply_size);
403 DEBUG_PACKET("STOP CTRL CONN RPLY");
407 * deal_out_call
409 * This method 'deals' with a OUT-GOING-CALL-REQUEST. After
410 * stripping down the request a suitable reply is formed and stored in
411 * 'rply_packet' ready for sending.
413 * args: packet (IN) - the packet that we have to deal with (should be a
414 * OUT-GOING-CALL-REQUEST packet)
415 * rply_packet (OUT) - suitable reply to the 'packet' we got.
416 * rply_size (OUT) - size of the reply packet
419 void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
421 u_int16_t pac_call_id;
422 struct pptp_out_call_rqst *out_call_rqst;
423 struct pptp_out_call_rply out_call_rply;
425 out_call_rqst = (struct pptp_out_call_rqst *) packet;
427 if ((pac_call_id = getcall()) == htons(-1)) {
428 /* XXX should reject call */
429 syslog(LOG_ERR, "CTRL: No free Call IDs!");
430 pac_call_id = 0;
432 MAKE_CTRL_HEADER(out_call_rply, OUT_CALL_RPLY);
433 /* call_id is used for ctrl, call_id_peer is used for GRE
434 * call_id_peer is what we were sent by the other end in ctrl initilization
436 out_call_rply.call_id = pac_call_id;
437 out_call_rply.call_id_peer = out_call_rqst->call_id;
438 out_call_rply.result_code = CONNECTED;
439 out_call_rply.error_code = NO_ERROR;
440 out_call_rply.cause_code = NO_ERROR;
441 /* maybe limit to pppd speed? but pppd doesn't accept 10Mbps as a speed and yet
442 * still performs at over 115200, eg, 60kbyte/sec and higher observed.
444 out_call_rply.speed = out_call_rqst->max_bps;
445 /* lets match their window size for now... was htons(PCKT_RECV_WINDOW_SIZE)
447 out_call_rply.pckt_recv_size = out_call_rqst->pckt_recv_size;
448 if(pptpctrl_debug)
449 syslog(LOG_DEBUG, "CTRL: Set parameters to %d maxbps, %d window size",
450 ntohl(out_call_rply.speed), ntohs(out_call_rply.pckt_recv_size));
451 out_call_rply.pckt_delay = htons(PCKT_PROCESS_DELAY);
452 out_call_rply.channel_id = htonl(CHANNEL_ID);
453 COPY_CTRL_PACKET(out_call_rply, rply_packet, rply_size);
454 DEBUG_PACKET("OUT CALL RPLY");
459 * deal_echo
461 * This method 'deals' with a ECHO-REQUEST. After stripping down the
462 * connection request a suitable reply is formed and stored in
463 * 'rply_packet' ready for sending.
465 * args: packet (IN) - the packet that we have to deal with (should be a
466 * ECHO-REQUEST packet)
467 * rply_packet (OUT) - suitable reply to the 'packet' we got.
468 * rply_size (OUT) - size of the reply packet
471 void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
473 struct pptp_echo_rqst *echo_rqst;
474 struct pptp_echo_rply echo_rply;
476 echo_rqst = (struct pptp_echo_rqst *) packet;
478 MAKE_CTRL_HEADER(echo_rply, ECHO_RPLY);
479 echo_rply.identifier = echo_rqst->identifier;
480 echo_rply.result_code = CONNECTED;
481 echo_rply.error_code = NO_ERROR;
482 echo_rply.reserved1 = htons(RESERVED);
483 COPY_CTRL_PACKET(echo_rply, rply_packet, rply_size);
484 DEBUG_PACKET("ECHO RPLY");
488 * deal_call_clr
490 * This method 'deals' with a CALL-CLEAR-REQUEST. After stripping down the
491 * connection request a suitable reply is formed and stored in
492 * 'rply_packet' ready for sending.
494 * args: packet (IN) - the packet that we have to deal with (should be a
495 * CALL-CLEAR-REQUEST packet)
496 * rply_packet (OUT) - suitable reply to the 'packet' we got.
497 * rply_size (OUT) - size of the reply packet
500 void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t *rply_size)
502 struct pptp_call_disconn_ntfy call_disconn_ntfy;
503 u_int16_t pac_call_id;
505 /* Form a reply
506 * The reply packet is a CALL-DISCONECT-NOTIFY
507 * In single call mode we don't care what peer's call ID is, so don't even bother looking
509 if ((pac_call_id = freecall()) == htons(-1)) {
510 /* XXX should return an error */
511 syslog(LOG_ERR, "CTRL: Could not free Call ID [call clear]!");
513 MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY);
514 call_disconn_ntfy.call_id = pac_call_id;
515 call_disconn_ntfy.result_code = CALL_CLEAR_REQUEST; /* disconnected by call_clr_rqst */
516 call_disconn_ntfy.error_code = NO_ERROR;
517 call_disconn_ntfy.cause_code = htons(NO_ERROR);
518 call_disconn_ntfy.reserved1 = htons(RESERVED);
519 memset(call_disconn_ntfy.call_stats, 0, 128);
520 COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size);
521 DEBUG_PACKET("CALL DISCONNECT RPLY");
525 * deal_set_link_info
527 * @FIXME This function is *not* completed
529 * This method 'deals' with a SET-LINK-INFO. After stripping down the
530 * connection request a suitable reply is formed and stored in
531 * 'rply_packet' ready for sending.
533 * args: packet (IN) - the packet that we have to deal with (should be a
534 * SET-LINK-INFO packet)
535 * rply_packet (OUT) - suitable reply to the 'packet' we got.
536 * rply_size (OUT) - size of the reply packet
539 void deal_set_link_info(unsigned char *packet)
541 struct pptp_set_link_info *set_link_info;
543 set_link_info = (struct pptp_set_link_info *) packet;
544 if(set_link_info->send_accm != 0xffffffff || set_link_info->recv_accm != 0xffffffff)
545 syslog(LOG_ERR, "CTRL: Ignored a SET LINK INFO packet with real ACCMs!");
546 else if(pptpctrl_debug)
547 syslog(LOG_DEBUG, "CTRL: Got a SET LINK INFO packet with standard ACCMs");
550 void make_echo_req_packet(unsigned char *rply_packet, ssize_t * rply_size, u_int32_t echo_id)
552 struct pptp_echo_rqst echo_packet;
554 MAKE_CTRL_HEADER(echo_packet, ECHO_RQST);
555 echo_packet.identifier = echo_id;
556 COPY_CTRL_PACKET(echo_packet, rply_packet, rply_size);
557 DEBUG_PACKET("ECHO REQ");
560 void make_stop_ctrl_req(unsigned char *rply_packet, ssize_t * rply_size)
562 struct pptp_stop_ctrl_conn_rqst stop_ctrl;
564 MAKE_CTRL_HEADER(stop_ctrl, STOP_CTRL_CONN_RQST);
565 stop_ctrl.reason = GENERAL_STOP_CTRL;
566 stop_ctrl.reserved1 = RESERVED;
567 stop_ctrl.reserved2 = htons(RESERVED);
568 COPY_CTRL_PACKET(stop_ctrl, rply_packet, rply_size);
569 DEBUG_PACKET("STOP CTRL REQ");
572 void make_call_admin_shutdown(unsigned char *rply_packet, ssize_t * rply_size)
574 struct pptp_call_disconn_ntfy call_disconn_ntfy;
575 u_int16_t pac_call_id;
577 /* Form a reply
578 * The reply packet is a CALL-DISCONECT-NOTIFY
579 * In single call mode we don't care what peer's call ID is, so don't even bother looking
581 if ((pac_call_id = freecall()) == htons(-1)) {
582 /* XXX should return an error */
583 syslog(LOG_ERR, "CTRL: Could not free Call ID [admin shutdown]!");
585 MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY);
586 call_disconn_ntfy.call_id = pac_call_id;
587 call_disconn_ntfy.result_code = ADMIN_SHUTDOWN; /* disconnected by admin shutdown */
588 call_disconn_ntfy.error_code = NO_ERROR;
589 call_disconn_ntfy.cause_code = htons(NO_ERROR);
590 call_disconn_ntfy.reserved1 = htons(RESERVED);
591 memset(call_disconn_ntfy.call_stats, 0, 128);
592 COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size);
593 DEBUG_PACKET("CALL DISCONNECT RPLY");
596 #if PNS_MODE
597 /* out of date. really PNS isn't 'trivially different', it's quite different */
599 #define C_BITS (sizeof(unsigned int) * 8)
600 #define C_SEG(x) (x/C_BITS)
601 #define C_BIT(x) ((1U)<<(x%C_BITS))
602 static unsigned int activeCalls[(MAX_CALLS / C_BITS) + 1];
605 * get_call_id
607 * Assigns a call ID and peer call ID to the session.
609 * args: call_id (OUT) - the call ID for the session
610 * retn: 0 on success, -1 on failure
612 int get_call_id(u_int16_t * loc)
614 for (i = 0; i < MAX_CALLS; i++) {
615 if (!(activeCalls[C_SEG(i)] & C_BIT(i))) {
616 activeCalls[C_SEG(i)] |= C_BIT(i);
617 *loc = i;
618 return 0;
621 return -1;
625 * free_call_id
627 * args: call_id (IN) - the call ID for a terminated session
628 * retn: 0 on success, -1 on failure
630 int free_call_id(u_int16_t call_id)
632 if (!(activeCalls[C_SEG(i)] & C_BIT(i)))
633 return -1;
634 activeCalls[C_SEG(i)] &= ~C_BIT(i);
635 return 0;
637 #else
638 static int _pac_call_id;
639 static u_int16_t _pac_init = 0;
642 * getcall
644 * Assigns a call ID to the session and stores/returns it
646 * we only permit one call at a time, so the chance of wrapping 65k on one
647 * control connection is zero to none...
649 u_int16_t getcall()
651 static u_int16_t i = 0;
652 extern u_int16_t unique_call_id;
654 /* Start with a random Call ID. This is to allocate unique
655 * Call ID's across multiple TCP PPTP connections. In this
656 * way remote clients masqueraded by a firewall will put
657 * unique peer call ID's into GRE packets that will have the
658 * same source IP address of the firewall. */
660 if (!i) {
661 if (unique_call_id == 0xFFFF) {
662 struct timeval tv;
663 if (gettimeofday(&tv, NULL) == 0) {
664 i = ((tv.tv_sec & 0x0FFF) << 4) +
665 (tv.tv_usec >> 16);
667 } else {
668 i = unique_call_id;
672 if(!_pac_init) {
673 _pac_call_id = htons(-1);
674 _pac_init = 1;
676 if(_pac_call_id != htons(-1))
677 syslog(LOG_ERR, "CTRL: Asked to allocate call id when call open, not handled well");
678 _pac_call_id = htons(i);
679 i++;
680 return _pac_call_id;
684 * freecall
686 * Notes termination of current call
688 * retn: -1 on failure, PAC call ID on success
690 u_int16_t freecall()
692 u_int16_t ret;
694 if(!_pac_init) {
695 _pac_call_id = htons(-1);
696 _pac_init = 1;
698 ret = _pac_call_id;
699 if(_pac_call_id == htons(-1))
700 syslog(LOG_ERR, "CTRL: Asked to free call when no call open, not handled well");
701 _pac_call_id = htons(-1);
702 return ret;
704 #endif