⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip.c

📁 基于东南大学开发的SEP3203的ARM7中的所有驱动
💻 C
📖 第 1 页 / 共 5 页
字号:

    /* If this packet is small enough send it.*/
    if (GET16(ip_dgram, IP_TLEN_OFFSET) <= int_face->dev_mtu)
    {

        /* Compute the IP checksum. Note that the length expected by TLS_IP_Check is 
           the length of the header in 16 bit half-words. */
        PUT16(ip_dgram, IP_CHECK_OFFSET, 0);
        PUT16(ip_dgram, IP_CHECK_OFFSET, TLS_IP_Check ((UINT16 *)ip_dgram, (UINT16)(hlen >> 1)) );

        /* Set the packet type that is in the buffer. */
        buf_ptr->mem_flags |= NET_IP;

        /* Send the packet. */
        
        status = (*(int_face->dev_output)) (buf_ptr, int_face, dest, ro);
    }
    else /* This packet must be fragmented. */
    {
#if INCLUDE_IP_FRAGMENT

        /* If the don't fragment bit is set return an error. */
        if (GET16(ip_dgram, IP_FRAGS_OFFSET) & IP_DF)
        {
            /* Increment the number of IP packets that could not be
               fragmented. In this case becuase the don't fragment
               bit is set. */
            SNMP_ipFragFails_Inc;

            return(NU_MSGSIZE);
        }
        
        status = IP_Fragment (buf_ptr, ip_dgram, int_face, dest, ro);
#else
        return(NU_MSGSIZE);
#endif
    }

    if ( (ro == &iproute) && ((flags & IP_ROUTETOIF) == 0) && ro->rt_route )
        RTAB_Free(ro->rt_route);

    return (status);

} /* IP_Send */

#if INCLUDE_IP_FRAGMENT

/***********************************************************************
*                                                                       
* FUNCTION                                                              
*                                                                       
*      IP_Fragment                                                      
*                                                                       
* DESCRIPTION                                                           
*                                                                       
*      Fragment an IP packet.                                           
*                                                                       
* INPUTS                                                                
*                                                                       
*      buf_ptr                                                          
*      ip                                                               
*      int_face                                                         
*      dest                                                             
*      ro                                                               
*                                                                       
* OUTPUTS                                                               
*                                                                       
*      NU_SUCCESS                                                       
*      NU_MSGSIZE                                                       
*                                                                       
*************************************************************************/

