/*
 *===========================================================================
 *                    ipnet_gre_tmo
 *===========================================================================
 * Description: Reassembly timeout handler.
 * Parameters:  netif - A GRE tunnel interface.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_STATIC void
ipnet_gre_seq_tmo(Ipnet_netif *netif)
{
    Ipnet_pkt_gre *gre_hdr;
    Ipcom_pkt     *pkt;
    Ipnet_gre_t   *gre = netif->ipcom.pdrv;

    /* RFC 2890, chapter 2.2
       ...
       Under no circumstances should a packet wait more that
       OUTOFORDER_TIMER milliseconds in the buffer.  If a packet has been
       waiting that long, the receiver MUST immediately traverse the buffer
       in sorted order, decapsulating packets (and ignoring any sequence
       number gaps) until there are no more packets in the buffer that have
       been waiting longer than OUTOFORDER_TIMER milliseconds. The "last
       successfully decapsulated sequence number" should then be set to the
       last packet so decapsulated.
       ...
    */
    pkt = ipcom_pqueue_get_next(gre->reassembly_queue);
    ip_assert(pkt != IP_NULL);
    gre->recv_seqnum = IP_GET_NTOHL(&pkt->data[pkt->start]);

    do
    {
        pkt = ipcom_pqueue_remove_next(gre->reassembly_queue);
        /* Discard the sequence number option and make place for a GRE header */
        pkt->start += IPNET_GRE_OPT_SEQNUM_SIZE - IPNET_GRE_HDR_SIZE;

        gre_hdr = (Ipnet_pkt_gre *)&pkt->data[pkt->start];
        gre_hdr->flags_reserved0_ver = 0;
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV4))
            gre_hdr->protocol_type = ip_htons(0x0800);
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV6))
            gre_hdr->protocol_type = ip_htons(0x86DD);

        (void) ipnet_gre_input(netif, pkt);
        ++gre->recv_seqnum;
    } while (IP_NULL != (pkt = ipcom_pqueue_get_next(gre->reassembly_queue))
             && gre->recv_seqnum == IP_GET_NTOHL(&pkt->data[pkt->start]));

    if (pkt != IP_NULL)
    {
        Ip_u32 timeout = IPNET_PKT_GET_TIMEOUT_ABS(pkt);

        /* More out of order packets waiting, schedule a timeout of
           the time remaining until this packet sequence timer timeouts */
        (void) ipnet_timeout_schedule((timeout < ipnet->msec_now
                                       ? 0
                                       : timeout - ipnet->msec_now),
                                      (Ipnet_timeout_handler) ipnet_gre_seq_tmo,
                                      netif,
                                      &gre->reassembly_tmo);
    }
}
/*
 *===========================================================================
 *                    ipnet_gre_destroy
 *===========================================================================
 * Description: Destroy the GRE tunnel.
 * Parameters:  netif - A GRE tunnel interface.
 * Returns:
 *
 */
IP_GLOBAL void
ipnet_gre_destroy(Ipnet_netif *netif)
{
#ifdef IPNET_USE_RFC2890
    Ipnet_gre_t *gre = netif->ipcom.pdrv;
    Ipcom_pkt   *pkt;

    if (gre != IP_NULL)
    {
        if (gre->reassembly_queue != IP_NULL)
        {
            while (IP_NULL != (pkt = ipcom_pqueue_remove_next(gre->reassembly_queue)))
                ipcom_pkt_free(pkt);
            ipcom_pqueue_delete(gre->reassembly_queue);
        }
        ipnet_timeout_cancel(gre->reassembly_tmo);
        ipcom_free(gre);
    }
#endif /* IPNET_USE_RFC2890 */
}
Example #3
0
/*
 *===========================================================================
 *                    ipcom_sysvar_for_each
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 */
IP_PUBLIC Ip_err
ipcom_sysvar_for_each(const char            *name,
                      Ipcom_sysvar_for_each cb_func,
                      void                  *cookie)
{
    Ipcom_sysvar_entry *sysvar;
    Ipcom_sysvar_tree  *tree;
    Ip_size_t           namelen = 0;
    Ip_err              retval;
    Ipcom_pqueue       *pq;

    retval = ipcom_once(&ipcom_sysvar_once, ipcom_sysvar_init, IP_NULL);
    if (retval != IPCOM_SUCCESS)
        return retval;

    if (name)
    {
        namelen = ipcom_strlen(name);
        if (name[namelen-1] == '*')
            namelen--; /* ignore trailing wildcard sign */
    }

    pq = ipcom_pqueue_new((Ipcom_pqueue_cmp_func)ipcom_sysvar_pqueue_cmp,
                          ipcom_pqueue_nop_store_index);
    if (pq == IP_NULL)
        return IPCOM_ERR_NO_MEMORY;

    IPCOM_CODE_LOCK();

    tree = ipcom_sysvar_tree_get(-1);
    if (tree == IP_NULL)
    {
        ipcom_pqueue_delete(pq);
        IPCOM_CODE_UNLOCK();
        return IPCOM_ERR_NO_MEMORY;
    }

    /* Add all sysvars to the priority queue so they can be extracted
       sorted in lexicographical order */
    ipcom_hash_for_each(tree->sysvars,
                        (Ipcom_hash_foreach_cb_func)ipcom_sysvar_pqueue_insert_cb,
                        pq);

    while (IP_NULL != (sysvar = ipcom_pqueue_remove_next(pq)))
    {
        if (name == IP_NULL
            || ipcom_strncmp(sysvar->name, name, namelen) == 0)
        {
            IPCOM_CODE_UNLOCK();
            (void)cb_func(sysvar->name, sysvar->value, sysvar->flags, cookie);
            IPCOM_CODE_LOCK();
        }
        ipcom_sysvar_release(tree, sysvar);
    }

    ipcom_pqueue_delete(pq);
    ipcom_sysvar_tree_done(tree);

    IPCOM_CODE_UNLOCK();

#ifdef IP_PORT_OSE5_DISABLED
    return ipcom_sysvar_for_each_ose5(name, cb_func, cookie);
#else
    return IPCOM_SUCCESS;
#endif
}