4 * PPTP Control Message packet reading, formatting and writing.
6 * $Id: ctrlpacket.c,v 1.6 2005/08/03 09:10:59 quozl Exp $
16 #include "our_syslog.h"
22 #include <sys/types.h>
25 #include <netinet/in.h>
32 #include "ctrlpacket.h"
38 /* Local function prototypes */
39 static ssize_t
read_pptp_header(int clientFd
, unsigned char *packet
, int *ctrl_message_type
);
40 static void deal_start_ctrl_conn(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
);
41 static void deal_stop_ctrl_conn(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
);
42 static void deal_out_call(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
);
43 static void deal_echo(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
);
44 static void deal_call_clr(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
);
45 static void deal_set_link_info(unsigned char *packet
);
46 static u_int16_t
getcall();
47 static u_int16_t
freecall();
50 static int make_out_call_rqst(unsigned char *rply_packet
, ssize_t
* rply_size
);
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.
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.
65 * retn: PPTP control message type of the packet on success.
66 * -1 on retryable error.
67 * 0 on error to abort on.
69 int read_pptp_packet(int clientFd
, unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
)
73 int pptp_ctrl_type
= 0; /* Control Message Type */
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");
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
);
88 case STOP_CTRL_CONN_RQST
:
89 deal_stop_ctrl_conn(packet
, rply_packet
, rply_size
);
92 case OUT_CALL_RQST
: /* Outgoing Call Request */
93 deal_out_call(packet
, rply_packet
, rply_size
);
96 case ECHO_RQST
: /* Echo Request */
97 deal_echo(packet
, rply_packet
, rply_size
);
100 case CALL_CLR_RQST
: /* Call Clear Request (Disconnect Request) */
101 deal_call_clr(packet
, rply_packet
, rply_size
);
104 case SET_LINK_INFO
: /* Set Link Info */
105 /* no reply packet but process it */
106 deal_set_link_info(packet
);
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 */
116 syslog(LOG_ERR
, "CTRL: PPTP Control Message type %d not supported.", pptp_ctrl_type
);
120 return pptp_ctrl_type
;
127 * Sends a PPTP packet to a file descriptor.
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.
133 * retn: Number of bytes written on success.
134 * -1 on write failure.
136 size_t send_pptp_packet(int clientFd
, unsigned char *packet
, size_t packet_size
)
139 size_t bytes_written
;
141 if ((bytes_written
= write(clientFd
, packet
, packet_size
)) == -1) {
143 syslog(LOG_ERR
, "CTRL: Couldn't write packet to client.");
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");
152 return bytes_written
;
159 * Check if an errno represents a read error which should be ignored, and
160 * put back to be select()ed on again later.
162 * Very similar to the function in Squid by Duane Wessels (under GPL).
164 * args: an errno value
166 * retn: 1 if the error is unimportant
167 * 0 if the error is important
169 static int ignoreErrno(int ierrno
) {
171 case EAGAIN
: /* nothing to read */
172 case EINTR
: /* signal received */
174 #if ERESTART != EINTR
175 case ERESTART
: /* signal received, should restart syscall */
178 #if EWOULDBLOCK != EAGAIN
179 case EWOULDBLOCK
: /* shouldn't get this one but anyway, just in case */
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.
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.
198 * retn: Number of bytes read on success.
199 * -1 on retryable error.
200 * 0 on error to exit on.
202 ssize_t
read_pptp_header(int clientFd
, unsigned char *packet
, int *pptp_ctrl_type
)
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 */
209 static char *buffer
= NULL
; /* buffer between calls */
210 static int buffered
= 0; /* size of buffer */
212 *pptp_ctrl_type
= 0; /* initialise return arg */
214 /* read any previously buffered data */
216 memcpy(packet
, buffer
, buffered
);
219 bytes_ttl
= buffered
;
222 syslog(LOG_DEBUG
, "CTRL: Read in previous incomplete ctrl packet");
226 /* try and get the length in */
228 bytes_this
= read(clientFd
, packet
+ bytes_ttl
, 2 - bytes_ttl
);
229 switch (bytes_this
) {
231 if (ignoreErrno(errno
)) {
232 /* re-tryable error, re-buffer and return */
234 buffered
= bytes_ttl
;
235 buffer
= malloc(bytes_ttl
);
238 memcpy(buffer
, packet
, bytes_ttl
);
240 syslog(LOG_ERR
, "CTRL: Error reading ctrl packet length (bytes_ttl=%d): %s", bytes_ttl
, strerror(errno
));
245 syslog(LOG_ERR
, "CTRL: EOF or bad error reading ctrl packet length.");
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
);
255 memcpy(buffer
, packet
, bytes_ttl
);
257 syslog(LOG_DEBUG
, "CTRL: Incomplete ctrl packet length, retry later");
262 /* OK, we have (at least) the first 2 bytes, and there is data waiting
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.
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)
281 /* Now read the actual control packet */
282 bytes_this
= read(clientFd
, packet
+ bytes_ttl
, length
- bytes_ttl
);
283 switch (bytes_this
) {
285 if(ignoreErrno(errno
)) {
286 /* re-tryable error, re-buffer and return */
288 buffered
= bytes_ttl
;
289 buffer
= malloc(bytes_ttl
);
292 memcpy(buffer
, packet
, bytes_ttl
);
294 syslog(LOG_ERR
, "CTRL: Error reading ctrl packet (bytes_ttl=%d,length=%d): %s", bytes_ttl
, length
, strerror(errno
));
299 syslog(LOG_ERR
, "CTRL: EOF or bad error reading ctrl packet.");
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
);
309 memcpy(buffer
, packet
, bytes_ttl
);
311 syslog(LOG_DEBUG
, "CTRL: Incomplete ctrl packet, retry later");
318 /* Cast the packet into the PPTP Control Message format */
319 header
= (struct pptp_header
*) packet
;
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
330 /* Woohoo! Looks like we got a valid PPTP packet */
331 *pptp_ctrl_type
= (int) (ntohs(header
->ctrl_type
));
333 syslog(LOG_DEBUG
, "CTRL: Received PPTP Control Message (type: %d)", *pptp_ctrl_type
);
337 /* Macros to use in making response packets */
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)
346 #define COPY_CTRL_PACKET(from, to, size) \
347 memcpy(to, &from, ((*size) = sizeof(from)))
349 #define DEBUG_PACKET(what) \
351 syslog(LOG_DEBUG, "CTRL: Made a " what " packet")
354 * deal_start_ctrl_conn
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.
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
365 void deal_start_ctrl_conn(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
)
367 struct pptp_start_ctrl_conn_rqst
*start_ctrl_conn_rqst
;
368 struct pptp_start_ctrl_conn_rply start_ctrl_conn_rply
;
370 start_ctrl_conn_rqst
= (struct pptp_start_ctrl_conn_rqst
*) packet
;
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");
389 * deal_stop_ctrl_conn
391 * This method response to a STOP-CONTROL-CONNECTION-REQUEST with a
392 * STOP-CONTROL-CONNECTION-REPLY.
394 void deal_stop_ctrl_conn(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
)
396 struct pptp_stop_ctrl_conn_rply stop_ctrl_conn_rply
;
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");
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.
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
419 void deal_out_call(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
)
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
;
425 out_call_rqst
= (struct pptp_out_call_rqst
*) packet
;
427 if ((pac_call_id
= getcall()) == htons(-1)) {
428 /* XXX should reject call */
429 syslog(LOG_ERR
, "CTRL: No free Call IDs!");
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
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.
444 out_call_rply
.speed
= out_call_rqst
->max_bps
;
445 /* lets match their window size for now... was htons(PCKT_RECV_WINDOW_SIZE)
447 out_call_rply
.pckt_recv_size
= out_call_rqst
->pckt_recv_size
;
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");
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.
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
471 void deal_echo(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
* rply_size
)
473 struct pptp_echo_rqst
*echo_rqst
;
474 struct pptp_echo_rply echo_rply
;
476 echo_rqst
= (struct pptp_echo_rqst
*) packet
;
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");
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.
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
500 void deal_call_clr(unsigned char *packet
, unsigned char *rply_packet
, ssize_t
*rply_size
)
502 struct pptp_call_disconn_ntfy call_disconn_ntfy
;
503 u_int16_t pac_call_id
;
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
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]!");
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");
527 * @FIXME This function is *not* completed
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.
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
539 void deal_set_link_info(unsigned char *packet
)
541 struct pptp_set_link_info
*set_link_info
;
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");
550 void make_echo_req_packet(unsigned char *rply_packet
, ssize_t
* rply_size
, u_int32_t echo_id
)
552 struct pptp_echo_rqst echo_packet
;
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");
560 void make_stop_ctrl_req(unsigned char *rply_packet
, ssize_t
* rply_size
)
562 struct pptp_stop_ctrl_conn_rqst stop_ctrl
;
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");
572 void make_call_admin_shutdown(unsigned char *rply_packet
, ssize_t
* rply_size
)
574 struct pptp_call_disconn_ntfy call_disconn_ntfy
;
575 u_int16_t pac_call_id
;
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
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]!");
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");
597 /* out of date. really PNS isn't 'trivially different', it's quite different */
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))
602 static unsigned int activeCalls
[(MAX_CALLS
/ C_BITS
) + 1];
607 * Assigns a call ID and peer call ID to the session.
609 * args: call_id (OUT) - the call ID for the session
610 * retn: 0 on success, -1 on failure
612 int get_call_id(u_int16_t
* loc
)
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
);
627 * args: call_id (IN) - the call ID for a terminated session
628 * retn: 0 on success, -1 on failure
630 int free_call_id(u_int16_t call_id
)
632 if (!(activeCalls
[C_SEG(i
)] & C_BIT(i
)))
634 activeCalls
[C_SEG(i
)] &= ~C_BIT(i
);
638 static int _pac_call_id
;
639 static u_int16_t _pac_init
= 0;
644 * Assigns a call ID to the session and stores/returns it
646 * we only permit one call at a time, so the chance of wrapping 65k on one
647 * control connection is zero to none...
651 static u_int16_t i
= 0;
652 extern u_int16_t unique_call_id
;
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. */
661 if (unique_call_id
== 0xFFFF) {
663 if (gettimeofday(&tv
, NULL
) == 0) {
664 i
= ((tv
.tv_sec
& 0x0FFF) << 4) +
673 _pac_call_id
= htons(-1);
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
);
686 * Notes termination of current call
688 * retn: -1 on failure, PAC call ID on success
695 _pac_call_id
= htons(-1);
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);