Exemplo n.º 1
0
/*** handle any pptp file descriptors set in fd_set, and clear them ***********/
int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
{
    int r = 0;
    assert(conn && conn->call);
    /* Check for signals */
    if (FD_ISSET(sigpipe_fd(), read_set)) {
        if (sigpipe_read() == SIGALRM) pptp_handle_timer();
	FD_CLR(sigpipe_fd(), read_set);
    }
    /* Check write_set could be set. */
    if (FD_ISSET(conn->inet_sock, write_set)) {
        FD_CLR(conn->inet_sock, write_set);
        if (conn->write_size > 0)
            r = pptp_write_some(conn);/* write as much as we can without blocking */
    }
    /* Check read_set */
    if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
        void *buffer; size_t size;
        FD_CLR(conn->inet_sock, read_set);
        r = pptp_read_some(conn); /* read as much as we can without blocking */
	if (r < 0)
	    return r;
        /* make packets of the buffer, while we can. */
        while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
            r = pptp_dispatch_packet(conn, buffer, size);
            free(buffer);
        }
    }
    /* That's all, folks.  Simple, eh? */
    return r;
}
Exemplo n.º 2
0
/*
 * pptp_handle_ctrl_connection
 *
 * 1. read a packet (should be start_ctrl_conn_rqst)
 * 2. reply to packet (send a start_ctrl_conn_rply)
 * 3. proceed with GRE and CTRL connections
 *
 * args: pppaddrs - ppp local and remote addresses (strings)
 *       inetaddrs - local and client socket address
 * retn: 0 success, -1 failure
 */
