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