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

📄 ipout.c

📁 代码在ti的c67系列单片机上实现了完整的TCPIP协议栈
💻 C
字号:
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// IPOUT.C
//
// Routines related to IP Transmit
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "ip.h"

//--------------------------------------------------------------------
// IPTxPacket( HANDLE hPkt, uint Flags )
//
// Handles requests to send IP packets
//--------------------------------------------------------------------
int IPTxPacket( HANDLE hPkt, uint Flags )
{
    HANDLE   hFrag,hIFTx,hIFRx,hRt,hLLA;
    uint     Offset,Valid,w;
    UINT8    *pb;
    IPHDR    *pIpHdr;
    IPN      IPDst,IPSrc;

    if( !_IPExecuting )
    {
        PktFree( hPkt );
        return(IPTX_SUCCESS);
    }

    if( !(hFrag = PktGetFrag( hPkt ))  ||
          !(PktGetFlags(hPkt) & FLG_PKT_IP_VALID) )
    {
        DbgPrintf(DBG_ERROR,"IPTxPacket: No Header");
        PktFree( hPkt );
        return( IPTX_ERROR );
    }

    // Get the buffer parameters
    pb = FragGetBufParams( hFrag, 0, &Valid, &Offset );

    // Assign the IP Header pointer
    pIpHdr = (IPHDR *)(pb + Offset);

    // Get a handle to the receiving interface
    hIFRx = PktGetIFRx( hPkt );

    //
    // Patch up header if not forwarding or in raw mode.
    //
    // This code WILL patch:
    //     TotalLength, Frag/Offset, and Id
    //
    // This code WILL NOT patch:
    //     Ttl, Protocol, IpSrc, IpDst
    //
    if( !(Flags & (FLG_IPTX_FORWARDING|FLG_IPTX_RAW)) )
    {
        // Set Total Length
        pIpHdr->TotalLen = HNC16( Valid );

        // Set IP Identification
        pIpHdr->Id = HNC16(IP_INDEX++);

        // Set Don't Frag (when specified)
        if( Flags & FLG_IPTX_DONTFRAG )
            pIpHdr->FlagOff = HNC16( IP_DF );
        else
            pIpHdr->FlagOff = 0;
    }
    else if( Flags & FLG_IPTX_RAW )
    {
        // We'll follow BSD's lead on this one
        if( !pIpHdr->Id )
            pIpHdr->Id = HNC16(IP_INDEX++);
    }

    // Perform Checksum
    IPChecksum( pIpHdr );

    // Set Ethertype
    PktSetEthType( hPkt, 0x800 );

    // Now find a route and send!

    // Get IP Source and Destination
    IPSrc = RdNet32( &pIpHdr->dwIPSrc );
    IPDst = RdNet32( &pIpHdr->dwIPDst );

    // Get preliminary route info
    hIFTx = PktGetIFTx( hPkt );
    hRt   = PktGetRoute( hPkt );
    hLLA  = PktGetLLADst( hPkt );

    //
    // Our final goal is to have the following:
    //
    // Valid EtherType in Packet Object
    // Valid IFTx in Pkt
    // Pkt Dst is valid LLA or we have a mapable IP Dst
    //
    // If any of these are not valid now, we can't hand the packet
    // off the the device.
    //

    // If have both a destination LLA and an Egress device, we're done.
    if( hIFTx && hLLA )
        goto IpRouteDone;

    //
    // If we have a multicast or broadcast IP addr, we mark it as valid
    // and distribute it directly to the egress device(s).
    //

    // IP BROADCAST/MULTICAST
    if( IPDst == INADDR_BROADCAST || IN_MULTICAST(IPDst) )
    {
        // If this socket can not broadcast, then this is an error
        if( IPDst == INADDR_BROADCAST && !(Flags & FLG_IPTX_BROADCAST) )
        {
            PktFree( hPkt );
            return( IPTX_ERROR_EACCES );
        }

        // We need an egress interface
        if( !hIFTx )
        {
            hIFTx = BindIPHost2IF( IPSrc );
            if( !hIFTx )
            {
                PktFree( hPkt );
                return( IPTX_ERROR_ADDRNOTAVAIL );
            }
            // Set the egress IF
            PktSetIFTx( hPkt,hIFTx );
        }

        // Set the destination LLA
        if( IFGetType( hIFTx ) == HTYPE_ETH )
        {
            if( IPDst == INADDR_BROADCAST )
                PktSetLLADst( hPkt, EtherGetLLABCast( hIFTx ) );
            else
            {
                if( !LLIMapIpPacket( hPkt, IPDst ) )
                {
                    PktFree( hPkt );
                    return( IPTX_ERROR_ADDRNOTAVAIL );
                }
            }
        }

        // We don't need a route
        PktSetRoute( hPkt, 0 );
        goto IpRouteDone;
    }

    //
    // If the DONTROUTE flag is set, we route to HOST routes only.
    // The search will discard intermediate GATEWAYS. This allows a
    // packet to find a local host in the event that a redirect
    // has been mistakenly entered into the route table.
    //
    if( Flags & FLG_IPTX_DONTROUTE )
    {
        hRt = 0;
        w = FLG_RTF_CLONE|FLG_RTF_REPORT|FLG_RTF_HOST;
    }
    else
        w = FLG_RTF_CLONE|FLG_RTF_REPORT;

    // We need a route to get hIFTx and hLLA
    // If we don't have a route, we must find one
    if( !hRt )
    {
        // Now find the next hop for this packet. Search for a route
        // WITH cloning.
        if( !(hRt = IPGetRoute( w, IPDst, 0 )) )
        {
            if( !(Flags & FLG_IPTX_FORWARDING) )
                ips.dwLocalnoroute++;
            else
            {
                ips.dwCantforward++;
                ICMPGenPacket(pIpHdr,hIFRx,ICMP_UNREACH,ICMP_UNREACH_NET,0);
            }
            PktFree( hPkt );
            return( IPTX_ERROR_UNREACH );
        }

        // Set the route in the packet (this will Ref it)
        PktSetRoute( hPkt, hRt );

        // We can now DeRef the route, but continue using it
        RtDeRef( hRt );
    }

    // Here we have a route we think we can use
    w = RtGetFlags( hRt );

    // If the route is down, we're still unreachable
    if( !(w & FLG_RTE_UP) )
    {
        if( !(Flags & FLG_IPTX_FORWARDING) )
            ips.dwLocalnoroute++;
        else
        {
            ips.dwCantforward++;
            ICMPGenPacket(pIpHdr,hIFRx,ICMP_UNREACH,ICMP_UNREACH_HOST,0);
        }
        PktFree( hPkt );
        return( IPTX_ERROR_HOSTDOWN );
    }

    // If the route is rejecting, we're still unreachable
    if( w & FLG_RTE_REJECT )
    {
        if( !(Flags & FLG_IPTX_FORWARDING) )
            ips.dwLocalnoroute++;
        else
        {
            ips.dwCantforward++;
            ICMPGenPacket(pIpHdr,hIFRx,ICMP_UNREACH,ICMP_UNREACH_HOST,0);
        }
        PktFree( hPkt );
        return( IPTX_ERROR_REJECTED );
    }

    // If the route is a black hole, stop here
    if( w & FLG_RTE_BLACKHOLE )
    {
        PktFree( hPkt );
        return( IPTX_SUCCESS );
    }

    // If the route is local, give the packet to the input function
    if( w & FLG_RTE_IFLOCAL )
    {
        // Note: If hIFRx is not null, we have an error
        if( hIFRx )
        {
            // Setting the IF to NULL tell Rx that this is a LOCAL IF
            PktSetIFRx( hPkt, 0 );
            // Still, better warn the operator
            DbgPrintf(DBG_WARN,"IPTxPacket: Route loop");
        }

        // No sense keeping the route around
        PktSetRoute( hPkt, 0 );

        // Give the packet to Rx
        IPRxPacket( hPkt );
        return( IPTX_SUCCESS );
    }

    // Make sure the egress interface is set
    hIFTx = RtGetIF( hRt );
    PktSetIFTx( hPkt, hIFTx );

IpRouteDone:
    if( !(Flags & FLG_IPTX_FORWARDING) )
        ips.dwLocalout++;
    else
    {
        // Bump Forwarding Stats and Check for redirects
        ips.dwForward++;

        if( hIFTx == hIFRx && hRt )
        {
            IPN IPTAddr, IPTMask;

            IPTAddr = RtGetIPAddr( hRt );
            IPTMask = RtGetIPMask( hRt );

            // A redirect is NOT sent in the following cases:
            //   - The packet was source routed
            //   - The Route was created or modifed by ICMP (DYNAMIC|MODIFIED)
            //   - The Route is the default route (IPMask != 0)
            //   - The sender is not a part of the next-hop subnet

            if( !(Flags&FLG_IPTX_SRCROUTE) &&
                !(w&(FLG_RTE_DYNAMIC|FLG_RTE_MODIFIED)) &&
                IPTMask!=0 && ((IPSrc&IPTMask)==IPTAddr) )
            {
                // We passed all the tests - we should generate an
                // ICMP redirect.
                ips.dwRedirectsent++;
                ICMPGenPacket( pIpHdr, hIFRx, ICMP_REDIRECT,
                               ICMP_REDIRECT_HOST, IPTAddr );
            }
        }
    }

    // Make sure the packet can fit out the egress device
    w     = IFGetMTU( hIFTx );
    Valid = HNC16(pIpHdr->TotalLen);
    if( w < Valid )
    {
        // Fragmentation required
        UINT16 off,hlen,size,offbase,offtmp;
        HANDLE hPkt2;
        IPHDR  *pIpHdr2;
        uint   Offset2;
        UINT8  *pb2;

        hlen = (pIpHdr->VerLen & 0xF) * 4;

        // If the DF flag is set, we're done
        if( pIpHdr->FlagOff & HNC16(IP_DF) )
            goto IpRouteCantFrag;

        // Record the offset base (we may be fragmenting a packet fragment
        // from a previous hop.
        offbase = HNC16(pIpHdr->FlagOff);

        // Get the payload bytes per frag amount
        w = (w - hlen) & ~7;
        if( w )
        {
            // Send out a bunch of fragmented packets
            for( off=0; off<(UINT16)Valid-hlen; off+=w )
            {
                // Get the payload size for this fragment
                size = w;
                if( (off+size) > ((UINT16)Valid-hlen) )
                    size = (UINT16)Valid - hlen - off;

                // Create the packet
                if( !(hPkt2 = IFCreatePacket( size, hlen, 0 )) )
                    goto IpRouteCantFrag;

                // Get the frag
                hFrag = PktGetFrag( hPkt2 );

                // Get pointers to packet headers
                pb2     = FragGetBufParams( hFrag, 0, 0, 0 );
                Offset2 = PktGetSizeLLC( hPkt2 );

                // Fixup packet frag info
                FragSetBufParams( hFrag, size+hlen, Offset2 );

                // Mark the IP packet as valid
                PktSetFlagsSet( hPkt2, FLG_PKT_IP_VALID );

                // Copy the IP header and data
                pIpHdr2 = (IPHDR *)(pb2 + Offset2 );
                mmCopy( pIpHdr2, pIpHdr, hlen );
                mmCopy( pb2+Offset2+hlen, pb+Offset+hlen+off, size );

                // Add this fragment offset to the base offset
                offtmp = offbase + (off>>3);

                // Set the MF bit as required (may already be set in offbase)
                if( (off+size) < ((UINT16)Valid-hlen) )
                    offtmp |= IP_MF;

                // Set the offset
                pIpHdr2->FlagOff = HNC16(offtmp);

                // Set the total length
                pIpHdr2->TotalLen = HNC16( (size+hlen) );

                // Perform Checksum
                IPChecksum( pIpHdr2 );

                // Set Ethertype
                PktSetEthType( hPkt2, 0x800 );

                // Set Destination Info
                PktSetIFTx( hPkt2, hIFTx );
                PktSetRoute( hPkt2, (PktGetRoute( hPkt )) );
                PktSetLLADst( hPkt2, (PktGetLLADst( hPkt )) );

                ips.dwOfragments++;

                // Send the packet
#ifdef _INCLUDE_PPP_CODE
                if( IFGetType( hIFTx ) == HTYPE_PPP )
                    pppTxIpPacket( hPkt2 );
                else
#endif
                    LLITxIpPacket( hPkt2 );
            }

            ips.dwFragmented++;
            PktFree( hPkt );
            return( IPTX_SUCCESS );
        }

IpRouteCantFrag:
        ips.dwCantfrag++;
        ICMPGenPacket(pIpHdr,hIFRx,ICMP_UNREACH,ICMP_UNREACH_NEEDFRAG,0);
        PktFree( hPkt );
        return( IPTX_ERROR_MSGSIZE );
    }

    // Send the packet
#ifdef _INCLUDE_PPP_CODE
    if( IFGetType( hIFTx ) == HTYPE_PPP )
        pppTxIpPacket( hPkt );
    else
#endif
        LLITxIpPacket( hPkt );

    return( IPTX_SUCCESS );
}


⌨️ 快捷键说明

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