📄 call.c
字号:
/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Handle a call as a separate thread */#include <stdio.h>#include <fcntl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/wait.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <termios.h>#include "l2tp.h"#ifdef USE_KERNEL#include <sys/ioctl.h>#endifstruct buffer *new_payload (struct sockaddr_in peer){ struct buffer *tmp = new_buf (MAX_RECV_SIZE); if (!tmp) return NULL; tmp->peer = peer; tmp->start += sizeof (struct payload_hdr); tmp->len = 0; return tmp;}inline void recycle_payload (struct buffer *buf, struct sockaddr_in peer){ buf->start = buf->rstart + sizeof (struct payload_hdr); buf->len = 0; buf->peer = peer;}void add_payload_hdr (struct tunnel *t, struct call *c, struct buffer *buf){ struct payload_hdr *p; buf->start -= sizeof (struct payload_hdr); buf->len += sizeof (struct payload_hdr); /* Account for no offset */ buf->start += 4; buf->len -= 4; if (!c->fbit && !c->ourfbit) { /* Forget about Ns and Nr fields then */ buf->start += 4; buf->len -= 4; } if (!c->lbit) { /* Forget about specifying the length */ buf->start += 2; buf->len -= 2; } p = (struct payload_hdr *) buf->start;/* p->ver = htons(c->lbit | c->rbit | c->fbit | c->ourfbit | VER_L2TP); */ p->ver = htons (c->lbit | c->fbit | c->ourfbit | VER_L2TP); if (c->lbit) { p->length = htons ((_u16) buf->len); } else { p = (struct payload_hdr *) (((char *) p) - 2); } p->tid = htons (t->tid); p->cid = htons (c->cid); if (c->fbit || c->ourfbit) { p->Ns = htons (c->data_seq_num); p->Nr = htons (c->data_rec_seq_num); } c->data_seq_num++;/* c->rbit=0; */}int read_packet (struct buffer *buf, int fd, int convert){ unsigned char c; unsigned char escape = 0; unsigned char *p; static unsigned char rbuf[MAX_RECV_SIZE]; static int pos = 0; static int max = 0; int res; int errors = 0; /* Read a packet, doing async->sync conversion if necessary */ p = buf->start; while (1) { if (pos >= max) { max = read (fd, rbuf, sizeof (rbuf)); res = max; pos = 0; } else { res = 1; } c = rbuf[pos++]; if (res < 1) { if (res == 0) { /* * Hmm.. Nothing to read. It happens */ return 0;/* } else if ((errno == EINTR ) || (errno == EAGAIN)) { */ } else if ((errno == EIO) || (errno == EINTR) || (errno == EAGAIN)) { /* * Oops, we were interrupted! * Or, we ran out of data too soon * anyway, we discared whatever it is we * have */ return 0; } errors++; log (LOG_DEBUG, "%s: Error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); if (errors > 10) { log (LOG_DEBUG, "%s: Too many errors. Declaring call dead.\n", __FUNCTION__); return -errno; } continue; } switch (c) { case PPP_FLAG: if (escape) { log (LOG_DEBUG, "%s: got an escaped PPP_FLAG\n", __FUNCTION__); return -EINVAL; } if (convert) { if (!buf->len) break; /* Drop the FCS */ buf->len -= 2; } else { if (buf->len < buf->maxlen) { *p = c; p++; buf->len++; } } return buf->len; case PPP_ESCAPE: escape = PPP_TRANS; if (convert) break; default: if (convert) c ^= escape; escape = 0; if (buf->len < buf->maxlen) { *p = c; p++; buf->len++; break; }; log (LOG_WARN, "%s: read overrun\n", __FUNCTION__); return -EINVAL; } } /* I should never get here */ log (LOG_WARN, "%s: You should not see this message. If you do, please enter a bug report at http://sourceforge.net/projects/l2tpd", __FUNCTION__); return -EINVAL;}void call_close (struct call *c){ struct buffer *buf; struct schedule_entry *se, *ose; struct call *tmp, *tmp2; if (!c || !c->container) { log (LOG_DEBUG, "%s: called on null call or containerless call\n", __FUNCTION__); return; } if (c == c->container->self) { /* * We're actually closing the * entire tunnel */ /* First deschedule any remaining packet transmissions for this tunnel. That means Hello's and any reminaing packets scheduled for transmission. This is a very nasty little piece of code here. */ se = events; ose = NULL; while (se) { if ((((struct buffer *) se->data)->tunnel == c->container) || ((struct tunnel *) se->data == c->container)) {#ifdef DEBUG_CLOSE log (LOG_DEBUG, "%s: Descheduling event\n", __FUNCTION__);#endif if (ose) { ose->next = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = ose->next; } else { events = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = events; } } else { ose = se; se = se->next; } } if (c->closing) { /* Really close this tunnel, as our StopCCN has been ack'd */#ifdef DEBUG_CLOSE log (LOG_DEBUG, "%s: Actually closing tunnel %d\n", __FUNCTION__, c->container->ourtid);#endif#ifdef USE_KERNEL if (kernel_support) ioctl (server_socket, L2TPIOCDELTUNNEL, c->container->ourtid);#endif destroy_tunnel (c->container); return; } /* * We need to close, but need to provide reliable delivery * of the final StopCCN. We record our state to know when * we have actually received an ACK on our StopCCN */ c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, StopCCN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } add_tunnelid_avp (buf, c->container->ourtid); if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); add_control_hdr (c->container, c, buf); if (packet_dump) do_packet_dump (buf);#ifdef DEBUG_CLOSE log (LOG_DEBUG, "%s: enqueing close message for tunnel\n", __FUNCTION__);#endif control_xmit (buf); /* * We also need to stop all traffic on any calls contained * within us. */ tmp = c->container->call_head; while (tmp) { tmp2 = tmp->next; tmp->needclose = 0; tmp->closing = -1; call_close (tmp); tmp = tmp2; } log (LOG_LOG, "%s : Connection %d closed to %s, port %d (%s)\n", __FUNCTION__, c->container->tid, IPADDY (c->container->peer.sin_addr), ntohs (c->container->peer.sin_port), c->errormsg); } else { /* * Just close a call */#ifdef USE_KERNEL struct l2tp_call_opts co;#endif if (c->zlb_xmit) deschedule (c->zlb_xmit);/* if (c->dethrottle) deschedule(c->dethrottle); */ if (c->closing) {#ifdef DEBUG_CLOSE log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__, c->ourcid);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -