summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/rip/route.c
blob: 82e44016e76b4e304254e131951ebdc7a8d6b7ec (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*******************************************************************/
/*	      Copyright(c)  1993 Microsoft Corporation		   */
/*******************************************************************/

//***
//
// Filename:	route.c
//
// Description: route packet routine
//
// Author:	Stefan Solomon (stefans)    October 11, 1993.
//
// Revision History:
//
//***

#include    "rtdefs.h"

//***
//
// Function:	RoutePacket
//
// Descr:	Routes this packet
//
// Params:	Packet
//
// Returns:	none
//
//***

VOID
RoutePacket(PPACKET_TAG     pktp)
{
    PUCHAR		hdrp;	 // points to the IPX packet header
    PUCHAR		destnet; // points to destination network
    UINT		segment; // routing table segment
    KIRQL		oldirql;
    PIPX_ROUTE_ENTRY	tabrtep;
    PNICCB		dstniccbp, srcniccbp;  // dest and src nic cb pointers

    // check if we know about the destination network
    hdrp = pktp->DataBufferp;
    destnet = hdrp + IPXH_DESTNET;

    segment = IpxGetSegment(destnet);

    ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql);

    if((tabrtep = IpxGetRoute(segment, destnet)) == NULL) {

	// no such route
	ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: route not found!\n"));
	FreeRcvPkt(pktp);
	return;
    }

    // check if the destination route is the Global Wan Route. If it is, then get the
    // nic id of the destination nic
    if(tabrtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {

	// sanity check
	ASSERT(tabrtep->NicId == 0xFFFE);
	ASSERT(WanGlobalNetworkEnabled);

	// get the destination nic id from the wan nodes hash table
	dstniccbp = GetWanNodeNiccbp(hdrp + IPXH_DESTNODE);

	// check if the nic hasn't been removed from the table (by RtLineDown)
	if(dstniccbp == NULL) {

	    ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	    FreeRcvPkt(pktp);
	    return;
	}
	else
	{
	    // extra sanity checks
	    ASSERT(dstniccbp->DeviceType == NdisMediumWan);
	    ASSERT(!dstniccbp->WanConnectionClient);
	}
    }
    else
    {
	dstniccbp = NicCbPtrTab[tabrtep->NicId];
    }

    // check if the destination route is reachable through another nic than
    // the nic we received the packet from.
    if(pktp->PacketOwnerNicCbp->NicId == dstniccbp->NicId) {

	// we can't send the packet back where it came from => discard it
	ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	FreeRcvPkt(pktp);
	return;
    }

    // if either the src or the dst of the packet is a WAN nic, there are
    // a series of checks to perform

    // get the source nic for this packet
    srcniccbp = NicCbPtrTab[pktp->PacketOwnerNicCbp->NicId];

    // 1. check if one of the two nics is WAN and the other is a LAN nic disabled
    //	  for WAN traffic
    if( ((dstniccbp->DeviceType == NdisMediumWan) &&
	 (srcniccbp->DeviceType != NdisMediumWan) &&
	 (srcniccbp->WanRoutingDisabled))	  ||

	((dstniccbp->DeviceType != NdisMediumWan) &&
	 (srcniccbp->DeviceType == NdisMediumWan) &&
	 (dstniccbp->WanRoutingDisabled)) ) {

	RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because WAN traffic disabled for this LAN\n"));
	ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	FreeRcvPkt(pktp);
	return;
    }

    // 2. check if one of the two nics is WAN and has a client role and
    //	  LAN-WAN-LAN traffic is disabled
    if(!LanWanLan) {

	if( ((dstniccbp->DeviceType == NdisMediumWan) &&
	     (dstniccbp->WanConnectionClient)) ||

	    ((srcniccbp->DeviceType == NdisMediumWan) &&
	     (srcniccbp->WanConnectionClient)) ) {

	    RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because WAN has client role\n"));
	    ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	    FreeRcvPkt(pktp);
	    return;
	}
    }

    // 3. If both source and destination NICs are LAN, check if LAN routing is
    //	  enabled.
    if((dstniccbp->DeviceType != NdisMediumWan) &&
       (srcniccbp->DeviceType != NdisMediumWan) &&
       (!EnableLanRouting)) {

	    RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because LAN routing disabled\n"));
	    ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
	    FreeRcvPkt(pktp);
	    return;
    }

    // general send preparation
    pktp->RemoteAddress.NicId = dstniccbp->NicId;

    //*** check if the network is directly connected ***

    if(tabrtep->Flags & IPX_ROUTER_LOCAL_NET) {

	// prepare the packet for a direct send to the destination node
	memcpy(&pktp->RemoteAddress.MacAddress,
	       hdrp + IPXH_DESTNODE,
	       IPX_NODE_LEN);
    }
    else
    {
	// prepare the packet to be sent to the next router in the path to
	// the destination node
	memcpy(&pktp->RemoteAddress.MacAddress,
	       tabrtep->NextRouter,
	       IPX_NODE_LEN);
    }

    ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);

    // increment the nr of hops in the packet
    *(hdrp + IPXH_XPORTCTL) += 1;

    // queue the packet at the sending nic and send it
    SendPacket(pktp);

    return;
}