STATUS IP_Fragment (NET_BUFFER *buf_ptr, IPLAYER *ip, DV_DEVICE_ENTRY *int_face,
                    SCK_SOCKADDR_IP *dest, RTAB_ROUTE *ro)
{
    INT32       len, hlen, tlen, f_hlen, first_len, data_len, total_data_len;
    INT32       off;
    NET_BUFFER  *work_buf;
    NET_BUFFER  *f_buf = buf_ptr;
    NET_BUFFER  **next = &buf_ptr->next;
    STATUS      err = NU_SUCCESS;
    IPLAYER     *f_ip;
    INT32       aloc_len;
    INT         at_least_one_succeeded = 0;

    /* Make sure this buffer is not pointing to any list. It should
       not be at this point. */
    buf_ptr->next = NU_NULL;

    hlen = (GET8(ip, IP_VERSIONANDHDRLEN_OFFSET) & 0x0f) << 2;

    /* len is the number of data bytes in each fragment. Computed as the mtu of
       the interface less the size of the header and rounded down to an 8-byte
       boundary by clearing the low-order 3 bits (& ~7).
    */
    len = (int_face->dev_mtu - hlen) & ~7;
    first_len = len;

    /* Each fragment must be able to hold at least 8 bytes. */
    if (len < 8)
        return NU_MSGSIZE;

    tlen = GET16(ip, IP_TLEN_OFFSET);

    buf_ptr = f_buf;

    f_hlen = sizeof(IPLAYER);

    aloc_len = len;

    /* Create the fragments. */
    for (off = hlen + len; off < tlen; off += len)
    {
        if (off + len >= GET16(ip, IP_TLEN_OFFSET))
            /* Shorten the length if this is the last fragment. */
            aloc_len = GET16(ip, IP_TLEN_OFFSET) - off;

        /* Allocate a buffer chain to build the fragment in. */
        f_buf = MEM_Buffer_Chain_Dequeue(&MEM_Buffer_Freelist, aloc_len +
                                         hlen + int_face->dev_hdrlen);

        if (f_buf == NU_NULL)

        {
            err = NU_NOBUFS;

            /* Increment the number of IP packets that could not be
               fragmented. In this case becuase of no buffers. */
            SNMP_ipFragFails_Inc;

            break;
        }

        /* Initialize mem_dlist for deallocation */
        f_buf->mem_dlist = &MEM_Buffer_Freelist;

        /* Point to the location where the IP header will begin. */
        f_buf->data_ptr = f_buf->mem_parent_packet + int_face->dev_hdrlen;

        /* Overlay the IP header so we can access the individual fields. */
        f_ip = (IPLAYER *)f_buf->data_ptr;

        /* Copy the IP header over to the new packet. */
        IP_HEADER_COPY(f_ip, ip);

        /* If there are options in the original, packet copy them. */
        if (hlen > sizeof(IPLAYER))

        {
            f_hlen = IP_Option_Copy(f_ip, ip) + sizeof(IPLAYER);
            PUT8(f_ip, IP_VERSIONANDHDRLEN_OFFSET, 
                 (UINT8)((f_hlen >> 2) | (IP_VERSION << 4)) );
        }


        /* Set the offset field for the fragment. */
        PUT16(f_ip, IP_FRAGS_OFFSET,
            (INT16)(((off - hlen) >> 3) + (GET16(ip, IP_FRAGS_OFFSET) & ~IP_MF)) );


        /* If MF is set in the original packet then it should be set in all
           fragments. */

        if (GET16(ip, IP_FRAGS_OFFSET) & IP_MF)
            PUT16(f_ip, IP_FRAGS_OFFSET, (INT16)(GET16(f_ip, IP_FRAGS_OFFSET) | IP_MF) );

        /* Is this the last fragment. MF is set for every fragment except the
           last one. Unless MF was set in the original packet. In that case MF
           should have already been set above. */

        if (off + len >= GET16(ip, IP_TLEN_OFFSET))
            /* Shorten the length if this is the last fragment. */
            len = GET16(ip, IP_TLEN_OFFSET) - off;
        else
            /* This is not the last fragment. Set MF. */
            PUT16(f_ip, IP_FRAGS_OFFSET, (INT16)(GET16(f_ip,
                                            IP_FRAGS_OFFSET) | IP_MF) );

        /* Set the new length. */
        PUT16(f_ip, IP_TLEN_OFFSET, (INT16)(len + f_hlen));

        /* The IP header is the only data present. */
        f_buf->data_len = f_hlen;

        /* We will also add the device header length in here. This
           is only done so that the Chain_Copy routine below will
           compute the correct size for the buffer area available.
           It will be removed after the copy. */
        f_buf->data_len += int_face->dev_hdrlen;

        /* Move the data point back to the start of the device header.
           This is also being done for the Chain_Copy routine. It will
           offset by the data_len and skip over these headers when
           doing the copy. */
        f_buf->data_ptr -= int_face->dev_hdrlen;

        /* Copy data from the original packet into this fragment. */
        MEM_Chain_Copy(f_buf, buf_ptr, off, len);

        /* Now remove the device header length that was added
           above. */
        f_buf->data_len -= int_face->dev_hdrlen;

        /* Put the data pointer back as well. */
        f_buf->data_ptr += int_face->dev_hdrlen;

        /* Set the length of all data in this buffer chain. */
        f_buf->mem_total_data_len = len + f_hlen;

        /* Clear the device pointer. */
        f_buf->mem_buf_device = NU_NULL;

        /* Compute the IP header checksum. */
        PUT16(f_ip, IP_CHECK_OFFSET, 0);
        PUT16(f_ip, IP_CHECK_OFFSET, TLS_IP_Check((UINT16 *)f_ip,
                                                (UINT16)(f_hlen >> 1)) );

        /* Link this fragment into the list of fragments. */
        *next = f_buf;
        next = &f_buf->next;

        /* Increment the number of fragments that have been created. */
        SNMP_ipFragCreates_Inc;
    }

    /* If the above loop was successful then the next step is to trim 
       all of the data in the original buffer chain that has been relocated 
       to the chain of fragments. */
    if (err == NU_SUCCESS)
    {
#if (INCLUDE_SNMP == NU_TRUE)
        /* Increment the number of packets that have been fragmented. */
        SNMP_ipFragOKs_Inc;
#endif

        /* Convert the original packet into the first fragment */
        f_buf = buf_ptr;

        /* Update the first fragment by trimming what's been copied out. */
        MEM_Trim(f_buf, hlen + first_len - tlen);

        /* Determine the total data length of the first fragment */
        total_data_len = f_buf->mem_total_data_len;
        data_len = 0;

        /* Terminate the first fragment */
        for(work_buf = f_buf; data_len < total_data_len; work_buf = work_buf->next_buffer)
        {
            data_len = work_buf->data_len + data_len;

            if(data_len == total_data_len)
            {
                /* Deallocate the buffers that the first fragment does not need */
                MEM_One_Buffer_Chain_Free (work_buf->next_buffer, &MEM_Buffer_Freelist);

                work_buf->next_buffer = NU_NULL;
            }
        }

        /* Update the header in the first fragment (the original packet). */
        PUT16(ip, IP_TLEN_OFFSET, (INT16)f_buf->mem_total_data_len);
        PUT16(ip, IP_FRAGS_OFFSET, (INT16)(GET16(ip, IP_FRAGS_OFFSET) | IP_MF));
        PUT16(ip, IP_CHECK_OFFSET, 0);
        PUT16(ip, IP_CHECK_OFFSET, TLS_IP_Check((UINT16 *)ip, (UINT16)(f_hlen >> 1)) );
    }
    else
    {
        /* There were not enough buffers to break the original buffer chain up
           into fragments. An error will be returned and the upper layer 
           software will free the original buffer chain. To keep the buffer chain 
           from being freed twice (once below and once in the upper layer 
           software) move buf_ptr forward, and separate it from the fragments 
           that were created. Doing this will cause the for loop below to only 
           free those buffers that were allocated within this function. The 
           upper layer software will free the original buffer chain. */
        work_buf = buf_ptr;
        buf_ptr = buf_ptr->next;
        work_buf->next = NU_NULL;
    }

    /* Save a pointer to the first buffer in the chain. It might be needed below. */
    work_buf = buf_ptr;

    /* Send each fragment */
    for (f_buf = buf_ptr; f_buf; f_buf = buf_ptr)
    {
        buf_ptr = f_buf->next;
        f_buf->next = NU_NULL;

        /* If the first packet can not be transmitted successfully, then abort 
           and free the rest. */
        if(err == NU_SUCCESS)
        {
            /* Set the packet type that is in the buffer. */
            f_buf->mem_flags |= NET_IP;

            if ((err = (*(int_face->dev_output)) (f_buf, int_face, dest, ro))
                                                            != NU_SUCCESS )
            {
                /* If the error occured on the first buffer don't free it. It will
                   be freed by the upper layer protocol. */
                if (f_buf != work_buf)
                {
                    MEM_One_Buffer_Chain_Free (f_buf, &MEM_Buffer_Freelist);
                }
            }
            else
            {
                /* If at least one fragment was sent successfully we will want
                   to return success below. This is so the upper layer 
                   protocols will not try to free the fragment that was sent 
                   successfully. In reality this should never occur. It would
                   require a device going down or a route being timed out from 
                   under us. Both of which should be impossibile as we have 
                   the semaphore. */
                at_least_one_succeeded = 1;
            }
        }
        else
            MEM_One_Buffer_Chain_Free (f_buf, &MEM_Buffer_Freelist);
    }

    if (at_least_one_succeeded)
        return (NU_SUCCESS);
    else
        return (err);

} /* IP_Fragment */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -