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