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