Merge trunk head (r43756)
[reactos.git] / reactos / drivers / network / tcpip / tcpip / iinfo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/iinfo.c
5 * PURPOSE: Per-interface information.
6 * PROGRAMMERS: Art Yerkes
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 TDI_STATUS InfoTdiQueryGetInterfaceMIB(TDIEntityID ID,
14 PIP_INTERFACE Interface,
15 PNDIS_BUFFER Buffer,
16 PUINT BufferSize) {
17 TDI_STATUS Status = TDI_INVALID_REQUEST;
18 PIFENTRY OutData;
19 PLAN_ADAPTER IF;
20 PCHAR IFDescr;
21 ULONG Size;
22 UINT DescrLenMax = MAX_IFDESCR_LEN - 1;
23 NDIS_STATUS NdisStatus;
24
25 if (!Interface)
26 return TDI_INVALID_PARAMETER;
27
28 IF = (PLAN_ADAPTER)Interface->Context;
29
30 TI_DbgPrint(DEBUG_INFO,
31 ("Getting IFEntry MIB (IF %08x LA %08x) (%04x:%d)\n",
32 Interface, IF, ID.tei_entity, ID.tei_instance));
33
34 OutData =
35 (PIFENTRY)exAllocatePool( NonPagedPool,
36 sizeof(IFENTRY) + MAX_IFDESCR_LEN );
37
38 if( !OutData ) return TDI_NO_RESOURCES; /* Out of memory */
39
40 RtlZeroMemory( OutData, sizeof(IFENTRY) + MAX_IFDESCR_LEN );
41
42 OutData->Index = Interface->Index;
43 /* viz: tcpip keeps those indices */
44 OutData->Type = Interface ==
45 Loopback ? MIB_IF_TYPE_LOOPBACK : MIB_IF_TYPE_ETHERNET;
46 OutData->Mtu = Interface->MTU;
47 TI_DbgPrint(DEBUG_INFO,
48 ("Getting interface speed\n"));
49 OutData->PhysAddrLen = Interface->AddressLength;
50 OutData->AdminStatus = MIB_IF_ADMIN_STATUS_UP;
51 /* NDIS_HARDWARE_STATUS -> ROUTER_CONNECTION_STATE */
52 Status = GetInterfaceConnectionStatus( Interface, &OutData->OperStatus );
53
54 /* Not sure what to do here, but not ready seems a safe bet on failure */
55 if( !NT_SUCCESS(Status) )
56 OutData->OperStatus = NdisHardwareStatusNotReady;
57
58 IFDescr = (PCHAR)&OutData[1];
59
60 if( IF ) {
61 GetInterfaceSpeed( Interface, (PUINT)&OutData->Speed );
62 TI_DbgPrint(DEBUG_INFO,
63 ("IF Speed = %d * 100bps\n", OutData->Speed));
64 memcpy(OutData->PhysAddr,Interface->Address,Interface->AddressLength);
65 TI_DbgPrint(DEBUG_INFO, ("Got HWAddr\n"));
66
67 memcpy(&OutData->InOctets, &Interface->Stats, sizeof(SEND_RECV_STATS));
68
69 NdisStatus = NDISCall(IF,
70 NdisRequestQueryInformation,
71 OID_GEN_XMIT_ERROR,
72 &OutData->OutErrors,
73 sizeof(ULONG));
74 if (NdisStatus != NDIS_STATUS_SUCCESS)
75 OutData->OutErrors = 0;
76
77 TI_DbgPrint(DEBUG_INFO, ("OutErrors = %d\n", OutData->OutErrors));
78
79 NdisStatus = NDISCall(IF,
80 NdisRequestQueryInformation,
81 OID_GEN_RCV_ERROR,
82 &OutData->InErrors,
83 sizeof(ULONG));
84 if (NdisStatus != NDIS_STATUS_SUCCESS)
85 OutData->InErrors = 0;
86
87 TI_DbgPrint(DEBUG_INFO, ("InErrors = %d\n", OutData->InErrors));
88 }
89
90 GetInterfaceName( Interface, IFDescr, MAX_IFDESCR_LEN - 1 );
91 DescrLenMax = strlen( IFDescr ) + 1;
92
93 TI_DbgPrint(DEBUG_INFO, ("Copied in name %s\n", IFDescr));
94 OutData->DescrLen = DescrLenMax;
95 IFDescr += DescrLenMax;
96 Size = IFDescr - (PCHAR)OutData + 1;
97
98 TI_DbgPrint(DEBUG_INFO, ("Finished IFEntry MIB (%04x:%d) size %d\n",
99 ID.tei_entity, ID.tei_instance, Size));
100
101 Status = InfoCopyOut( (PCHAR)OutData, Size, Buffer, BufferSize );
102 exFreePool( OutData );
103
104 TI_DbgPrint(DEBUG_INFO,("Returning %x\n", Status));
105
106 return Status;
107 }
108
109 TDI_STATUS InfoTdiQueryGetArptableMIB(TDIEntityID ID,
110 PIP_INTERFACE Interface,
111 PNDIS_BUFFER Buffer,
112 PUINT BufferSize) {
113 NTSTATUS Status;
114 ULONG NumNeighbors = NBCopyNeighbors( Interface, NULL );
115 ULONG MemSize = NumNeighbors * sizeof(IPARP_ENTRY);
116 PIPARP_ENTRY ArpEntries;
117
118 if (MemSize != 0)
119 {
120 ArpEntries = exAllocatePoolWithTag( NonPagedPool, MemSize, FOURCC('A','R','P','t') );
121 if( !ArpEntries ) return STATUS_NO_MEMORY;
122
123 NBCopyNeighbors( Interface, ArpEntries );
124
125 Status = InfoCopyOut( (PVOID)ArpEntries, MemSize, Buffer, BufferSize );
126
127 exFreePool( ArpEntries );
128 }
129 else
130 {
131 Status = InfoCopyOut(NULL, 0, NULL, BufferSize);
132 }
133
134 return Status;
135 }
136
137 TDI_STATUS InfoTdiSetArptableMIB(PIP_INTERFACE IF, PVOID Buffer, UINT BufferSize)
138 {
139 PIPARP_ENTRY ArpEntry = Buffer;
140 IP_ADDRESS Address;
141 PNEIGHBOR_CACHE_ENTRY NCE;
142
143 if (!Buffer || BufferSize < sizeof(IPARP_ENTRY))
144 return TDI_INVALID_PARAMETER;
145
146 AddrInitIPv4(&Address, ArpEntry->LogAddr);
147
148 if ((NCE = NBLocateNeighbor(&Address)))
149 NBRemoveNeighbor(NCE);
150
151 if (NBAddNeighbor(IF,
152 &Address,
153 ArpEntry->PhysAddr,
154 ArpEntry->AddrSize,
155 NUD_PERMANENT,
156 0))
157 return TDI_SUCCESS;
158 else
159 return TDI_INVALID_PARAMETER;
160 }
161
162 VOID InsertTDIInterfaceEntity( PIP_INTERFACE Interface ) {
163 KIRQL OldIrql;
164 UINT IFCount = 0, CLNLCount = 0, CLTLCount = 0, COTLCount = 0, ATCount = 0, ERCount = 0, i;
165
166 TI_DbgPrint(DEBUG_INFO,
167 ("Inserting interface %08x (%d entities already)\n",
168 Interface, EntityCount));
169
170 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
171
172 /* Count IP Entities */
173 for( i = 0; i < EntityCount; i++ )
174 switch( EntityList[i].tei_entity )
175 {
176 case IF_ENTITY:
177 IFCount++;
178 break;
179
180 case CL_NL_ENTITY:
181 CLNLCount++;
182 break;
183
184 case CL_TL_ENTITY:
185 CLTLCount++;
186 break;
187
188 case CO_TL_ENTITY:
189 COTLCount++;
190 break;
191
192 case AT_ENTITY:
193 ATCount++;
194 break;
195
196 case ER_ENTITY:
197 ERCount++;
198 break;
199
200 default:
201 break;
202 }
203
204 EntityList[EntityCount].tei_entity = IF_ENTITY;
205 EntityList[EntityCount].tei_instance = IFCount;
206 EntityList[EntityCount].context = Interface;
207 EntityList[EntityCount].flags = IF_MIB;
208 EntityCount++;
209 EntityList[EntityCount].tei_entity = CL_NL_ENTITY;
210 EntityList[EntityCount].tei_instance = CLNLCount;
211 EntityList[EntityCount].context = Interface;
212 EntityList[EntityCount].flags = CL_NL_IP;
213 EntityCount++;
214 EntityList[EntityCount].tei_entity = CL_TL_ENTITY;
215 EntityList[EntityCount].tei_instance = CLTLCount;
216 EntityList[EntityCount].context = Interface;
217 EntityList[EntityCount].flags = CL_TL_UDP;
218 EntityCount++;
219 EntityList[EntityCount].tei_entity = CO_TL_ENTITY;
220 EntityList[EntityCount].tei_instance = COTLCount;
221 EntityList[EntityCount].context = Interface;
222 EntityList[EntityCount].flags = CO_TL_TCP;
223 EntityCount++;
224 EntityList[EntityCount].tei_entity = ER_ENTITY;
225 EntityList[EntityCount].tei_instance = ERCount;
226 EntityList[EntityCount].context = Interface;
227 EntityList[EntityCount].flags = ER_ICMP;
228 EntityCount++;
229 EntityList[EntityCount].tei_entity = AT_ENTITY;
230 EntityList[EntityCount].tei_instance = ATCount;
231 EntityList[EntityCount].context = Interface;
232 EntityList[EntityCount].flags = (Interface != Loopback) ? AT_ARP : AT_NULL;
233 EntityCount++;
234
235 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
236 }
237
238 VOID RemoveTDIInterfaceEntity( PIP_INTERFACE Interface ) {
239 KIRQL OldIrql;
240 UINT i;
241
242 TI_DbgPrint(DEBUG_INFO,("Removing TDI entry 0x%x\n", Interface));
243
244 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
245
246 /* Remove entities that have this interface as context
247 * In the future, this might include AT_ENTITY types, too
248 */
249 for( i = 0; i < EntityCount; i++ ) {
250 TI_DbgPrint(DEBUG_INFO,("--> examining TDI entry 0x%x\n", EntityList[i].context));
251 if( EntityList[i].context == Interface ) {
252 if( i != EntityCount-1 ) {
253 memcpy( &EntityList[i],
254 &EntityList[--EntityCount],
255 sizeof(EntityList[i]) );
256 } else {
257 EntityCount--;
258 }
259 }
260 }
261
262 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
263 }
264