Example #1
0
File: call.c Project: sina-ht/l2tpd
void call_close (struct call *c)
{
    struct buffer *buf;
    struct schedule_entry *se, *ose;
    struct call *tmp, *tmp2;
    if (!c || !c->container)
    {
        l2tp_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
                l2tp_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
            l2tp_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
        l2tp_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;
        }
	/* mf, 16.04.2003: change log message to show tunneltag */
        // l2tp_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);
        l2tp_log (LOG_LOG,
             "%s : Connection closed with peer %s, reason: %s\n",
             __FUNCTION__, c->container->tunneltag, 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
            l2tp_log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__,
                 c->ourcid);
#endif
            destroy_call (c);
            return;
        }
#ifdef USE_KERNEL
        if (kernel_support)
        {
            co.ourtid = c->container->ourtid;
            co.ourcid = c->ourcid;
            ioctl (server_socket, L2TPIOCGETCALLOPTS, &co);
            co.flags = co.flags & ~L2TP_FLAG_CALL_UP;
            ioctl (server_socket, L2TPIOCSETCALLOPTS, &co);
        }
#endif
        c->closeSs = c->container->control_seq_num;
        buf = new_outgoing (c->container);
        add_message_type_avp (buf, CDN);
        if (c->container->hbit)
        {
            mk_challenge (c->container->chal_them.vector, VECTOR_SIZE);
            add_randvect_avp (buf, c->container->chal_them.vector,
                              VECTOR_SIZE);
        }
        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));
#ifdef TEST_HIDDEN
        add_callid_avp (buf, c->ourcid, c->container);
#else
        add_callid_avp (buf, c->ourcid);
#endif
        add_control_hdr (c->container, c, buf);
        if (packet_dump)
            do_packet_dump (buf);
#ifdef DEBUG_CLOSE
        l2tp_log (LOG_DEBUG, "%s: enqueuing close message for call %d\n",
             __FUNCTION__, c->ourcid);
#endif
        control_xmit (buf);
        l2tp_log (LOG_LOG, "%s: Call %d to %s disconnected\n", __FUNCTION__,
             c->ourcid, IPADDY (c->container->peer.sin_addr));
    }
    /*
       * Note that we're in the process of closing now
     */
    c->closing = -1;
}
void call_close (struct call *c)
{
    struct buffer *buf;
    struct schedule_entry *se, *ose;
    struct call *tmp, *tmp2;
    if (!c || !c->container)
    {
        l2tp_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
                l2tp_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
            l2tp_log (LOG_DEBUG, "%s: Actually closing tunnel %d\n", __FUNCTION__,
                      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 (gconfig.packet_dump)
            do_packet_dump (buf);
#ifdef DEBUG_CLOSE
        l2tp_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;
        }
        l2tp_log (LOG_DEBUG, "Connection %d closed to %s, port %d (%s)\n",
                  c->container->tid,
                  IPADDY (c->container->peer.sin_addr),
                  ntohs (c->container->peer.sin_port), c->errormsg);

        if(strcmp(c->errormsg,"Server closing") )
        {
            if(!strcmp(c->errormsg,"goodbye!") )
                l2tp_log (LOG_INFO,
                          "Terminated by router connect %s, cause manual disconnect.\n", IPADDY (c->container->peer.sin_addr) );
            else if( c->msgtype <= 0 || c->msgtype > 16 )
                l2tp_log (LOG_INFO, "Detect %s from %s, port %d \n",
                          c->errormsg, IPADDY (c->container->peer.sin_addr),
                          ntohs (c->container->peer.sin_port));
            else
                l2tp_log (LOG_INFO, "Detect %s %s from %s, port %d \n",
                          msgtypes[c->msgtype],c->errormsg, IPADDY (c->container->peer.sin_addr),
                          ntohs (c->container->peer.sin_port));
        }
        //if( (!strcmp(c->errormsg, "Timeout")) && (c->container->tid != 0) )
        //	l2tp_log(LOG_INFO, "Terminated by router, cause no response to echo-requests.");

    }
    else
    {
        /*
           * Just close a call
         */
        if (c->zlb_xmit)
            deschedule (c->zlb_xmit);
        /*		if (c->dethrottle) deschedule(c->dethrottle); */
        if (c->closing)
        {
#ifdef DEBUG_CLOSE
            l2tp_log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__,
                      c->ourcid);
#endif
            destroy_call (c);
            return;
        }
        c->closeSs = c->container->control_seq_num;
        buf = new_outgoing (c->container);
        add_message_type_avp (buf, CDN);
        if (c->container->hbit)
        {
            mk_challenge (c->container->chal_them.vector, VECTOR_SIZE);
            add_randvect_avp (buf, c->container->chal_them.vector,
                              VECTOR_SIZE);
        }
        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));
#ifdef TEST_HIDDEN
        add_callid_avp (buf, c->ourcid, c->container);
#else
        add_callid_avp (buf, c->ourcid);
#endif
        add_control_hdr (c->container, c, buf);
        if (gconfig.packet_dump)
            do_packet_dump (buf);
#ifdef DEBUG_CLOSE
        l2tp_log (LOG_DEBUG, "%s: enqueuing close message for call %d\n",
                  __FUNCTION__, c->ourcid);
#endif
        control_xmit (buf);
        l2tp_log (LOG_DEBUG, "%s: Call %d to %s disconnected\n", __FUNCTION__,
                  c->ourcid, IPADDY (c->container->peer.sin_addr));
    }
    /*
       * Note that we're in the process of closing now
     */
    c->closing = -1;
}