1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/interface.c
5 * PURPOSE: Convenient abstraction for getting and setting information
6 * in IP_INTERFACE.
7 * PROGRAMMERS: Art Yerkes
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 */
11
12 #include "precomp.h"
13
14 #include <ntifs.h>
15 #include <ipifcons.h>
16
17 ULONG NextDefaultAdapter = 0;
18
GetInterfaceIPv4Address(PIP_INTERFACE Interface,ULONG TargetType,PULONG Address)19 NTSTATUS GetInterfaceIPv4Address( PIP_INTERFACE Interface,
20 ULONG TargetType,
21 PULONG Address ) {
22 switch( TargetType ) {
23 case ADE_UNICAST:
24 *Address = Interface->Unicast.Address.IPv4Address;
25 break;
26
27 case ADE_ADDRMASK:
28 *Address = Interface->Netmask.Address.IPv4Address;
29 break;
30
31 case ADE_BROADCAST:
32 *Address = Interface->Broadcast.Address.IPv4Address;
33 break;
34
35 case ADE_POINTOPOINT:
36 *Address = Interface->PointToPoint.Address.IPv4Address;
37 break;
38
39 default:
40 return STATUS_UNSUCCESSFUL;
41 }
42
43 return STATUS_SUCCESS;
44 }
45
CountInterfaces()46 UINT CountInterfaces() {
47 ULONG Count = 0;
48 KIRQL OldIrql;
49 IF_LIST_ITER(CurrentIF);
50
51 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
52
53 ForEachInterface(CurrentIF) {
54 Count++;
55 } EndFor(CurrentIF);
56
57 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
58
59 return Count;
60 }
61
GetInterfaceSpeed(PIP_INTERFACE Interface,PUINT Speed)62 NTSTATUS GetInterfaceSpeed( PIP_INTERFACE Interface, PUINT Speed ) {
63 PLAN_ADAPTER IF = (PLAN_ADAPTER)Interface->Context;
64
65 *Speed = IF->Speed;
66
67 return STATUS_SUCCESS;
68 }
69
GetInterfaceName(PIP_INTERFACE Interface,PCHAR NameBuffer,UINT Len)70 NTSTATUS GetInterfaceName( PIP_INTERFACE Interface,
71 PCHAR NameBuffer,
72 UINT Len ) {
73 ULONG ResultSize = 0;
74 NTSTATUS Status =
75 RtlUnicodeToMultiByteN( NameBuffer,
76 Len,
77 &ResultSize,
78 Interface->Name.Buffer,
79 Interface->Name.Length );
80
81 if( NT_SUCCESS(Status) )
82 NameBuffer[ResultSize] = 0;
83 else
84 NameBuffer[0] = 0;
85
86 return Status;
87 }
88
AddrLocateInterface(PIP_ADDRESS MatchAddress)89 PIP_INTERFACE AddrLocateInterface(
90 PIP_ADDRESS MatchAddress)
91 {
92 KIRQL OldIrql;
93 PIP_INTERFACE RetIF = NULL;
94 IF_LIST_ITER(CurrentIF);
95
96 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
97
98 ForEachInterface(CurrentIF) {
99 if( AddrIsEqual( &CurrentIF->Unicast, MatchAddress ) ||
100 AddrIsEqual( &CurrentIF->Broadcast, MatchAddress ) ) {
101 RetIF = CurrentIF;
102 break;
103 }
104 } EndFor(CurrentIF);
105
106 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
107
108 return RetIF;
109 }
110
HasPrefix(PIP_ADDRESS Address,PIP_ADDRESS Prefix,UINT Length)111 BOOLEAN HasPrefix(
112 PIP_ADDRESS Address,
113 PIP_ADDRESS Prefix,
114 UINT Length)
115 /*
116 * FUNCTION: Determines wether an address has an given prefix
117 * ARGUMENTS:
118 * Address = Pointer to address to use
119 * Prefix = Pointer to prefix to check for
120 * Length = Length of prefix
121 * RETURNS:
122 * TRUE if the address has the prefix, FALSE if not
123 * NOTES:
124 * The two addresses must be of the same type
125 */
126 {
127 PUCHAR pAddress = (PUCHAR)&Address->Address;
128 PUCHAR pPrefix = (PUCHAR)&Prefix->Address;
129
130 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length));
131
132 #if 0
133 TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) Prefix (%s).\n",
134 A2S(Address), A2S(Prefix)));
135 #endif
136
137 /* Don't report matches for empty prefixes */
138 if (Length == 0) {
139 return FALSE;
140 }
141
142 /* Check that initial integral bytes match */
143 while (Length > 8) {
144 if (*pAddress++ != *pPrefix++)
145 return FALSE;
146 Length -= 8;
147 }
148
149 /* Check any remaining bits */
150 if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length))))
151 return FALSE;
152
153 return TRUE;
154 }
155
GetDefaultInterface(VOID)156 PIP_INTERFACE GetDefaultInterface(VOID)
157 {
158 KIRQL OldIrql;
159 ULONG Index = 0;
160 ULONG IfStatus;
161
162 IF_LIST_ITER(CurrentIF);
163
164 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
165 /* DHCP hack: Always return the adapter without an IP address */
166 ForEachInterface(CurrentIF) {
167 if (CurrentIF->Context && AddrIsUnspecified(&CurrentIF->Unicast)) {
168 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
169
170 GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
171 if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
172 return CurrentIF;
173 }
174
175 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
176 }
177 } EndFor(CurrentIF);
178
179 /* Try to continue from the next adapter */
180 ForEachInterface(CurrentIF) {
181 if (CurrentIF->Context && (Index++ == NextDefaultAdapter)) {
182 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
183
184 GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
185 if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
186 NextDefaultAdapter++;
187 return CurrentIF;
188 }
189
190 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
191 }
192 } EndFor(CurrentIF);
193
194 /* No luck, so we'll choose the first adapter this time */
195 Index = 0;
196 ForEachInterface(CurrentIF) {
197 if (CurrentIF->Context) {
198 Index++;
199 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
200
201 GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
202 if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
203 NextDefaultAdapter = Index;
204 return CurrentIF;
205 }
206
207 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
208 }
209 } EndFor(CurrentIF);
210
211 /* Even that didn't work, so we'll just go with loopback */
212 NextDefaultAdapter = 0;
213 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
214
215 /* There are no physical interfaces on the system
216 * so we must pick the loopback interface */
217
218 return Loopback;
219 }
220
FindOnLinkInterface(PIP_ADDRESS Address)221 PIP_INTERFACE FindOnLinkInterface(PIP_ADDRESS Address)
222 /*
223 * FUNCTION: Checks all on-link prefixes to find out if an address is on-link
224 * ARGUMENTS:
225 * Address = Pointer to address to check
226 * RETURNS:
227 * Pointer to interface if address is on-link, NULL if not
228 */
229 {
230 KIRQL OldIrql;
231 IF_LIST_ITER(CurrentIF);
232
233 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X)\n", Address));
234 TI_DbgPrint(DEBUG_ROUTER, ("Address (%s)\n", A2S(Address)));
235
236 if (AddrIsUnspecified(Address))
237 return GetDefaultInterface();
238
239 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
240
241 ForEachInterface(CurrentIF) {
242 if (HasPrefix(Address, &CurrentIF->Unicast,
243 AddrCountPrefixBits(&CurrentIF->Netmask))) {
244 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
245 return CurrentIF;
246 }
247 } EndFor(CurrentIF);
248
249 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
250
251 return NULL;
252 }
253
GetInterfaceConnectionStatus(PIP_INTERFACE Interface,PULONG Result)254 VOID GetInterfaceConnectionStatus(PIP_INTERFACE Interface, PULONG Result)
255 {
256 PLAN_ADAPTER Adapter = Interface->Context;
257
258 /* Loopback has no adapter context */
259 if (Adapter == NULL || Adapter->State == LAN_STATE_STARTED) {
260 *Result = MIB_IF_OPER_STATUS_OPERATIONAL;
261 }
262 else {
263 *Result = MIB_IF_OPER_STATUS_DISCONNECTED;
264 }
265 }
266