| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 | 
							- /*
 
-  * ctrlpacket.c
 
-  *
 
-  * PPTP Control Message packet reading, formatting and writing.
 
-  */
 
- #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"
 
- #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(void *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size);
 
- static void deal_stop_ctrl_conn(void *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size);
 
- static void deal_out_call(unsigned char *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size);
 
- static void deal_echo(unsigned char *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size);
 
- static void deal_call_clr(unsigned char *packet, struct pptp_out_call_rply *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, void *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size)
 
- {
 
-         ssize_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.
 
-  */
 
- ssize_t send_pptp_packet(int clientFd, void *packet, size_t packet_size)
 
- {
 
-         ssize_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 %lu bytes to the client.", (unsigned long) 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=%lu): %s", (unsigned long) 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=%lu,length=%d): %s", (unsigned long) bytes_ttl, 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(void *packet, struct pptp_out_call_rply *rply_packet, ssize_t * rply_size)
 
- {
 
-         struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply;
 
-         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);
 
-         memset(start_ctrl_conn_rply.hostname, 0, MAX_HOSTNAME_SIZE);
 
-         strncpy((char *)start_ctrl_conn_rply.hostname, PPTP_HOSTNAME, MAX_HOSTNAME_SIZE);
 
-         memset(start_ctrl_conn_rply.vendor, 0, 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(void *packet, struct pptp_out_call_rply *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, struct pptp_out_call_rply *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;
 
-         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, struct pptp_out_call_rply *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, struct pptp_out_call_rply *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) {
 
-                 /* Async-Control-Character-Map (ACCM) are bits that
 
-                    show which control characters should be escaped by the
 
-                    PPP implementation ... pptpd leaves pppd to negotiate
 
-                    that via LCP and does not process SET LINK INFO
 
-                    packets ... this is not complaint with the RFC but
 
-                    still works. */
 
-                 if (pptpctrl_debug)
 
-                         syslog(LOG_DEBUG, "CTRL: Ignored a SET LINK INFO packet with real ACCMs! (intentional non-compliance with section 2.15 of RFC 2637, ACCM is negotiated by PPP LCP asyncmap)");
 
-         } else if (pptpctrl_debug)
 
-                 syslog(LOG_DEBUG, "CTRL: Got a SET LINK INFO packet with standard ACCMs");
 
- }
 
- void make_echo_req_packet(struct pptp_out_call_rply *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(struct pptp_out_call_rply *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(struct pptp_out_call_rply *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()
 
- {
 
-         static u_int16_t i = 0;
 
-         extern u_int16_t unique_call_id;
 
-         /* Start with a random Call ID.  This is to allocate unique
 
-          * Call ID's across multiple TCP PPTP connections.  In this
 
-          * way remote clients masqueraded by a firewall will put
 
-          * unique peer call ID's into GRE packets that will have the
 
-          * same source IP address of the firewall. */
 
-         if (!i) {
 
-                 if (unique_call_id == 0xFFFF) {
 
-                         struct timeval tv;
 
-                         if (gettimeofday(&tv, NULL) == 0) {
 
-                                 i = ((tv.tv_sec & 0x0FFF) << 4) + 
 
-                                     (tv.tv_usec >> 16);
 
-                         }
 
-                 } else {
 
-                         i = unique_call_id;
 
-                 }
 
-         }
 
-         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(i);
 
-         i++;
 
-         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(!_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
 
 
  |