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