• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/accel-pptpd/pptpd-1.3.3/
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#include <net/if.h>
35#include <net/ethernet.h>
36//#include "if_pppox.h" //Yau del
37#include <linux/if_pppox.h>
38
39#ifndef HAVE_STRERROR
40#include "compat.h"
41#endif
42
43/* Local function prototypes */
44static ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *ctrl_message_type);
45static void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
46static void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
47static void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
48static void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
49static void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size);
50static void deal_set_link_info(unsigned char *packet);
51static u_int16_t getcall();
52static u_int16_t freecall();
53
54#if notyet
55static int make_out_call_rqst(unsigned char *rply_packet, ssize_t * rply_size);
56#endif
57
58/*
59 * read_pptp_packet
60 *
61 * Sees if a packet can be read and if so what type of packet it is. The
62 * method then calls the appropriate function to examine the details of the
63 * packet and form a suitable reply packet.
64 *
65 * args:        clientFd (IN) - Client socket to read from.
66 *              packet (OUT) - Packet read from the client.
67 *              rply_packet (OUT) - Reply packet for the client.
68 *              rply_size (OUT) - Size of the reply packet.
69 *
70 * retn:        PPTP control message type of the packet on success.
71 *              -1 on retryable error.
72 *              0 on error to abort on.
73 */
74int read_pptp_packet(int clientFd, unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
75{
76
77	size_t bytes_read;
78	int pptp_ctrl_type = 0;	/* Control Message Type */
79
80	/* read a packet and parse header */
81	if ((bytes_read = read_pptp_header(clientFd, packet, &pptp_ctrl_type)) <= 0) {
82		/* error reading packet */
83		syslog(LOG_ERR, "CTRL: couldn't read packet header (%s)", bytes_read ? "retry" : "exit");
84		return bytes_read;
85	}
86
87	/* launch appropriate method to form suitable reply to the packet */
88	switch (pptp_ctrl_type) {
89	case START_CTRL_CONN_RQST:	/* Start Control Connection Request */
90		deal_start_ctrl_conn(packet, rply_packet, rply_size);
91		break;
92
93	case STOP_CTRL_CONN_RQST:
94		deal_stop_ctrl_conn(packet, rply_packet, rply_size);
95		break;
96
97	case OUT_CALL_RQST:		/* Outgoing Call Request */
98		deal_out_call(packet, rply_packet, rply_size);
99		break;
100
101	case ECHO_RQST:			/* Echo Request */
102		deal_echo(packet, rply_packet, rply_size);
103		break;
104
105	case CALL_CLR_RQST:		/* Call Clear Request (Disconnect Request) */
106		deal_call_clr(packet, rply_packet, rply_size);
107		break;
108
109	case SET_LINK_INFO:		/* Set Link Info */
110		/* no reply packet but process it */
111		deal_set_link_info(packet);
112		break;
113
114	case ECHO_RPLY:			/* Echo Reply */
115	case STOP_CTRL_CONN_RPLY:	/* Stop Control Connection Reply */
116	case CALL_DISCONN_NTFY:		/* Call Disconnect Notify */
117		/* no reply packet */
118		break;
119
120	default:
121		syslog(LOG_ERR, "CTRL: PPTP Control Message type %d not supported.", pptp_ctrl_type);
122		pptp_ctrl_type = -1;
123	}
124
125	return pptp_ctrl_type;
126}
127
128
129/*
130 * send_pptp_packet
131 *
132 * Sends a PPTP packet to a file descriptor.
133 *
134 * args:        clientFd (IN) - file descriptor to write the packet to.
135 *              packet (IN) - the packet data to write.
136 *              packet_size (IN) - the packet size.
137 *
138 * retn:        Number of bytes written on success.
139 *              -1 on write failure.
140 */
141size_t send_pptp_packet(int clientFd, unsigned char *packet, size_t packet_size)
142{
143
144	size_t bytes_written;
145
146	if ((bytes_written = write(clientFd, packet, packet_size)) == -1) {
147		/* write failed */
148		syslog(LOG_ERR, "CTRL: Couldn't write packet to client.");
149		return -1;
150
151	} else {
152		/* debugging */
153		if (pptpctrl_debug) {
154			syslog(LOG_DEBUG, "CTRL: I wrote %i bytes to the client.", (int)packet_size);
155			syslog(LOG_DEBUG, "CTRL: Sent packet to client");
156		}
157		return bytes_written;
158	}
159}
160
161/*
162 * ignoreErrno
163 *
164 * Check if an errno represents a read error which should be ignored, and
165 * put back to be select()ed on again later.
166 *
167 * Very similar to the function in Squid by Duane Wessels (under GPL).
168 *
169 * args: an errno value
170 *
171 * retn: 1 if the error is unimportant
172 *       0 if the error is important
173 */
174static int ignoreErrno(int ierrno) {
175	switch (ierrno) {
176	case EAGAIN:		/* nothing to read */
177	case EINTR:		/* signal received */
178#ifdef ERESTART
179#if ERESTART != EINTR
180	case ERESTART:		/* signal received, should restart syscall */
181#endif
182#endif
183#if EWOULDBLOCK != EAGAIN
184	case EWOULDBLOCK:	/* shouldn't get this one but anyway, just in case */
185#endif
186		return 1;
187	default:
188		return 0;
189	}
190}
191
192/*
193 * read_pptp_header
194 *
195 * Reads a packet from a file descriptor and determines whether it is a
196 * valid PPTP Control Message. If a valid PPTP Control Message is detected
197 * it extracts the Control Message type from the packet header.
198 *
199 * args:        clientFd (IN) - Clients file descriptor.
200 *              packet (OUT) - Packet we read from the client.
201 *              pptp_ctrl_type (OUT) - PPTP Control Message type of the packet.
202 *
203 * retn:        Number of bytes read on success.
204 *              -1 on retryable error.
205 *              0 on error to exit on.
206 */
207ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *pptp_ctrl_type)
208{
209
210	ssize_t bytes_ttl, bytes_this;	/* quantities read (total and this read) */
211	u_int16_t length;		/* length of this packet */
212	struct pptp_header *header;	/* the received header */
213
214	static char *buffer = NULL;	/* buffer between calls */
215	static int buffered = 0;	/* size of buffer */
216
217	*pptp_ctrl_type = 0;		/* initialise return arg	*/
218
219	/* read any previously buffered data */
220	if (buffered) {
221		memcpy(packet, buffer, buffered);
222		free(buffer);
223		buffer = NULL;
224		bytes_ttl = buffered;
225		buffered = 0;
226		if (pptpctrl_debug)
227			syslog(LOG_DEBUG, "CTRL: Read in previous incomplete ctrl packet");
228	} else
229		bytes_ttl = 0;
230
231	/* try and get the length in */
232	if (bytes_ttl < 2) {
233		bytes_this = read(clientFd, packet + bytes_ttl, 2 - bytes_ttl);
234		switch (bytes_this) {
235		case -1:
236			if (ignoreErrno(errno)) {
237				/* re-tryable error, re-buffer and return */
238				if (bytes_ttl) {
239					buffered = bytes_ttl;
240					buffer = malloc(bytes_ttl);
241					if (!buffer)
242						return(0);
243					memcpy(buffer, packet, bytes_ttl);
244				}
245				syslog(LOG_ERR, "CTRL: Error reading ctrl packet length (bytes_ttl=%i): %s", (int)bytes_ttl, strerror(errno));
246				return -1;
247			}
248			/* FALLTHRU */
249		case 0:
250			syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet length.");
251			return 0;
252		default:
253			bytes_ttl += bytes_this;
254			/* Not enough data to proceed */
255			if (bytes_ttl == 1) {
256				buffered = bytes_ttl;
257				buffer = malloc(bytes_ttl);
258				if (!buffer)
259					return(0);
260				memcpy(buffer, packet, bytes_ttl);
261				if (pptpctrl_debug)
262					syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet length, retry later");
263				return -1;
264			}
265		}
266	}
267	/* OK, we have (at least) the first 2 bytes, and there is data waiting
268	 *
269	 * length includes the header,  so a length less than 2 is someone
270	 * trying to hack into us or a badly corrupted packet.
271	 * Why not require length to be at least 10? Since we later cast
272	 * packet to struct pptp_header and use at least the 10 first bytes..
273	 * Thanks to Timo Sirainen for mentioning this.
274	 */
275	length = htons(*(u_int16_t *) packet);
276	if (length <= 10 || length > PPTP_MAX_CTRL_PCKT_SIZE) {
277		syslog(LOG_ERR, "CTRL: 11 < Control packet (length=%d) < "
278				"PPTP_MAX_CTRL_PCKT_SIZE (%d)",
279				length, PPTP_MAX_CTRL_PCKT_SIZE);
280		/* we loose sync (unless we malloc something big, which isn't a good
281		 * idea - potential DoS) so we must close connection (draft states that
282		 * if you loose sync you must close the control connection immediately)
283		 */
284		return 0;
285	}
286	/* Now read the actual control packet */
287	bytes_this = read(clientFd, packet + bytes_ttl, length - bytes_ttl);
288	switch (bytes_this) {
289	case -1:
290		if(ignoreErrno(errno)) {
291			/* re-tryable error, re-buffer and return */
292			if (bytes_ttl) {
293				buffered = bytes_ttl;
294				buffer = malloc(bytes_ttl);
295				if (!buffer)
296					return(0);
297				memcpy(buffer, packet, bytes_ttl);
298			}
299			syslog(LOG_ERR, "CTRL: Error reading ctrl packet (bytes_ttl=%d,length=%d): %s", (int)bytes_ttl, (int)length, strerror(errno));
300			return -1;
301		}
302		/* FALLTHRU */
303	case 0:
304		syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet.");
305		return 0;
306	default:
307		bytes_ttl += bytes_this;
308		/* not enough data to proceed */
309		if (bytes_ttl != length) {
310			buffered = bytes_ttl;
311			buffer = malloc(bytes_ttl);
312			if (!buffer)
313				return(0);
314			memcpy(buffer, packet, bytes_ttl);
315			if (pptpctrl_debug)
316				syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet, retry later");
317			return -1;
318		}
319	}
320
321	/* We got one :-) */
322
323	/* Cast the packet into the PPTP Control Message format */
324	header = (struct pptp_header *) packet;
325
326	/* Packet sanity check on magic cookie */
327	if (ntohl(header->magic) != PPTP_MAGIC_COOKIE) {
328		/* Oops! Not a valid Control Message */
329		syslog(LOG_ERR, "CTRL: Bad magic cookie - lost syncronization, closing control connection.");
330		/* draft states loss of syncronization must result in
331		 * immediate closing of the control connection
332		 */
333		return 0;
334	}
335	/* Woohoo! Looks like we got a valid PPTP packet */
336	*pptp_ctrl_type = (int) (ntohs(header->ctrl_type));
337	if (pptpctrl_debug)
338		syslog(LOG_DEBUG, "CTRL: Received PPTP Control Message (type: %d)", *pptp_ctrl_type);
339	return bytes_ttl;
340}
341
342/* Macros to use in making response packets */
343
344#define MAKE_CTRL_HEADER(where, what) \
345	where.header.length = htons(sizeof(where)); \
346	where.header.pptp_type = htons(PPTP_CTRL_MESSAGE); \
347	where.header.magic = htonl(PPTP_MAGIC_COOKIE); \
348	where.header.ctrl_type = htons(what); \
349	where.header.reserved0 = htons(RESERVED)
350
351#define COPY_CTRL_PACKET(from, to, size) \
352	memcpy(to, &from, ((*size) = sizeof(from)))
353
354#define DEBUG_PACKET(what) \
355	if(pptpctrl_debug) \
356		syslog(LOG_DEBUG, "CTRL: Made a " what " packet")
357
358/*
359 * deal_start_ctrl_conn
360 *
361 * This method 'deals' with a START-CONTROL-CONNECTION-REQUEST. After
362 * stripping down the connection request a suitable reply is formed and
363 * stored in 'rply_packet' ready for sending.
364 *
365 * args: packet (IN) - the packet that we have to deal with (should be a
366 *                     START-CONTROL-CONNECTION-REQUEST packet)
367 *       rply_packet (OUT) - suitable reply to the 'packet' we got.
368 *       rply_size (OUT) - size of the reply packet
369 */
370void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
371{
372	struct pptp_start_ctrl_conn_rqst *start_ctrl_conn_rqst;
373	struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply;
374
375	start_ctrl_conn_rqst = (struct pptp_start_ctrl_conn_rqst *) packet;
376
377	MAKE_CTRL_HEADER(start_ctrl_conn_rply, START_CTRL_CONN_RPLY);
378	start_ctrl_conn_rply.version = htons(PPTP_VERSION);
379	start_ctrl_conn_rply.result_code = CONNECTED;
380	start_ctrl_conn_rply.error_code = NO_ERROR;
381	start_ctrl_conn_rply.framing_cap = htons(OUR_FRAMING);
382	start_ctrl_conn_rply.bearer_cap = htons(OUR_BEARER);
383	start_ctrl_conn_rply.max_channels = htons(MAX_CHANNELS);
384	start_ctrl_conn_rply.firmware_rev = htons(PPTP_FIRMWARE_VERSION);
385	bzero(start_ctrl_conn_rply.hostname, MAX_HOSTNAME_SIZE);
386	strncpy((char *)start_ctrl_conn_rply.hostname, PPTP_HOSTNAME, MAX_HOSTNAME_SIZE);
387	bzero(start_ctrl_conn_rply.vendor, MAX_VENDOR_SIZE);
388	strncpy((char *)start_ctrl_conn_rply.vendor, PPTP_VENDOR, MAX_VENDOR_SIZE);
389	COPY_CTRL_PACKET(start_ctrl_conn_rply, rply_packet, rply_size);
390	DEBUG_PACKET("START CTRL CONN RPLY");
391}
392
393/*
394 * deal_stop_ctrl_conn
395 *
396 * This method response to a STOP-CONTROL-CONNECTION-REQUEST with a
397 * STOP-CONTROL-CONNECTION-REPLY.
398 */
399void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
400{
401	struct pptp_stop_ctrl_conn_rply stop_ctrl_conn_rply;
402
403	MAKE_CTRL_HEADER(stop_ctrl_conn_rply, STOP_CTRL_CONN_RPLY);
404        stop_ctrl_conn_rply.result_code = DISCONNECTED;
405        stop_ctrl_conn_rply.error_code = NO_ERROR;
406        stop_ctrl_conn_rply.reserved1 = htons(RESERVED);
407	COPY_CTRL_PACKET(stop_ctrl_conn_rply, rply_packet, rply_size);
408	DEBUG_PACKET("STOP CTRL CONN RPLY");
409}
410
411/*
412 * deal_out_call
413 *
414 * This method 'deals' with a OUT-GOING-CALL-REQUEST. After
415 * stripping down the request a suitable reply is formed and stored in
416 * 'rply_packet' ready for sending.
417 *
418 * args: packet (IN) - the packet that we have to deal with (should be a
419 *                      OUT-GOING-CALL-REQUEST packet)
420 *       rply_packet (OUT) - suitable reply to the 'packet' we got.
421 *       rply_size (OUT) - size of the reply packet
422 *
423 */
424void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
425{
426	u_int16_t pac_call_id;
427	struct pptp_out_call_rqst *out_call_rqst;
428	struct pptp_out_call_rply out_call_rply;
429
430	out_call_rqst = (struct pptp_out_call_rqst *) packet;
431
432	if ((pac_call_id = getcall()) == htons(-1)) {
433		/* XXX should reject call */
434		syslog(LOG_ERR, "CTRL: No free Call IDs!");
435		pac_call_id = 0;
436	}
437	MAKE_CTRL_HEADER(out_call_rply, OUT_CALL_RPLY);
438	/* call_id is used for ctrl, call_id_peer is used for GRE
439	 * call_id_peer is what we were sent by the other end in ctrl initilization
440	 */
441	out_call_rply.call_id = pac_call_id;
442	out_call_rply.call_id_peer = out_call_rqst->call_id;
443	out_call_rply.result_code = CONNECTED;
444	out_call_rply.error_code = NO_ERROR;
445	out_call_rply.cause_code = NO_ERROR;
446	/* maybe limit to pppd speed? but pppd doesn't accept 10Mbps as a speed and yet
447	 * still performs at over 115200, eg, 60kbyte/sec and higher observed.
448	 */
449	out_call_rply.speed = out_call_rqst->max_bps;
450	/* lets match their window size for now... was htons(PCKT_RECV_WINDOW_SIZE)
451	 */
452	out_call_rply.pckt_recv_size = out_call_rqst->pckt_recv_size;
453	window=htons(out_call_rply.pckt_recv_size);
454	if(pptpctrl_debug)
455		syslog(LOG_DEBUG, "CTRL: Set parameters to %d maxbps, %d window size",
456			ntohl(out_call_rply.speed), ntohs(out_call_rply.pckt_recv_size));
457	out_call_rply.pckt_delay = htons(PCKT_PROCESS_DELAY);
458	out_call_rply.channel_id = htonl(CHANNEL_ID);
459	COPY_CTRL_PACKET(out_call_rply, rply_packet, rply_size);
460	DEBUG_PACKET("OUT CALL RPLY");
461}
462
463
464/*
465 * deal_echo
466 *
467 * This method 'deals' with a ECHO-REQUEST. After stripping down the
468 * connection request a suitable reply is formed and stored in
469 * 'rply_packet' ready for sending.
470 *
471 * args: packet (IN) - the packet that we have to deal with (should be a
472 *                      ECHO-REQUEST packet)
473 *       rply_packet (OUT) - suitable reply to the 'packet' we got.
474 *       rply_size (OUT) - size of the reply packet
475 *
476 */
477void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size)
478{
479	struct pptp_echo_rqst *echo_rqst;
480	struct pptp_echo_rply echo_rply;
481
482	echo_rqst = (struct pptp_echo_rqst *) packet;
483
484	MAKE_CTRL_HEADER(echo_rply, ECHO_RPLY);
485	echo_rply.identifier = echo_rqst->identifier;
486	echo_rply.result_code = CONNECTED;
487	echo_rply.error_code = NO_ERROR;
488	echo_rply.reserved1 = htons(RESERVED);
489	COPY_CTRL_PACKET(echo_rply, rply_packet, rply_size);
490	DEBUG_PACKET("ECHO RPLY");
491}
492
493/*
494 * deal_call_clr
495 *
496 * This method 'deals' with a CALL-CLEAR-REQUEST. After stripping down the
497 * connection request a suitable reply is formed and stored in
498 * 'rply_packet' ready for sending.
499 *
500 * args: packet (IN) - the packet that we have to deal with (should be a
501 *                      CALL-CLEAR-REQUEST packet)
502 *       rply_packet (OUT) - suitable reply to the 'packet' we got.
503 *       rply_size (OUT) - size of the reply packet
504 *
505 */
506void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t *rply_size)
507{
508	struct pptp_call_disconn_ntfy call_disconn_ntfy;
509	u_int16_t pac_call_id;
510
511	/* Form a reply
512	 * The reply packet is a CALL-DISCONECT-NOTIFY
513	 * In single call mode we don't care what peer's call ID is, so don't even bother looking
514	 */
515	if ((pac_call_id = freecall()) == htons(-1)) {
516		/* XXX should return an error */
517		syslog(LOG_ERR, "CTRL: Could not free Call ID [call clear]!");
518	}
519	MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY);
520	call_disconn_ntfy.call_id = pac_call_id;
521	call_disconn_ntfy.result_code = CALL_CLEAR_REQUEST;	/* disconnected by call_clr_rqst */
522	call_disconn_ntfy.error_code = NO_ERROR;
523	call_disconn_ntfy.cause_code = htons(NO_ERROR);
524	call_disconn_ntfy.reserved1 = htons(RESERVED);
525	memset(call_disconn_ntfy.call_stats, 0, 128);
526	COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size);
527	DEBUG_PACKET("CALL DISCONNECT RPLY");
528}
529
530/*
531 * deal_set_link_info
532 *
533 * @FIXME This function is *not* completed
534 *
535 * This method 'deals' with a SET-LINK-INFO. After stripping down the
536 * connection request a suitable reply is formed and stored in
537 * 'rply_packet' ready for sending.
538 *
539 * args: packet (IN) - the packet that we have to deal with (should be a
540 *                      SET-LINK-INFO packet)
541 *       rply_packet (OUT) - suitable reply to the 'packet' we got.
542 *       rply_size (OUT) - size of the reply packet
543 *
544 */
545void deal_set_link_info(unsigned char *packet)
546{
547	struct pptp_set_link_info *set_link_info;
548
549	set_link_info = (struct pptp_set_link_info *) packet;
550	if(set_link_info->send_accm != 0xffffffff || set_link_info->recv_accm != 0xffffffff)
551		syslog(LOG_ERR, "CTRL: Ignored a SET LINK INFO packet with real ACCMs!");
552	else if(pptpctrl_debug)
553		syslog(LOG_DEBUG, "CTRL: Got a SET LINK INFO packet with standard ACCMs");
554}
555
556void make_echo_req_packet(unsigned char *rply_packet, ssize_t * rply_size, u_int32_t echo_id)
557{
558	struct pptp_echo_rqst echo_packet;
559
560	MAKE_CTRL_HEADER(echo_packet, ECHO_RQST);
561	echo_packet.identifier = echo_id;
562	COPY_CTRL_PACKET(echo_packet, rply_packet, rply_size);
563	DEBUG_PACKET("ECHO REQ");
564}
565
566void make_stop_ctrl_req(unsigned char *rply_packet, ssize_t * rply_size)
567{
568	struct pptp_stop_ctrl_conn_rqst stop_ctrl;
569
570	MAKE_CTRL_HEADER(stop_ctrl, STOP_CTRL_CONN_RQST);
571	stop_ctrl.reason = GENERAL_STOP_CTRL;
572	stop_ctrl.reserved1 = RESERVED;
573	stop_ctrl.reserved2 = htons(RESERVED);
574	COPY_CTRL_PACKET(stop_ctrl, rply_packet, rply_size);
575	DEBUG_PACKET("STOP CTRL REQ");
576}
577
578void make_call_admin_shutdown(unsigned char *rply_packet, ssize_t * rply_size)
579{
580	struct pptp_call_disconn_ntfy call_disconn_ntfy;
581	u_int16_t pac_call_id;
582
583	/* Form a reply
584	 * The reply packet is a CALL-DISCONECT-NOTIFY
585	 * In single call mode we don't care what peer's call ID is, so don't even bother looking
586	 */
587	if ((pac_call_id = freecall()) == htons(-1)) {
588		/* XXX should return an error */
589		syslog(LOG_ERR, "CTRL: Could not free Call ID [admin shutdown]!");
590	}
591	MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY);
592	call_disconn_ntfy.call_id = pac_call_id;
593	call_disconn_ntfy.result_code = ADMIN_SHUTDOWN;		/* disconnected by admin shutdown */
594	call_disconn_ntfy.error_code = NO_ERROR;
595	call_disconn_ntfy.cause_code = htons(NO_ERROR);
596	call_disconn_ntfy.reserved1 = htons(RESERVED);
597	memset(call_disconn_ntfy.call_stats, 0, 128);
598	COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size);
599	DEBUG_PACKET("CALL DISCONNECT RPLY");
600}
601
602#if PNS_MODE
603/* out of date.  really PNS isn't 'trivially different', it's quite different */
604
605#define C_BITS (sizeof(unsigned int) * 8)
606#define C_SEG(x) (x/C_BITS)
607#define C_BIT(x) ((1U)<<(x%C_BITS))
608static unsigned int activeCalls[(MAX_CALLS / C_BITS) + 1];
609
610/*
611 * get_call_id
612 *
613 * Assigns a call ID and peer call ID to the session.
614 *
615 * args: call_id (OUT) - the call ID for the session
616 * retn: 0 on success, -1 on failure
617 */
618int get_call_id(u_int16_t * loc)
619{
620	for (i = 0; i < MAX_CALLS; i++) {
621		if (!(activeCalls[C_SEG(i)] & C_BIT(i))) {
622			activeCalls[C_SEG(i)] |= C_BIT(i);
623			*loc = i;
624			return 0;
625		}
626	}
627	return -1;
628}
629
630/*
631 * free_call_id
632 *
633 * args: call_id (IN) - the call ID for a terminated session
634 * retn: 0 on success, -1 on failure
635 */
636int free_call_id(u_int16_t call_id)
637{
638	if (!(activeCalls[C_SEG(i)] & C_BIT(i)))
639		return -1;
640	activeCalls[C_SEG(i)] &= ~C_BIT(i);
641	return 0;
642}
643#else
644static int _pac_call_id;
645static u_int16_t _pac_init = 0;
646
647/*
648 * getcall
649 *
650 * Assigns a call ID to the session and stores/returns it
651 *
652 * we only permit one call at a time, so the chance of wrapping 65k on one
653 * control connection is zero to none...
654 */
655u_int16_t getcall()
656{
657	struct sockaddr_pppox src_addr;
658	socklen_t addrlen;
659
660	src_addr.sa_family=AF_PPPOX;
661	src_addr.sa_protocol=PX_PROTO_PPTP;
662	src_addr.sa_addr.pptp.call_id=0;
663	src_addr.sa_addr.pptp.sin_addr=inetaddrs[0];
664
665	if (pptp_sock!=-1) close(pptp_sock);
666
667	pptp_sock=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP);
668	if (pptp_sock<0)
669	{
670		syslog(LOG_ERR,"CTRL: failed to create PPTP socket (%s)\n",strerror(errno));
671		exit(-1);
672	}
673	if (bind(pptp_sock,(struct sockaddr*)&src_addr,sizeof(src_addr)))
674	{
675		syslog(LOG_ERR,"CTRL: failed to bind PPTP socket (%s)\n",strerror(errno));
676		close(pptp_sock);
677		pptp_sock=-1;
678		exit(-1);
679	}
680	addrlen=sizeof(src_addr);
681	getsockname(pptp_sock,(struct sockaddr*)&src_addr,&addrlen);
682
683	if(!_pac_init) {
684		_pac_call_id = htons(-1);
685		_pac_init = 1;
686	}
687	if(_pac_call_id != htons(-1))
688		syslog(LOG_ERR, "CTRL: Asked to allocate call id when call open, not handled well");
689
690	_pac_call_id = htons(src_addr.sa_addr.pptp.call_id) ;
691	return _pac_call_id;
692}
693
694/*
695 * freecall
696 *
697 * Notes termination of current call
698 *
699 * retn: -1 on failure, PAC call ID on success
700 */
701u_int16_t freecall()
702{
703	u_int16_t ret;
704
705	if (pptp_sock!=-1){
706		close(pptp_sock);
707		pptp_sock=-1;
708	}
709
710	if(!_pac_init) {
711		_pac_call_id = htons(-1);
712		_pac_init = 1;
713	}
714	ret = _pac_call_id;
715	if(_pac_call_id == htons(-1))
716		syslog(LOG_ERR, "CTRL: Asked to free call when no call open, not handled well");
717	_pac_call_id = htons(-1);
718	return ret;
719}
720#endif
721