Merge from amd64 branch:
[reactos.git] / reactos / drivers / network / tcpip / tcpip / info.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/info.c
5 * PURPOSE: TDI query and set information routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12 #include <debug.h>
13 #include <route.h>
14
15 TDI_STATUS InfoCopyOut( PCHAR DataOut, UINT SizeOut,
16 PNDIS_BUFFER ClientBuf, PUINT ClientBufSize ) {
17 UINT RememberedCBSize = *ClientBufSize;
18 *ClientBufSize = SizeOut;
19
20 /* The driver returns success even when it couldn't fit every available
21 * byte. */
22 if( RememberedCBSize < SizeOut || !ClientBuf )
23 return TDI_SUCCESS;
24 else {
25 CopyBufferToBufferChain( ClientBuf, 0, (PCHAR)DataOut, SizeOut );
26 return TDI_SUCCESS;
27 }
28 }
29
30 VOID InsertTDIInterfaceEntity( PIP_INTERFACE Interface ) {
31 KIRQL OldIrql;
32 UINT Count = 0, i;
33
34 TI_DbgPrint(DEBUG_INFO,
35 ("Inserting interface %08x (%d entities already)\n",
36 Interface, EntityCount));
37
38 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
39
40 /* Count IP Entities */
41 for( i = 0; i < EntityCount; i++ )
42 if( EntityList[i].tei_entity == IF_ENTITY ) {
43 Count++;
44 TI_DbgPrint(DEBUG_INFO, ("Entity %d is an IF. Found %d\n",
45 i, Count));
46 }
47
48 EntityList[EntityCount].tei_entity = IF_ENTITY;
49 EntityList[EntityCount].tei_instance = Count;
50 EntityList[EntityCount].context = Interface;
51 EntityList[EntityCount].info_req = InfoInterfaceTdiQueryEx;
52 EntityList[EntityCount].info_set = InfoInterfaceTdiSetEx;
53
54 EntityCount++;
55
56 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
57 }
58
59 VOID RemoveTDIInterfaceEntity( PIP_INTERFACE Interface ) {
60 KIRQL OldIrql;
61 UINT i;
62
63 TI_DbgPrint(DEBUG_INFO,("Removing TDI entry 0x%x\n", Interface));
64
65 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
66
67 /* Remove entities that have this interface as context
68 * In the future, this might include AT_ENTITY types, too
69 */
70 for( i = 0; i < EntityCount; i++ ) {
71 TI_DbgPrint(DEBUG_INFO,("--> examining TDI entry 0x%x\n", EntityList[i].context));
72 if( EntityList[i].context == Interface ) {
73 if( i != EntityCount-1 ) {
74 memcpy( &EntityList[i],
75 &EntityList[--EntityCount],
76 sizeof(EntityList[i]) );
77 } else {
78 EntityCount--;
79 }
80 }
81 }
82
83 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
84 }
85
86 TDI_STATUS InfoTdiQueryListEntities(PNDIS_BUFFER Buffer,
87 PUINT BufferSize)
88 {
89 UINT Count, Size, BufSize = *BufferSize;
90 KIRQL OldIrql;
91
92 TI_DbgPrint(DEBUG_INFO,("About to copy %d TDIEntityIDs to user\n",
93 EntityCount));
94
95 TcpipAcquireSpinLock(&EntityListLock, &OldIrql);
96
97 Size = EntityCount * sizeof(TDIEntityID);
98 *BufferSize = Size;
99
100 TI_DbgPrint(DEBUG_INFO,("BufSize: %d, NeededSize: %d\n", BufSize, Size));
101
102 if (BufSize < Size || !Buffer)
103 {
104 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
105 /* The buffer is too small to contain requested data, but we return
106 * success anyway, as we did everything we wanted. */
107 return TDI_SUCCESS;
108 }
109
110 /* Return entity list -- Copy only the TDIEntityID parts. */
111 for( Count = 0; Count < EntityCount; Count++ ) {
112 CopyBufferToBufferChain(Buffer,
113 Count * sizeof(TDIEntityID),
114 (PCHAR)&EntityList[Count],
115 sizeof(TDIEntityID));
116 }
117
118 TcpipReleaseSpinLock(&EntityListLock, OldIrql);
119
120 return TDI_SUCCESS;
121 }
122
123 TDI_STATUS InfoTdiQueryInformationEx(
124 PTDI_REQUEST Request,
125 TDIObjectID *ID,
126 PNDIS_BUFFER Buffer,
127 PUINT BufferSize,
128 PVOID Context)
129 /*
130 * FUNCTION: Returns extended information
131 * ARGUMENTS:
132 * Request = Pointer to TDI request structure for the request
133 * ID = TDI object ID
134 * Buffer = Pointer to buffer with data to use
135 * BufferSize = Pointer to buffer with size of Buffer. On return
136 * this is filled with number of bytes returned
137 * Context = Pointer to context buffer
138 * RETURNS:
139 * Status of operation
140 */
141 {
142 KIRQL OldIrql;
143 UINT i;
144 PVOID context = NULL;
145 NTSTATUS Status = TDI_INVALID_PARAMETER;
146 BOOLEAN FoundEntity = FALSE;
147 InfoRequest_f InfoRequest = NULL;
148
149 TI_DbgPrint(DEBUG_INFO,
150 ("InfoEx Req: %x %x %x!%04x:%d\n",
151 ID->toi_class,
152 ID->toi_type,
153 ID->toi_id,
154 ID->toi_entity.tei_entity,
155 ID->toi_entity.tei_instance));
156
157 /* Check wether it is a query for a list of entities */
158 if (ID->toi_entity.tei_entity == GENERIC_ENTITY)
159 {
160 if ((ID->toi_class != INFO_CLASS_GENERIC) ||
161 (ID->toi_type != INFO_TYPE_PROVIDER) ||
162 (ID->toi_id != ENTITY_LIST_ID)) {
163 TI_DbgPrint(DEBUG_INFO,("Invalid parameter\n"));
164 Status = TDI_INVALID_PARAMETER;
165 } else
166 Status = InfoTdiQueryListEntities(Buffer, BufferSize);
167 } else if (ID->toi_entity.tei_entity == AT_ENTITY) {
168 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
169
170 for( i = 0; i < EntityCount; i++ ) {
171 if( EntityList[i].tei_entity == IF_ENTITY &&
172 EntityList[i].tei_instance == ID->toi_entity.tei_instance ) {
173 InfoRequest = EntityList[i].info_req;
174 context = EntityList[i].context;
175 FoundEntity = TRUE;
176 break;
177 }
178 }
179
180 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
181
182 if( FoundEntity ) {
183 TI_DbgPrint(DEBUG_INFO,
184 ("Calling AT Entity %d (%04x:%d) InfoEx (%x,%x,%x)\n",
185 i, ID->toi_entity.tei_entity,
186 ID->toi_entity.tei_instance,
187 ID->toi_class, ID->toi_type, ID->toi_id));
188 Status = InfoRequest( ID->toi_class,
189 ID->toi_type,
190 ID->toi_id,
191 context,
192 &ID->toi_entity,
193 Buffer,
194 BufferSize );
195 }
196 } else {
197 TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
198
199 for( i = 0; i < EntityCount; i++ ) {
200 if( EntityList[i].tei_entity == ID->toi_entity.tei_entity &&
201 EntityList[i].tei_instance == ID->toi_entity.tei_instance ) {
202 InfoRequest = EntityList[i].info_req;
203 context = EntityList[i].context;
204 FoundEntity = TRUE;
205 break;
206 }
207 }
208
209 TcpipReleaseSpinLock( &EntityListLock, OldIrql );
210
211 if( FoundEntity ) {
212 TI_DbgPrint(DEBUG_INFO,
213 ("Calling Entity %d (%04x:%d) InfoEx (%x,%x,%x)\n",
214 i, ID->toi_entity.tei_entity,
215 ID->toi_entity.tei_instance,
216 ID->toi_class, ID->toi_type, ID->toi_id));
217 Status = InfoRequest( ID->toi_class,
218 ID->toi_type,
219 ID->toi_id,
220 context,
221 &ID->toi_entity,
222 Buffer,
223 BufferSize );
224 }
225 }
226
227 TI_DbgPrint(DEBUG_INFO,("Status: %08x\n", Status));
228
229 return Status;
230 }
231
232 TDI_STATUS InfoTdiSetInformationEx
233 (PTDI_REQUEST Request,
234 TDIObjectID *ID,
235 PVOID Buffer,
236 UINT BufferSize)
237 /*
238 * FUNCTION: Sets extended information
239 * ARGUMENTS:
240 * Request = Pointer to TDI request structure for the request
241 * ID = Pointer to TDI object ID
242 * Buffer = Pointer to buffer with data to use
243 * BufferSize = Size of Buffer
244 * RETURNS:
245 * Status of operation
246 */
247 {
248 switch( ID->toi_class ) {
249 case INFO_CLASS_PROTOCOL:
250 switch( ID->toi_type ) {
251 case INFO_TYPE_PROVIDER:
252 switch( ID->toi_id ) {
253 case IP_MIB_ROUTETABLE_ENTRY_ID:
254 return InfoNetworkLayerTdiSetEx
255 ( ID->toi_class,
256 ID->toi_type,
257 ID->toi_id,
258 NULL,
259 &ID->toi_entity,
260 Buffer,
261 BufferSize );
262 }
263 }
264 break;
265 }
266
267 return TDI_INVALID_PARAMETER;
268 }