📄 ipout.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 + -