diff options
Diffstat (limited to 'pptpd-1.3.3/ctrlpacket.c')
| -rw-r--r-- | pptpd-1.3.3/ctrlpacket.c | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/pptpd-1.3.3/ctrlpacket.c b/pptpd-1.3.3/ctrlpacket.c new file mode 100644 index 0000000..b463941 --- /dev/null +++ b/pptpd-1.3.3/ctrlpacket.c @@ -0,0 +1,719 @@ +/* + * ctrlpacket.c + * + * PPTP Control Message packet reading, formatting and writing. + * + * $Id: ctrlpacket.c,v 1.6 2005/08/03 09:10:59 quozl Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_SYSLOG_H +#include <syslog.h> +#else +#include "our_syslog.h" +#endif + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <time.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "pptpdefs.h" +#include "pptpctrl.h" +#include "ctrlpacket.h" + +#include <net/if.h> +#include <net/ethernet.h> +#include "if_pppox.h" + +#ifndef HAVE_STRERROR +#include "compat.h" +#endif + +/* Local function prototypes */ +static ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *ctrl_message_type); +static void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size); +static void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size); +static void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size); +static void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size); +static void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size); +static void deal_set_link_info(unsigned char *packet); +static u_int16_t getcall(); +static u_int16_t freecall(); + +#if notyet +static int make_out_call_rqst(unsigned char *rply_packet, ssize_t * rply_size); +#endif + +/* + * read_pptp_packet + * + * Sees if a packet can be read and if so what type of packet it is. The + * method then calls the appropriate function to examine the details of the + * packet and form a suitable reply packet. + * + * args: clientFd (IN) - Client socket to read from. + * packet (OUT) - Packet read from the client. + * rply_packet (OUT) - Reply packet for the client. + * rply_size (OUT) - Size of the reply packet. + * + * retn: PPTP control message type of the packet on success. + * -1 on retryable error. + * 0 on error to abort on. + */ +int read_pptp_packet(int clientFd, unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size) +{ + + size_t bytes_read; + int pptp_ctrl_type = 0; /* Control Message Type */ + + /* read a packet and parse header */ + if ((bytes_read = read_pptp_header(clientFd, packet, &pptp_ctrl_type)) <= 0) { + /* error reading packet */ + syslog(LOG_ERR, "CTRL: couldn't read packet header (%s)", bytes_read ? "retry" : "exit"); + return bytes_read; + } + + /* launch appropriate method to form suitable reply to the packet */ + switch (pptp_ctrl_type) { + case START_CTRL_CONN_RQST: /* Start Control Connection Request */ + deal_start_ctrl_conn(packet, rply_packet, rply_size); + break; + + case STOP_CTRL_CONN_RQST: + deal_stop_ctrl_conn(packet, rply_packet, rply_size); + break; + + case OUT_CALL_RQST: /* Outgoing Call Request */ + deal_out_call(packet, rply_packet, rply_size); + break; + + case ECHO_RQST: /* Echo Request */ + deal_echo(packet, rply_packet, rply_size); + break; + + case CALL_CLR_RQST: /* Call Clear Request (Disconnect Request) */ + deal_call_clr(packet, rply_packet, rply_size); + break; + + case SET_LINK_INFO: /* Set Link Info */ + /* no reply packet but process it */ + deal_set_link_info(packet); + break; + + case ECHO_RPLY: /* Echo Reply */ + case STOP_CTRL_CONN_RPLY: /* Stop Control Connection Reply */ + case CALL_DISCONN_NTFY: /* Call Disconnect Notify */ + /* no reply packet */ + break; + + default: + syslog(LOG_ERR, "CTRL: PPTP Control Message type %d not supported.", pptp_ctrl_type); + pptp_ctrl_type = -1; + } + + return pptp_ctrl_type; +} + + +/* + * send_pptp_packet + * + * Sends a PPTP packet to a file descriptor. + * + * args: clientFd (IN) - file descriptor to write the packet to. + * packet (IN) - the packet data to write. + * packet_size (IN) - the packet size. + * + * retn: Number of bytes written on success. + * -1 on write failure. + */ +size_t send_pptp_packet(int clientFd, unsigned char *packet, size_t packet_size) +{ + + size_t bytes_written; + + if ((bytes_written = write(clientFd, packet, packet_size)) == -1) { + /* write failed */ + syslog(LOG_ERR, "CTRL: Couldn't write packet to client."); + return -1; + + } else { + /* debugging */ + if (pptpctrl_debug) { + syslog(LOG_DEBUG, "CTRL: I wrote %i bytes to the client.", (int)packet_size); + syslog(LOG_DEBUG, "CTRL: Sent packet to client"); + } + return bytes_written; + } +} + +/* + * ignoreErrno + * + * Check if an errno represents a read error which should be ignored, and + * put back to be select()ed on again later. + * + * Very similar to the function in Squid by Duane Wessels (under GPL). + * + * args: an errno value + * + * retn: 1 if the error is unimportant + * 0 if the error is important + */ +static int ignoreErrno(int ierrno) { + switch (ierrno) { + case EAGAIN: /* nothing to read */ + case EINTR: /* signal received */ +#ifdef ERESTART +#if ERESTART != EINTR + case ERESTART: /* signal received, should restart syscall */ +#endif +#endif +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: /* shouldn't get this one but anyway, just in case */ +#endif + return 1; + default: + return 0; + } +} + +/* + * read_pptp_header + * + * Reads a packet from a file descriptor and determines whether it is a + * valid PPTP Control Message. If a valid PPTP Control Message is detected + * it extracts the Control Message type from the packet header. + * + * args: clientFd (IN) - Clients file descriptor. + * packet (OUT) - Packet we read from the client. + * pptp_ctrl_type (OUT) - PPTP Control Message type of the packet. + * + * retn: Number of bytes read on success. + * -1 on retryable error. + * 0 on error to exit on. + */ +ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *pptp_ctrl_type) +{ + + ssize_t bytes_ttl, bytes_this; /* quantities read (total and this read) */ + u_int16_t length; /* length of this packet */ + struct pptp_header *header; /* the received header */ + + static char *buffer = NULL; /* buffer between calls */ + static int buffered = 0; /* size of buffer */ + + *pptp_ctrl_type = 0; /* initialise return arg */ + + /* read any previously buffered data */ + if (buffered) { + memcpy(packet, buffer, buffered); + free(buffer); + buffer = NULL; + bytes_ttl = buffered; + buffered = 0; + if (pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Read in previous incomplete ctrl packet"); + } else + bytes_ttl = 0; + + /* try and get the length in */ + if (bytes_ttl < 2) { + bytes_this = read(clientFd, packet + bytes_ttl, 2 - bytes_ttl); + switch (bytes_this) { + case -1: + if (ignoreErrno(errno)) { + /* re-tryable error, re-buffer and return */ + if (bytes_ttl) { + buffered = bytes_ttl; + buffer = malloc(bytes_ttl); + if (!buffer) + return(0); + memcpy(buffer, packet, bytes_ttl); + } + syslog(LOG_ERR, "CTRL: Error reading ctrl packet length (bytes_ttl=%i): %s", (int)bytes_ttl, strerror(errno)); + return -1; + } + /* FALLTHRU */ + case 0: + syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet length."); + return 0; + default: + bytes_ttl += bytes_this; + /* Not enough data to proceed */ + if (bytes_ttl == 1) { + buffered = bytes_ttl; + buffer = malloc(bytes_ttl); + if (!buffer) + return(0); + memcpy(buffer, packet, bytes_ttl); + if (pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet length, retry later"); + return -1; + } + } + } + /* OK, we have (at least) the first 2 bytes, and there is data waiting + * + * length includes the header, so a length less than 2 is someone + * trying to hack into us or a badly corrupted packet. + * Why not require length to be at least 10? Since we later cast + * packet to struct pptp_header and use at least the 10 first bytes.. + * Thanks to Timo Sirainen for mentioning this. + */ + length = htons(*(u_int16_t *) packet); + if (length <= 10 || length > PPTP_MAX_CTRL_PCKT_SIZE) { + syslog(LOG_ERR, "CTRL: 11 < Control packet (length=%d) < " + "PPTP_MAX_CTRL_PCKT_SIZE (%d)", + length, PPTP_MAX_CTRL_PCKT_SIZE); + /* we loose sync (unless we malloc something big, which isn't a good + * idea - potential DoS) so we must close connection (draft states that + * if you loose sync you must close the control connection immediately) + */ + return 0; + } + /* Now read the actual control packet */ + bytes_this = read(clientFd, packet + bytes_ttl, length - bytes_ttl); + switch (bytes_this) { + case -1: + if(ignoreErrno(errno)) { + /* re-tryable error, re-buffer and return */ + if (bytes_ttl) { + buffered = bytes_ttl; + buffer = malloc(bytes_ttl); + if (!buffer) + return(0); + memcpy(buffer, packet, bytes_ttl); + } + syslog(LOG_ERR, "CTRL: Error reading ctrl packet (bytes_ttl=%d,length=%d): %s", (int)bytes_ttl, (int)length, strerror(errno)); + return -1; + } + /* FALLTHRU */ + case 0: + syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet."); + return 0; + default: + bytes_ttl += bytes_this; + /* not enough data to proceed */ + if (bytes_ttl != length) { + buffered = bytes_ttl; + buffer = malloc(bytes_ttl); + if (!buffer) + return(0); + memcpy(buffer, packet, bytes_ttl); + if (pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet, retry later"); + return -1; + } + } + + /* We got one :-) */ + + /* Cast the packet into the PPTP Control Message format */ + header = (struct pptp_header *) packet; + + /* Packet sanity check on magic cookie */ + if (ntohl(header->magic) != PPTP_MAGIC_COOKIE) { + /* Oops! Not a valid Control Message */ + syslog(LOG_ERR, "CTRL: Bad magic cookie - lost syncronization, closing control connection."); + /* draft states loss of syncronization must result in + * immediate closing of the control connection + */ + return 0; + } + /* Woohoo! Looks like we got a valid PPTP packet */ + *pptp_ctrl_type = (int) (ntohs(header->ctrl_type)); + if (pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Received PPTP Control Message (type: %d)", *pptp_ctrl_type); + return bytes_ttl; +} + +/* Macros to use in making response packets */ + +#define MAKE_CTRL_HEADER(where, what) \ + where.header.length = htons(sizeof(where)); \ + where.header.pptp_type = htons(PPTP_CTRL_MESSAGE); \ + where.header.magic = htonl(PPTP_MAGIC_COOKIE); \ + where.header.ctrl_type = htons(what); \ + where.header.reserved0 = htons(RESERVED) + +#define COPY_CTRL_PACKET(from, to, size) \ + memcpy(to, &from, ((*size) = sizeof(from))) + +#define DEBUG_PACKET(what) \ + if(pptpctrl_debug) \ + syslog(LOG_DEBUG, "CTRL: Made a " what " packet") + +/* + * deal_start_ctrl_conn + * + * This method 'deals' with a START-CONTROL-CONNECTION-REQUEST. After + * stripping down the connection request a suitable reply is formed and + * stored in 'rply_packet' ready for sending. + * + * args: packet (IN) - the packet that we have to deal with (should be a + * START-CONTROL-CONNECTION-REQUEST packet) + * rply_packet (OUT) - suitable reply to the 'packet' we got. + * rply_size (OUT) - size of the reply packet + */ +void deal_start_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size) +{ + struct pptp_start_ctrl_conn_rqst *start_ctrl_conn_rqst; + struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply; + + start_ctrl_conn_rqst = (struct pptp_start_ctrl_conn_rqst *) packet; + + MAKE_CTRL_HEADER(start_ctrl_conn_rply, START_CTRL_CONN_RPLY); + start_ctrl_conn_rply.version = htons(PPTP_VERSION); + start_ctrl_conn_rply.result_code = CONNECTED; + start_ctrl_conn_rply.error_code = NO_ERROR; + start_ctrl_conn_rply.framing_cap = htons(OUR_FRAMING); + start_ctrl_conn_rply.bearer_cap = htons(OUR_BEARER); + start_ctrl_conn_rply.max_channels = htons(MAX_CHANNELS); + start_ctrl_conn_rply.firmware_rev = htons(PPTP_FIRMWARE_VERSION); + bzero(start_ctrl_conn_rply.hostname, MAX_HOSTNAME_SIZE); + strncpy((char *)start_ctrl_conn_rply.hostname, PPTP_HOSTNAME, MAX_HOSTNAME_SIZE); + bzero(start_ctrl_conn_rply.vendor, MAX_VENDOR_SIZE); + strncpy((char *)start_ctrl_conn_rply.vendor, PPTP_VENDOR, MAX_VENDOR_SIZE); + COPY_CTRL_PACKET(start_ctrl_conn_rply, rply_packet, rply_size); + DEBUG_PACKET("START CTRL CONN RPLY"); +} + +/* + * deal_stop_ctrl_conn + * + * This method response to a STOP-CONTROL-CONNECTION-REQUEST with a + * STOP-CONTROL-CONNECTION-REPLY. + */ +void deal_stop_ctrl_conn(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size) +{ + struct pptp_stop_ctrl_conn_rply stop_ctrl_conn_rply; + + MAKE_CTRL_HEADER(stop_ctrl_conn_rply, STOP_CTRL_CONN_RPLY); + stop_ctrl_conn_rply.result_code = DISCONNECTED; + stop_ctrl_conn_rply.error_code = NO_ERROR; + stop_ctrl_conn_rply.reserved1 = htons(RESERVED); + COPY_CTRL_PACKET(stop_ctrl_conn_rply, rply_packet, rply_size); + DEBUG_PACKET("STOP CTRL CONN RPLY"); +} + +/* + * deal_out_call + * + * This method 'deals' with a OUT-GOING-CALL-REQUEST. After + * stripping down the request a suitable reply is formed and stored in + * 'rply_packet' ready for sending. + * + * args: packet (IN) - the packet that we have to deal with (should be a + * OUT-GOING-CALL-REQUEST packet) + * rply_packet (OUT) - suitable reply to the 'packet' we got. + * rply_size (OUT) - size of the reply packet + * + */ +void deal_out_call(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size) +{ + u_int16_t pac_call_id; + struct pptp_out_call_rqst *out_call_rqst; + struct pptp_out_call_rply out_call_rply; + + out_call_rqst = (struct pptp_out_call_rqst *) packet; + + if ((pac_call_id = getcall()) == htons(-1)) { + /* XXX should reject call */ + syslog(LOG_ERR, "CTRL: No free Call IDs!"); + pac_call_id = 0; + } + MAKE_CTRL_HEADER(out_call_rply, OUT_CALL_RPLY); + /* call_id is used for ctrl, call_id_peer is used for GRE + * call_id_peer is what we were sent by the other end in ctrl initilization + */ + out_call_rply.call_id = pac_call_id; + out_call_rply.call_id_peer = out_call_rqst->call_id; + out_call_rply.result_code = CONNECTED; + out_call_rply.error_code = NO_ERROR; + out_call_rply.cause_code = NO_ERROR; + /* maybe limit to pppd speed? but pppd doesn't accept 10Mbps as a speed and yet + * still performs at over 115200, eg, 60kbyte/sec and higher observed. + */ + out_call_rply.speed = out_call_rqst->max_bps; + /* lets match their window size for now... was htons(PCKT_RECV_WINDOW_SIZE) + */ + out_call_rply.pckt_recv_size = out_call_rqst->pckt_recv_size; + window=htons(out_call_rply.pckt_recv_size); + if(pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Set parameters to %d maxbps, %d window size", + ntohl(out_call_rply.speed), ntohs(out_call_rply.pckt_recv_size)); + out_call_rply.pckt_delay = htons(PCKT_PROCESS_DELAY); + out_call_rply.channel_id = htonl(CHANNEL_ID); + COPY_CTRL_PACKET(out_call_rply, rply_packet, rply_size); + DEBUG_PACKET("OUT CALL RPLY"); +} + + +/* + * deal_echo + * + * This method 'deals' with a ECHO-REQUEST. After stripping down the + * connection request a suitable reply is formed and stored in + * 'rply_packet' ready for sending. + * + * args: packet (IN) - the packet that we have to deal with (should be a + * ECHO-REQUEST packet) + * rply_packet (OUT) - suitable reply to the 'packet' we got. + * rply_size (OUT) - size of the reply packet + * + */ +void deal_echo(unsigned char *packet, unsigned char *rply_packet, ssize_t * rply_size) +{ + struct pptp_echo_rqst *echo_rqst; + struct pptp_echo_rply echo_rply; + + echo_rqst = (struct pptp_echo_rqst *) packet; + + MAKE_CTRL_HEADER(echo_rply, ECHO_RPLY); + echo_rply.identifier = echo_rqst->identifier; + echo_rply.result_code = CONNECTED; + echo_rply.error_code = NO_ERROR; + echo_rply.reserved1 = htons(RESERVED); + COPY_CTRL_PACKET(echo_rply, rply_packet, rply_size); + DEBUG_PACKET("ECHO RPLY"); +} + +/* + * deal_call_clr + * + * This method 'deals' with a CALL-CLEAR-REQUEST. After stripping down the + * connection request a suitable reply is formed and stored in + * 'rply_packet' ready for sending. + * + * args: packet (IN) - the packet that we have to deal with (should be a + * CALL-CLEAR-REQUEST packet) + * rply_packet (OUT) - suitable reply to the 'packet' we got. + * rply_size (OUT) - size of the reply packet + * + */ +void deal_call_clr(unsigned char *packet, unsigned char *rply_packet, ssize_t *rply_size) +{ + struct pptp_call_disconn_ntfy call_disconn_ntfy; + u_int16_t pac_call_id; + + /* Form a reply + * The reply packet is a CALL-DISCONECT-NOTIFY + * In single call mode we don't care what peer's call ID is, so don't even bother looking + */ + if ((pac_call_id = freecall()) == htons(-1)) { + /* XXX should return an error */ + syslog(LOG_ERR, "CTRL: Could not free Call ID [call clear]!"); + } + MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY); + call_disconn_ntfy.call_id = pac_call_id; + call_disconn_ntfy.result_code = CALL_CLEAR_REQUEST; /* disconnected by call_clr_rqst */ + call_disconn_ntfy.error_code = NO_ERROR; + call_disconn_ntfy.cause_code = htons(NO_ERROR); + call_disconn_ntfy.reserved1 = htons(RESERVED); + memset(call_disconn_ntfy.call_stats, 0, 128); + COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size); + DEBUG_PACKET("CALL DISCONNECT RPLY"); +} + +/* + * deal_set_link_info + * + * @FIXME This function is *not* completed + * + * This method 'deals' with a SET-LINK-INFO. After stripping down the + * connection request a suitable reply is formed and stored in + * 'rply_packet' ready for sending. + * + * args: packet (IN) - the packet that we have to deal with (should be a + * SET-LINK-INFO packet) + * rply_packet (OUT) - suitable reply to the 'packet' we got. + * rply_size (OUT) - size of the reply packet + * + */ +void deal_set_link_info(unsigned char *packet) +{ + struct pptp_set_link_info *set_link_info; + + set_link_info = (struct pptp_set_link_info *) packet; + if(set_link_info->send_accm != 0xffffffff || set_link_info->recv_accm != 0xffffffff) + syslog(LOG_ERR, "CTRL: Ignored a SET LINK INFO packet with real ACCMs!"); + else if(pptpctrl_debug) + syslog(LOG_DEBUG, "CTRL: Got a SET LINK INFO packet with standard ACCMs"); +} + +void make_echo_req_packet(unsigned char *rply_packet, ssize_t * rply_size, u_int32_t echo_id) +{ + struct pptp_echo_rqst echo_packet; + + MAKE_CTRL_HEADER(echo_packet, ECHO_RQST); + echo_packet.identifier = echo_id; + COPY_CTRL_PACKET(echo_packet, rply_packet, rply_size); + DEBUG_PACKET("ECHO REQ"); +} + +void make_stop_ctrl_req(unsigned char *rply_packet, ssize_t * rply_size) +{ + struct pptp_stop_ctrl_conn_rqst stop_ctrl; + + MAKE_CTRL_HEADER(stop_ctrl, STOP_CTRL_CONN_RQST); + stop_ctrl.reason = GENERAL_STOP_CTRL; + stop_ctrl.reserved1 = RESERVED; + stop_ctrl.reserved2 = htons(RESERVED); + COPY_CTRL_PACKET(stop_ctrl, rply_packet, rply_size); + DEBUG_PACKET("STOP CTRL REQ"); +} + +void make_call_admin_shutdown(unsigned char *rply_packet, ssize_t * rply_size) +{ + struct pptp_call_disconn_ntfy call_disconn_ntfy; + u_int16_t pac_call_id; + + /* Form a reply + * The reply packet is a CALL-DISCONECT-NOTIFY + * In single call mode we don't care what peer's call ID is, so don't even bother looking + */ + if ((pac_call_id = freecall()) == htons(-1)) { + /* XXX should return an error */ + syslog(LOG_ERR, "CTRL: Could not free Call ID [admin shutdown]!"); + } + MAKE_CTRL_HEADER(call_disconn_ntfy, CALL_DISCONN_NTFY); + call_disconn_ntfy.call_id = pac_call_id; + call_disconn_ntfy.result_code = ADMIN_SHUTDOWN; /* disconnected by admin shutdown */ + call_disconn_ntfy.error_code = NO_ERROR; + call_disconn_ntfy.cause_code = htons(NO_ERROR); + call_disconn_ntfy.reserved1 = htons(RESERVED); + memset(call_disconn_ntfy.call_stats, 0, 128); + COPY_CTRL_PACKET(call_disconn_ntfy, rply_packet, rply_size); + DEBUG_PACKET("CALL DISCONNECT RPLY"); +} + +#if PNS_MODE +/* out of date. really PNS isn't 'trivially different', it's quite different */ + +#define C_BITS (sizeof(unsigned int) * 8) +#define C_SEG(x) (x/C_BITS) +#define C_BIT(x) ((1U)<<(x%C_BITS)) +static unsigned int activeCalls[(MAX_CALLS / C_BITS) + 1]; + +/* + * get_call_id + * + * Assigns a call ID and peer call ID to the session. + * + * args: call_id (OUT) - the call ID for the session + * retn: 0 on success, -1 on failure + */ +int get_call_id(u_int16_t * loc) +{ + for (i = 0; i < MAX_CALLS; i++) { + if (!(activeCalls[C_SEG(i)] & C_BIT(i))) { + activeCalls[C_SEG(i)] |= C_BIT(i); + *loc = i; + return 0; + } + } + return -1; +} + +/* + * free_call_id + * + * args: call_id (IN) - the call ID for a terminated session + * retn: 0 on success, -1 on failure + */ +int free_call_id(u_int16_t call_id) +{ + if (!(activeCalls[C_SEG(i)] & C_BIT(i))) + return -1; + activeCalls[C_SEG(i)] &= ~C_BIT(i); + return 0; +} +#else +static int _pac_call_id; +static u_int16_t _pac_init = 0; + +/* + * getcall + * + * Assigns a call ID to the session and stores/returns it + * + * we only permit one call at a time, so the chance of wrapping 65k on one + * control connection is zero to none... + */ +u_int16_t getcall() +{ + struct sockaddr_pppox src_addr; + socklen_t addrlen; + + src_addr.sa_family=AF_PPPOX; + src_addr.sa_protocol=PX_PROTO_PPTP; + src_addr.sa_addr.pptp.call_id=0; + src_addr.sa_addr.pptp.sin_addr=inetaddrs[0]; + + if (pptp_sock!=-1) close(pptp_sock); + + pptp_sock=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP); + if (pptp_sock<0) + { + syslog(LOG_ERR,"CTRL: failed to create PPTP socket (%s)\n",strerror(errno)); + exit(-1); + } + if (bind(pptp_sock,(struct sockaddr*)&src_addr,sizeof(src_addr))) + { + syslog(LOG_ERR,"CTRL: failed to bind PPTP socket (%s)\n",strerror(errno)); + close(pptp_sock); + pptp_sock=-1; + exit(-1); + } + addrlen=sizeof(src_addr); + getsockname(pptp_sock,(struct sockaddr*)&src_addr,&addrlen); + + if(!_pac_init) { + _pac_call_id = htons(-1); + _pac_init = 1; + } + if(_pac_call_id != htons(-1)) + syslog(LOG_ERR, "CTRL: Asked to allocate call id when call open, not handled well"); + + _pac_call_id = htons(src_addr.sa_addr.pptp.call_id) ; + return _pac_call_id; +} + +/* + * freecall + * + * Notes termination of current call + * + * retn: -1 on failure, PAC call ID on success + */ +u_int16_t freecall() +{ + u_int16_t ret; + + if (pptp_sock!=-1){ + close(pptp_sock); + pptp_sock=-1; + } + + if(!_pac_init) { + _pac_call_id = htons(-1); + _pac_init = 1; + } + ret = _pac_call_id; + if(_pac_call_id == htons(-1)) + syslog(LOG_ERR, "CTRL: Asked to free call when no call open, not handled well"); + _pac_call_id = htons(-1); + return ret; +} +#endif |