static void pptp_handle_ctrl_connection(char **pppaddrs, struct in_addr *inetaddrs)
{

	/* For echo requests used to check link is alive */
	int echo_wait = FALSE;		/* Waiting for echo? */
	u_int32_t echo_count = 0;	/* Sequence # of echo */
	time_t echo_time = 0;		/* Time last echo req sent */
	struct timeval idleTime;	/* How long to select() */

	/* General local variables */
	ssize_t rply_size;		/* Reply packet size */
	fd_set fds;			/* For select() */
	int maxfd = clientSocket;	/* For select() */
	int send_packet;		/* Send a packet this time? */
#if BSDUSER_PPP || SLIRP
/* not needed by stuff which uses socketpair() in startCall() */
#define init 1
#else
	int init = 0;			/* Has pppd initialized the pty? */
#endif
	int pty_fd = -1;		/* File descriptor of pty */
	int gre_fd = -1;		/* Network file descriptor */
	int sig_fd = sigpipe_fd();	/* Signal pipe descriptor	*/

	unsigned char packet[PPTP_MAX_CTRL_PCKT_SIZE];
	unsigned char rply_packet[PPTP_MAX_CTRL_PCKT_SIZE];

	for (;;) {

		FD_ZERO(&fds);
		FD_SET(sig_fd, &fds);
		FD_SET(clientSocket, &fds);
		if (pty_fd != -1)
			FD_SET(pty_fd, &fds);
		if (gre_fd != -1 && init)
			FD_SET(gre_fd, &fds);

		/* set timeout */
		if (encaps_gre(-1, NULL, 0) || decaps_hdlc(-1, NULL, 0)) {
			idleTime.tv_sec = 0;
			idleTime.tv_usec = 50000; /* don't ack immediately */
		} else {
			idleTime.tv_sec = IDLE_WAIT;
			idleTime.tv_usec = 0;
		}

		/* default: do nothing */
		send_packet = FALSE;

		switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
		case -1:	/* Error with select() */
			if (errno != EINTR)
				syslog(LOG_ERR, "CTRL: Error with select(), quitting");
			goto leave_clear_call;

		case 0:
			if (decaps_hdlc(-1, NULL, 0)) {
				if(decaps_hdlc(-1, encaps_gre, gre_fd))
					syslog(LOG_ERR, "CTRL: GRE re-xmit failed");
			} else if (encaps_gre(-1, NULL, 0))
				/* Pending ack and nothing else to do */
				encaps_gre(gre_fd, NULL, 0);	/* send ack with no payload */
			else if (echo_wait != TRUE) {
				/* Timeout. Start idle link detection. */
				echo_count++;
				if (pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Sending ECHO REQ id %d", echo_count);
				time(&echo_time);
				make_echo_req_packet(rply_packet, &rply_size, echo_count);
				echo_wait = TRUE;
				send_packet = TRUE;
			}
			break;

		default:
			break;
		}

		/* check for pending SIGTERM delivery */
		if (FD_ISSET(sig_fd, &fds)) {
			if (sigpipe_read() == SIGTERM)
				bail(SIGTERM);
		}

		/* detect startup of pppd */
#ifndef init
		if (!init && pty_fd != -1 && FD_ISSET(pty_fd, &fds))
			init = 1;
#endif

		/* handle actual packets */

		/* send from pty off via GRE */
		if (pty_fd != -1 && FD_ISSET(pty_fd, &fds) && decaps_hdlc(pty_fd, encaps_gre, gre_fd) < 0) {
			syslog(LOG_ERR, "CTRL: PTY read or GRE write failed (pty,gre)=(%d,%d)", pty_fd, gre_fd);
			break;
		}
		/* send from GRE off to pty */
		if (gre_fd != -1 && FD_ISSET(gre_fd, &fds) && decaps_gre(gre_fd, encaps_hdlc, pty_fd) < 0) {
			if (gre_fd == 6 && pty_fd == 5) {
				syslog(LOG_ERR, "CTRL: GRE-tunnel has collapsed (GRE read or PTY write failed (gre,pty)=(%d,%d))", gre_fd, pty_fd);
			} else {
				syslog(LOG_ERR, "CTRL: GRE read or PTY write failed (gre,pty)=(%d,%d)", gre_fd, pty_fd);
			}
			break;
		}
		/* handle control messages */

		if (FD_ISSET(clientSocket, &fds)) {
			send_packet = TRUE;
			switch (read_pptp_packet(clientSocket, packet, rply_packet, &rply_size)) {
			case 0:
				syslog(LOG_ERR, "CTRL: CTRL read failed");
				goto leave_drop_call;

			case -1:
				send_packet = FALSE;
				break;

			case STOP_CTRL_CONN_RQST:
				if (pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Received STOP CTRL CONN request (disconnecting)");
				if (gre_fd != -1 || pty_fd != -1)
					syslog(LOG_WARNING, "CTRL: Request to close control connection when call is open, closing");
				send_pptp_packet(clientSocket, rply_packet, rply_size);
				goto leave_drop_call;

			case CALL_CLR_RQST:
				if(pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Received CALL CLR request (closing call)");
				if (gre_fd == -1 || pty_fd == -1)
					syslog(LOG_WARNING, "CTRL: Request to close call but call not open");
				if (gre_fd != -1) {
					FD_CLR(gre_fd, &fds);
					close(gre_fd);
					gre_fd = -1;
				}
				if (pty_fd != -1) {
					FD_CLR(pty_fd, &fds);
					close(pty_fd);
					pty_fd = -1;
				}
				/* violating RFC */
                                goto leave_drop_call;

			case OUT_CALL_RQST:
				/* for killing off the link later (ugly) */
				NOTE_VALUE(PAC, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id);
				NOTE_VALUE(PNS, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id_peer);
				if (gre_fd != -1 || pty_fd != -1) {
					syslog(LOG_WARNING, "CTRL: Request to open call when call is already open, closing");
					if (gre_fd != -1) {
						FD_CLR(gre_fd, &fds);
						close(gre_fd);
						gre_fd = -1;
					}
					if (pty_fd != -1) {
						FD_CLR(pty_fd, &fds);
						close(pty_fd);
						pty_fd = -1;
					}
				}
                                /* change process title for accounting and status scripts */
                                my_setproctitle(gargc, gargv,
                                      "pptpd [%s:%04X - %04X]",
                                      inet_ntoa(inetaddrs[1]),
                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id_peer),
                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id));
				/* start the call, by launching pppd */
				syslog(LOG_INFO, "CTRL: Starting call (launching pppd, opening GRE)");
				pty_fd = startCall(pppaddrs, inetaddrs);
				if (pty_fd > maxfd) maxfd = pty_fd;
				if ((gre_fd = pptp_gre_init(call_id_pair, pty_fd, inetaddrs)) > maxfd)
					maxfd = gre_fd;
				break;

			case ECHO_RPLY:
				if (echo_wait == TRUE && ((struct pptp_echo_rply *) (packet))->identifier == echo_count)
					echo_wait = FALSE;
				else
					syslog(LOG_WARNING, "CTRL: Unexpected ECHO REPLY packet");
				/* FALLTHRU */
			case SET_LINK_INFO:
				send_packet = FALSE;
				break;

#ifdef PNS_MODE
			case IN_CALL_RQST:
			case IN_CALL_RPLY:
			case IN_CALL_CONN:
#endif

			case CALL_DISCONN_NTFY:
			case STOP_CTRL_CONN_RPLY:
				/* These don't generate replies.  Also they come from things we don't send in this section. */
				syslog(LOG_WARNING, "CTRL: Got a reply to a packet we didn't send");
				send_packet = FALSE;
				break;

			/* Otherwise, the already-formed reply will do fine, so send it */
			}
		}

		/* send reply packet - this may block, but it should be very rare */
		if (send_packet == TRUE && send_pptp_packet(clientSocket, rply_packet, rply_size) < 0) {
			syslog(LOG_ERR, "CTRL: Error sending GRE, aborting call");
			goto leave_clear_call;
		}

		/* waiting for echo reply and curtime - echo_time > max wait */
		if (echo_wait == TRUE && (time(NULL) - echo_time) > MAX_ECHO_WAIT) {
			syslog(LOG_INFO, "CTRL: Session timed out, ending call");
			goto leave_clear_call;
		}
	}
	/* Finished! :-) */
leave_drop_call:
	NOTE_VALUE(PAC, call_id_pair, htons(-1));
	NOTE_VALUE(PNS, call_id_pair, htons(-1));
	close(clientSocket);
leave_clear_call:
	/* leave clientSocket and call_id_pair alone for bail() */
	if (gre_fd != -1)
		close(gre_fd);
	gre_fd = -1;
	if (pty_fd != -1)
		close(pty_fd);
	pty_fd = -1;
	return;
#ifdef init
#undef init
#endif
}
Exemplo n.º 3
0
int pptp_manager(int argc, char **argv)
{
        int firstOpen = -1;
        int ctrl_pid;
        socklen_t addrsize;

        int hostSocket;
        fd_set connSet;

        int rc, sig_fd;

        rc = sigpipe_create();
        if (rc < 0) {
                syslog(LOG_ERR, "MGR: unable to setup sigchld pipe!");
                syslog_perror("sigpipe_create");
                exit(-1);
        }
        
        sigpipe_assign(SIGCHLD);
        sigpipe_assign(SIGTERM);
        sig_fd = sigpipe_fd();

        /* openlog() not required, done in pptpd.c */

        syslog(LOG_INFO, "MGR: Manager process started");

        if (!pptp_delegate) {
                syslog(LOG_INFO, "MGR: Maximum of %d connections available", 
                       pptp_connections);
        }

        /* Connect the host socket and activate it for listening */
        if (createHostSocket(&hostSocket) < 0) {
                syslog(LOG_ERR, "MGR: Couldn't create host socket");
                syslog_perror("createHostSocket");
                exit(-1);
        }

        while (1) {
                int max_fd;
                FD_ZERO(&connSet);
                if (pptp_delegate) {
                        FD_SET(hostSocket, &connSet);
                } else {
                        firstOpen = slot_find_empty();
                        if (firstOpen == -1) {
                                syslog(LOG_ERR, "MGR: No free connection slots or IPs - no more clients can connect!");
                        } else {
                                FD_SET(hostSocket, &connSet);
                        }
                }
                max_fd = hostSocket;

                FD_SET(sig_fd, &connSet);
                if (max_fd < sig_fd) max_fd = sig_fd;

                while (1) {
                        if (select(max_fd + 1, &connSet, NULL, NULL, NULL) != -1) break;
                        if (errno == EINTR) continue;
                        syslog(LOG_ERR, "MGR: Error with manager select()!");
                        syslog_perror("select");
                        exit(-1);
                }

                if (FD_ISSET(sig_fd, &connSet)) {       /* SIGCHLD */
                        int signum = sigpipe_read();
                        if (signum == SIGCHLD)
                                sigchld_responder(signum);
                        else if (signum == SIGTERM)
                        {
                                if (!keep_connections) sigterm_responder();
                                    return signum;
                        }
                }

                if (FD_ISSET(hostSocket, &connSet)) {   /* A call came! */
                        int clientSocket;
                        struct sockaddr_in client_addr;

                        /* Accept call and launch PPTPCTRL */
                        addrsize = sizeof(client_addr);
                        clientSocket = accept(hostSocket, (struct sockaddr *) &client_addr, &addrsize);

#ifdef HAVE_LIBWRAP
                        if (clientSocket != -1) {
                                struct request_info r;
                                request_init(&r, RQ_DAEMON, "pptpd", RQ_FILE, clientSocket, NULL);
                                fromhost(&r);
                                if (!hosts_access(&r)) {
                                        /* send a permission denied message? this is a tcp wrapper
                                         * type deny so probably best to just drop it immediately like
                                         * this, as tcp wrappers usually do.
                                         */
                                        close(clientSocket);
                                        /* this would never be file descriptor 0, so use it as a error
                                         * value
                                         */
                                        clientSocket = 0;
                                }
                        }
#endif
                        if (clientSocket == -1) {
                                /* accept failed, but life goes on... */
                                syslog(LOG_ERR, "MGR: accept() failed");
                                syslog_perror("accept");
                        } else if (clientSocket != 0) {
                                fd_set rfds;
                                struct timeval tv;
                                struct pptp_header ph;

                                /* TODO: this select below prevents
                                   other connections from being
                                   processed during the wait for the
                                   first data packet from the
                                   client. */

                                /*
                                 * DOS protection: get a peek at the first packet
                                 * and do some checks on it before we continue.
                                 * A 10 second timeout on the first packet seems reasonable
                                 * to me,  if anything looks sus,  throw it away.
                                 */

                                FD_ZERO(&rfds);
                                FD_SET(clientSocket, &rfds);
                                tv.tv_sec = pptp_stimeout;
                                tv.tv_usec = 0;
                                if (select(clientSocket + 1, &rfds, NULL, NULL, &tv) <= 0) {
                                        syslog(LOG_ERR, "MGR: dropped slow initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                if (recv(clientSocket, &ph, sizeof(ph), MSG_PEEK) !=
                                                sizeof(ph)) {
                                        syslog(LOG_ERR, "MGR: dropped small initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                ph.length = ntohs(ph.length);
                                ph.pptp_type = ntohs(ph.pptp_type);
                                ph.magic = ntohl(ph.magic);
                                ph.ctrl_type = ntohs(ph.ctrl_type);

                                if (ph.length <= 0 || ph.length > PPTP_MAX_CTRL_PCKT_SIZE) {
                                        syslog(LOG_WARNING, "MGR: initial packet length %d outside "
                                                        "(0 - %d)",  ph.length, PPTP_MAX_CTRL_PCKT_SIZE);
                                        goto dos_exit;
                                }

                                if (ph.magic != PPTP_MAGIC_COOKIE) {
                                        syslog(LOG_WARNING, "MGR: initial packet bad magic");
                                        goto dos_exit;
                                }

                                if (ph.pptp_type != PPTP_CTRL_MESSAGE) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad type");
                                        goto dos_exit;
                                }

                                if (ph.ctrl_type != START_CTRL_CONN_RQST) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad ctrl type "
                                                        "0x%x", ph.ctrl_type);
                dos_exit:
                                        close(clientSocket);
                                        continue;
                                }

#ifndef HAVE_FORK
                                switch (ctrl_pid = vfork()) {
#else
                                switch (ctrl_pid = fork()) {
#endif
                                case -1:        /* error */
                                        syslog(LOG_ERR, "MGR: fork() failed launching " PPTP_CTRL_BIN);
                                        close(clientSocket);
                                        break;

                                case 0: /* child */
                                        close(hostSocket);
                                        if (pptp_debug)
                                                syslog(LOG_DEBUG, "MGR: Launching " PPTP_CTRL_BIN " to handle client");
                                        connectCall(clientSocket, !pptp_delegate ? firstOpen : 0);
                                        _exit(1);
                                        /* NORETURN */
                                default:        /* parent */
                                        close(clientSocket);
                                        unique_call_id += MAX_CALLS_PER_TCP_LINK;
                                        if (!pptp_delegate)
                                                slot_set_pid(firstOpen, ctrl_pid);
                                        break;
                                }
                        }
                }               /* FD_ISSET(hostSocket, &connSet) */
        }                       /* while (1) */
}                               /* pptp_manager() */

/*
 * Author: Kevin Thayer
 * 
 * This creates a socket to listen on, sets the max # of pending connections and 
 * various other options.
 * 
 * Returns the fd of the host socket.
 * 
 * The function return values are:
 * 0 for sucessful
 * -1 for bad socket creation
 * -2 for bad socket options
 * -3 for bad bind
 * -4 for bad listen
 */
static int createHostSocket(int *hostSocket)
{
        int opt = 1;
        struct sockaddr_in address;
#ifdef HAVE_GETSERVBYNAME
        struct servent *serv;
#endif

        /* create the master socket and check it worked */
        if ((*hostSocket = vrf_socket(vrf, AF_INET, SOCK_STREAM, 0)) <= 0)
                return -1;

        /* set master socket to allow daemon to be restarted with connections active  */
        if (setsockopt(*hostSocket, SOL_SOCKET, SO_REUSEADDR,
                       (char *) &opt, sizeof(opt)) < 0)
                return -2;

        /* set up socket */
        memset(&address, 0, sizeof(address));
        address.sin_family = AF_INET;
        if(bindaddr)
                address.sin_addr.s_addr = inet_addr(bindaddr);
        else
                address.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_GETSERVBYNAME
        if ((serv = getservbyname("pptp", "tcp")) != NULL) {
                address.sin_port = serv->s_port;
        } else
#endif
                address.sin_port = htons(PPTP_PORT);

        /* bind the socket to the pptp port */
        if (bind(*hostSocket, (struct sockaddr *) &address, sizeof(address)) < 0)
                return -3;

        /* minimal backlog to avoid DoS */
        if (listen(*hostSocket, 3) < 0)
                return -4;

        return 0;
}
Exemplo n.º 4
0
/*
 * pptp_handle_ctrl_connection
 *
 * 1. read a packet (should be start_ctrl_conn_rqst)
 * 2. reply to packet (send a start_ctrl_conn_rply)
 * 3. proceed with GRE and CTRL connections
 *
 * args: pppaddrs - ppp local and remote addresses (strings)
 *       inetaddrs - local and client socket address
 * retn: 0 success, -1 failure
 */
static void pptp_handle_ctrl_connection(char **pppaddrs, struct in_addr *inetaddrs)
{

	/* For echo requests used to check link is alive */
	int echo_wait = FALSE;		/* Waiting for echo? */
	u_int32_t echo_count = 0;	/* Sequence # of echo */
	time_t echo_time = 0;		/* Time last echo req sent */
	struct timeval idleTime;	/* How long to select() */

	/* General local variables */
	ssize_t rply_size;		/* Reply packet size */
	fd_set fds;			/* For select() */
	int maxfd = clientSocket;	/* For select() */
	int send_packet;		/* Send a packet this time? */
#if BSDUSER_PPP || SLIRP
/* not needed by stuff which uses socketpair() in startCall() */
#define init 1
#else
	int init = 0;			/* Has pppd initialized the pty? */
#endif
	int sig_fd = sigpipe_fd();	/* Signal pipe descriptor	*/

	unsigned char packet[PPTP_MAX_CTRL_PCKT_SIZE];
	unsigned char rply_packet[PPTP_MAX_CTRL_PCKT_SIZE];

	struct sockaddr_pppox dst_addr;

	for (;;) {

		FD_ZERO(&fds);
		FD_SET(sig_fd, &fds);
		FD_SET(clientSocket, &fds);

		/* set timeout */
		idleTime.tv_sec = IDLE_WAIT;
			idleTime.tv_usec = 0;

		/* default: do nothing */
		send_packet = FALSE;

		switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
		case -1:	/* Error with select() */
			if (errno != EINTR)
				syslog(LOG_ERR, "CTRL: Error with select(), quitting");
			goto leave_clear_call;

		case 0:
			if (echo_wait != TRUE) {
				/* Timeout. Start idle link detection. */
				echo_count++;
				if (pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Sending ECHO REQ id %d", echo_count);
				time(&echo_time);
				make_echo_req_packet(rply_packet, &rply_size, echo_count);
				echo_wait = TRUE;
				send_packet = TRUE;
			}
			break;

		default:
			break;
		}

		/* check for pending SIGTERM delivery */
		if (FD_ISSET(sig_fd, &fds)) {
			if (sigpipe_read() == SIGTERM)
				bail(SIGTERM);
		}

		/* handle control messages */

		if (FD_ISSET(clientSocket, &fds)) {
			send_packet = TRUE;
			switch (read_pptp_packet(clientSocket, packet, rply_packet, &rply_size)) {
			case 0:
				syslog(LOG_ERR, "CTRL: CTRL read failed");
				goto leave_drop_call;

			case -1:
				send_packet = FALSE;
				break;

			case STOP_CTRL_CONN_RQST:
				if (pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Received STOP CTRL CONN request (disconnecting)");
				send_pptp_packet(clientSocket, rply_packet, rply_size);
				goto leave_drop_call;

			case CALL_CLR_RQST:
				if(pptpctrl_debug)
					syslog(LOG_DEBUG, "CTRL: Received CALL CLR request (closing call)");
				/* violating RFC */
                                goto leave_drop_call;

			case OUT_CALL_RQST:
				/* for killing off the link later (ugly) */
				NOTE_VALUE(PAC, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id);
				NOTE_VALUE(PNS, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id_peer);

				pptp_timeout*=1000;
				if (setsockopt(pptp_sock,0,PPTP_SO_TIMEOUT,&pptp_timeout,sizeof(pptp_timeout)))
					syslog(LOG_WARNING,"CTRL: failed to setsockopt SO_TIMEOUT\n");

				dst_addr.sa_family=AF_PPPOX;
				dst_addr.sa_protocol=PX_PROTO_PPTP;
				dst_addr.sa_addr.pptp.call_id=htons(((struct pptp_out_call_rply *) (rply_packet))->call_id_peer);
				dst_addr.sa_addr.pptp.sin_addr=inetaddrs[1];

				if (connect(pptp_sock,(struct sockaddr*)&dst_addr,sizeof(dst_addr))){
					syslog(LOG_ERR,"CTRL: failed to connect PPTP socket (%s)\n",strerror(errno));
					exit(-1);
					break;
				}


                                /* change process title for accounting and status scripts */
                                my_setproctitle(gargc, gargv,
                                      "pptpd [%s:%04X - %04X]",
                                      inet_ntoa(inetaddrs[1]),
                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id_peer),
                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id));
				/* start the call, by launching pppd */
				syslog(LOG_INFO, "CTRL: Starting call (launching pppd, opening GRE)");
				startCall(pppaddrs, inetaddrs);
				if (PPP_WAIT) {
					switch(ioctl(pptp_sock,PPPTPIOWFP,PPP_WAIT)){
					case -1:
						syslog(LOG_ERR,
						       "CTRL: waiting for first packet failed, ignoring");
						break;
					case 0:
						syslog(LOG_ERR,
						       "CTRL: timeout waiting for first packet");
						break;
					}
				}
				close(pptp_sock);
				pptp_sock=-1;
				break;

			case ECHO_RPLY:
				if (echo_wait == TRUE && ((struct pptp_echo_rply *) (packet))->identifier == echo_count)
					echo_wait = FALSE;
				else
					syslog(LOG_WARNING, "CTRL: Unexpected ECHO REPLY packet");
				/* FALLTHRU */
			case SET_LINK_INFO:
				send_packet = FALSE;
				break;

#ifdef PNS_MODE
			case IN_CALL_RQST:
			case IN_CALL_RPLY:
			case IN_CALL_CONN:
#endif

			case CALL_DISCONN_NTFY:
			case STOP_CTRL_CONN_RPLY:
				/* These don't generate replies.  Also they come from things we don't send in this section. */
				syslog(LOG_WARNING, "CTRL: Got a reply to a packet we didn't send");
				send_packet = FALSE;
				break;

			/* Otherwise, the already-formed reply will do fine, so send it */
			}
		}

		/* send reply packet - this may block, but it should be very rare */
		if (send_packet == TRUE && send_pptp_packet(clientSocket, rply_packet, rply_size) < 0) {
			syslog(LOG_ERR, "CTRL: Error sending GRE, aborting call");
			goto leave_clear_call;
		}

		/* waiting for echo reply and curtime - echo_time > max wait */
		if (echo_wait == TRUE && (time(NULL) - echo_time) > MAX_ECHO_WAIT) {
			syslog(LOG_INFO, "CTRL: Session timed out, ending call");
			goto leave_clear_call;
		}
	}
	/* Finished! :-) */
leave_drop_call:
	NOTE_VALUE(PAC, call_id_pair, htons(-1));
	NOTE_VALUE(PNS, call_id_pair, htons(-1));
	close(clientSocket);
leave_clear_call:
	return;
#ifdef init
#undef init
#endif
}