177 lines
3.4 KiB
C
177 lines
3.4 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ipsend.c
|
|
|
|
Abstract:
|
|
|
|
IP datagram transmission related functions
|
|
|
|
Revision History:
|
|
|
|
05/22/2000 davidx
|
|
Created it.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
//
|
|
// Default type-of-service value for outgoing datagrams
|
|
//
|
|
BYTE cfgDefaultTos = 0;
|
|
|
|
//
|
|
// Default time-to-live value for outgoing datagrams
|
|
//
|
|
BYTE cfgDefaultTtl = 64;
|
|
|
|
//
|
|
// Identifier to be assigned to the next outgoing IP datagram
|
|
//
|
|
WORD IpNextDgramId;
|
|
|
|
|
|
NTSTATUS
|
|
IpSendPacket(
|
|
Packet* pkt,
|
|
IPADDR dstaddr,
|
|
IfInfo* ifp,
|
|
RTE** cachedRte
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send out an IP datagram to the specified destination address
|
|
|
|
Arguments:
|
|
|
|
pkt - Specifies the datagram to be sent
|
|
dstaddr - Specifies the destination address
|
|
ifp - Points to the outgoing interface, optional
|
|
cachedRte - Address of a cached route entry pointer
|
|
|
|
Return Value:
|
|
|
|
Status code
|
|
|
|
--*/
|
|
|
|
{
|
|
RTE* rte;
|
|
|
|
RUNS_AT_DISPATCH_LEVEL
|
|
|
|
// The IP header must be completely filled out
|
|
ASSERT(pkt->data == (BYTE*) GETPKTIPHDR(pkt));
|
|
|
|
// Find a route and cache it
|
|
if ((rte = *cachedRte) == NULL || IsRteOrphaned(rte)) {
|
|
// release the orphaned route entry
|
|
if (rte) { IpReleaseCachedRTE(rte); }
|
|
|
|
*cachedRte = rte = IpFindRTE(dstaddr, ifp);
|
|
if (!rte) {
|
|
XnetCompletePacket(pkt, NETERR_UNREACHABLE);
|
|
return NETERR_UNREACHABLE;
|
|
}
|
|
RteAddRef(rte);
|
|
}
|
|
|
|
pkt->nexthop = IsRteLocal(rte) ? dstaddr : rte->nexthop;
|
|
ifp = rte->ifp;
|
|
if (pkt->datalen > ifp->mtu) {
|
|
XnetCompletePacket(pkt, NETERR_MSGSIZE);
|
|
return NETERR_MSGSIZE;
|
|
}
|
|
|
|
//
|
|
// Queue up the packet for transmission
|
|
// We use a very crude priority mechanism here:
|
|
// - normal packets are added to the end of the queue
|
|
// - retransmitted packets are added to the front of the queue
|
|
//
|
|
if (pkt->pktflags & PKTFLAG_REXMIT) {
|
|
PktQInsertHead(&ifp->sendq, pkt);
|
|
} else {
|
|
PktQInsertTail(&ifp->sendq, pkt);
|
|
}
|
|
ifp->StartOutput(ifp);
|
|
|
|
return NETERR_OK;
|
|
}
|
|
|
|
|
|
VOID
|
|
IpSendPacketInternal(
|
|
Packet* pkt,
|
|
IPADDR srcaddr,
|
|
IPADDR dstaddr,
|
|
BYTE protocol,
|
|
IfInfo* ifp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send an IP datagram out on the specified interface.
|
|
This is called by internal clients such as ICMP and DHCP.
|
|
|
|
Arguments:
|
|
|
|
pkt - Specifies the datagram to be sent
|
|
srcaddr - Specifies the source address
|
|
dstaddr - Specifies the destination address
|
|
protocol - Specifies the protocol number
|
|
ifp - Points to the outgoing interface
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
Note:
|
|
|
|
We assume the pkt->iphdr field points to where the IP header starts.
|
|
|
|
--*/
|
|
|
|
{
|
|
RTE* rte = NULL;
|
|
IpHeader* iphdr;
|
|
UINT iphdrlen;
|
|
KIRQL irql;
|
|
|
|
//
|
|
// Fix up the IP header
|
|
//
|
|
iphdr = GETPKTIPHDR(pkt);
|
|
ASSERT((BYTE*) iphdr < pkt->data);
|
|
|
|
iphdrlen = pkt->data - (BYTE*) iphdr;
|
|
pkt->data -= iphdrlen;
|
|
pkt->datalen += iphdrlen;
|
|
|
|
FILL_IPHEADER(
|
|
iphdr,
|
|
iphdrlen,
|
|
cfgDefaultTos,
|
|
pkt->datalen,
|
|
0,
|
|
cfgDefaultTtl,
|
|
protocol,
|
|
srcaddr,
|
|
dstaddr);
|
|
|
|
irql = RaiseToDpc();
|
|
IpSendPacket(pkt, dstaddr, ifp, &rte);
|
|
if (rte) { IpReleaseCachedRTE(rte); }
|
|
LowerFromDpc(irql);
|
|
}
|
|
|