1/*
2 * ctrlpacket.c
3 *
4 * PPTP Control Message packet reading, formatting and writing.
5 *
6 * $Id: ctrlpacket.c,v 1.6 2005/08/03 09:10:59 quozl Exp $
7 */
8
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif
12
13#if HAVE_SYSLOG_H
14#include <syslog.h>
15#else
16#include "our_syslog.h"
17#endif
18
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>
29
30#include "pptpdefs.h"
31#include "pptpctrl.h"
32#include "ctrlpacket.h"
33
34#ifndef HAVE_STRERROR
35#include "compat.h"
36#endif
37
38/* Local function prototypes */
39static ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *ctrl_message_type);
40static void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
41static void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
42static void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
43static void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
44static void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
45static void deal_set_link_info(unsigned char *packet);
46static u_int16_t getcall();
47static u_int16_t freecall();
48
49#if notyet
50static int make_out_call_rqst(unsigned char *rply_packet, ssize_t * rply_size);
51#endif
52
53/*
54 * read_pptp_packet
55 *
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.
59 *
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.
64 *
65 * retn:        PPTP control message type of the packet on success.
66 *              -1 on retryable error.
67 *              0 on error to abort on.
68 */
69int read_pptp_packet(int clientFd, unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
70{
71
72	size_t bytes_read;
73	int pptp_ctrl_type = 0;	/* Control Message Type */
74
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;
80	}
81
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;
87
88	case STOP_CTRL_CONN_RQST:
89		deal_stop_ctrl_conn(packet, rply_packet, rply_size);
90		break;
91
92	case OUT_CALL_RQST:		/* Outgoing Call Request */
93		deal_out_call(packet, rply_packet, rply_size);
94		break;
95
96	case ECHO_RQST:			/* Echo Request */
97		deal_echo(packet, rply_packet, rply_size);
98		break;
99
100	case CALL_CLR_RQST:		/* Call Clear Request (Disconnect Request) */
101		deal_call_clr(packet, rply_packet, rply_size);
102		break;
103
104	case SET_LINK_INFO:		/* Set Link Info */
105		/* no reply packet but process it */
106		deal_set_link_info(packet);
107		break;
108
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;
114
115	default:
116		syslog(LOG_ERR, "CTRL: PPTP Control Message type %d not supported.", pptp_ctrl_type);
117		pptp_ctrl_type = -1;
118	}
119
120	return pptp_ctrl_type;
121}
122
123
124/*
125 * send_pptp_packet
126 *
127 * Sends a PPTP packet to a file descriptor.
128 *
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.
132 *
133 * retn:        Number of bytes written on success.
134 *              -1 on write failure.
135 */
136size_t send_pptp_packet(int clientFd, unsigned char *packet, size_t packet_size)
137{
138
139	size_t bytes_written;
140
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;
145
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");
151		}
152		return bytes_written;
153	}
154}
155
156/*
157 * ignoreErrno
158 *
159 * Check if an errno represents a read error which should be ignored, and
160 * put back to be select()ed on again later.
161 *
162 * Very similar to the function in Squid by Duane Wessels (under GPL).
163 *
164 * args: an errno value
165 *
166 * retn: 1 if the error is unimportant
167 *       0 if the error is important
168 */
169static 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;
184	}
185}
186
187/*
188 * read_pptp_header
189 *
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.
193 *
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.
197 *
198 * retn:        Number of bytes read on success.
199 *              -1 on retryable error.
200 *              0 on error to exit on.
201 */
202ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *pptp_ctrl_type)
203{
204
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 */
208
209	static char *buffer = NULL;	/* buffer between calls */
210	static int buffered = 0;	/* size of buffer */
211
212	*pptp_ctrl_type = 0;		/* initialise return arg	*/
213
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;
225
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);
239				}
240				syslog(LOG_ERR, "CTRL: Error reading ctrl packet length (bytes_ttl=%d): %s", bytes_ttl, strerror(errno));
241				return -1;
242			}
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;
259			}
260		}
261	}
262	/* OK, we have (at least) the first 2 bytes, and there is data waiting
263	 *
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.
269	 */
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)
278		 */
279		return 0;
280	}
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);
293			}
294			syslog(LOG_ERR, "CTRL: Error reading ctrl packet (bytes_ttl=%d,length=%d): %s", bytes_ttl, length, strerror(errno));
295			return -1;
296		}
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;
313		}
314	}
315
316	/* We got one :-) */
317
318	/* Cast the packet into the PPTP Control Message format */
319	header = (struct pptp_header *) packet;
320
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
327		 */
328		return 0;
329	}
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;
335}
336
337/* Macros to use in making response packets */
338
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)
345
346#define COPY_CTRL_PACKET(from, to, size) \
347	memcpy(to, &from, ((*size) = sizeof(from)))
348
349#define DEBUG_PACKET(what) \
350	if(pptpctrl_debug) \
351		syslog(LOG_DEBUG, "CTRL: Made a " what " packet")
352
353/*
354 * deal_start_ctrl_conn
355 *
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.
359 *
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
364 */
365void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
366{
367	struct pptp_start_ctrl_conn_rqst *start_ctrl_conn_rqst;
368	struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply;
369
370	start_ctrl_conn_rqst = (struct pptp_start_ctrl_conn_rqst *) packet;
371
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");
386}
387
388/*
389 * deal_stop_ctrl_conn
390 *
391 * This method response to a STOP-CONTROL-CONNECTION-REQUEST with a
392 * STOP-CONTROL-CONNECTION-REPLY.
393 */
394void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
395{
396	struct pptp_stop_ctrl_conn_rply stop_ctrl_conn_rply;
397
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");
404}
405
406/*
407 * deal_out_call
408 *
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.
412 *
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
417 *
418 */
419void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
420{
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;
424
425	out_call_rqst = (struct pptp_out_call_rqst *) packet;
426
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;
431	}
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
435	 */
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.
443	 */
444	out_call_rply.speed = out_call_rqst->max_bps;
445	/* lets match their window size for now... was htons(PCKT_RECV_WINDOW_SIZE)
446	 */
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");
455}
456
457
458/*
459 * deal_echo
460 *
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.
464 *
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
469 *
470 */
471void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
472{
473	struct pptp_echo_rqst *echo_rqst;
474	struct pptp_echo_rply echo_rply;
475
476	echo_rqst = (struct pptp_echo_rqst *) packet;
477
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");
485}
486
487/*
488 * deal_call_clr
489 *
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.
493 *
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
498 *
499 */
500void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t *rply_size)
501{
502	struct pptp_call_disconn_ntfy call_disconn_ntfy;
503	u_int16_t pac_call_id;
504
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
508	 */
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]!");
512	}
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");
522}
523
524/*
525 * deal_set_link_info
526 *
527 * @FIXME This function is *not* completed
528 *
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.
532 *
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
537 *
538 */
539void deal_set_link_info(unsigned char *packet)
540{
541	struct pptp_set_link_info *set_link_info;
542
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");
548}
549
550void make_echo_req_packet(unsigned char *rply_packet, ssize_t * rply_size, u_int32_t echo_id)
551{
552	struct pptp_echo_rqst echo_packet;
553
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");
558}
559
560void make_stop_ctrl_req(unsigned char *rply_packet, ssize_t * rply_size)
561{
562	struct pptp_stop_ctrl_conn_rqst stop_ctrl;
563
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");
570}
571
572void make_call_admin_shutdown(unsigned char *rply_packet, ssize_t * rply_size)
573{
574	struct pptp_call_disconn_ntfy call_disconn_ntfy;
575	u_int16_t pac_call_id;
576
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
580	 */
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]!");
584	}
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");
594}
595
596#if PNS_MODE
597/* out of date.  really PNS isn't 'trivially different', it's quite different */
598
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))
602static unsigned int activeCalls[(MAX_CALLS / C_BITS) + 1];
603
604/*
605 * get_call_id
606 *
607 * Assigns a call ID and peer call ID to the session.
608 *
609 * args: call_id (OUT) - the call ID for the session
610 * retn: 0 on success, -1 on failure
611 */
612int get_call_id(u_int16_t * loc)
613{
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;
619		}
620	}
621	return -1;
622}
623
624/*
625 * free_call_id
626 *
627 * args: call_id (IN) - the call ID for a terminated session
628 * retn: 0 on success, -1 on failure
629 */
630int free_call_id(u_int16_t call_id)
631{
632	if (!(activeCalls[C_SEG(i)] & C_BIT(i)))
633		return -1;
634	activeCalls[C_SEG(i)] &= ~C_BIT(i);
635	return 0;
636}
637#else
638static int _pac_call_id;
639static u_int16_t _pac_init = 0;
640
641/*
642 * getcall
643 *
644 * Assigns a call ID to the session and stores/returns it
645 *
646 * we only permit one call at a time, so the chance of wrapping 65k on one
647 * control connection is zero to none...
648 */
649u_int16_t getcall()
650{
651	static u_int16_t i = 0;
652	extern u_int16_t unique_call_id;
653
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. */
659
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);
666			}
667		} else {
668			i = unique_call_id;
669		}
670	}
671
672	if(!_pac_init) {
673		_pac_call_id = htons(-1);
674		_pac_init = 1;
675	}
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;
681}
682
683/*
684 * freecall
685 *
686 * Notes termination of current call
687 *
688 * retn: -1 on failure, PAC call ID on success
689 */
690u_int16_t freecall()
691{
692	u_int16_t ret;
693
694	if(!_pac_init) {
695		_pac_call_id = htons(-1);
696		_pac_init = 1;
697	}
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;
703}
704#endif
705