07c95ebb8a75690874493fe1760b1a1698f6e86a
[reactos.git] / reactos / drivers / network / dd / pcnet / requests.c
1 /*
2 * ReactOS AMD PCNet Driver
3 *
4 * Copyright (C) 2000 Casper Hornstroup <chorns@users.sourceforge.net>
5 * Copyright (C) 2003 Vizzini <vizzini@plasmic.com>
6 * Copyright (C) 2004 Filip Navara <navaraf@reactos.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * PROGRAMMERS:
23 * Vizzini (vizzini@plasmic.com),
24 * borrowed very heavily from the ReactOS ne2000 driver by
25 * Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISIONS:
27 * 14-Sep-2003 vizzini - Created
28 * 17-Oct-2004 navaraf - Add multicast support.
29 * - Add media state detection support.
30 * - Protect the adapter context with spinlock
31 * and move code talking to card to inside
32 * NdisMSynchronizeWithInterrupt calls where
33 * necessary.
34 */
35
36 #include "pcnet.h"
37
38 #define NDEBUG
39 #include <debug.h>
40
41 /* List of supported OIDs */
42 static ULONG MiniportOIDList[] =
43 {
44 OID_GEN_SUPPORTED_LIST,
45 OID_GEN_HARDWARE_STATUS,
46 OID_GEN_MEDIA_SUPPORTED,
47 OID_GEN_MEDIA_IN_USE,
48 OID_GEN_MAXIMUM_LOOKAHEAD,
49 OID_GEN_MAXIMUM_FRAME_SIZE,
50 OID_GEN_LINK_SPEED,
51 OID_GEN_TRANSMIT_BUFFER_SPACE,
52 OID_GEN_RECEIVE_BUFFER_SPACE,
53 OID_GEN_TRANSMIT_BLOCK_SIZE,
54 OID_GEN_RECEIVE_BLOCK_SIZE,
55 OID_GEN_VENDOR_ID,
56 OID_GEN_VENDOR_DESCRIPTION,
57 OID_GEN_VENDOR_DRIVER_VERSION,
58 OID_GEN_CURRENT_PACKET_FILTER,
59 OID_GEN_CURRENT_LOOKAHEAD,
60 OID_GEN_DRIVER_VERSION,
61 OID_GEN_MAXIMUM_TOTAL_SIZE,
62 OID_GEN_PROTOCOL_OPTIONS,
63 OID_GEN_MAC_OPTIONS,
64 OID_GEN_MEDIA_CONNECT_STATUS,
65 OID_GEN_MAXIMUM_SEND_PACKETS,
66 OID_GEN_XMIT_OK,
67 OID_GEN_RCV_OK,
68 OID_GEN_XMIT_ERROR,
69 OID_GEN_RCV_ERROR,
70 OID_GEN_RCV_NO_BUFFER,
71 OID_GEN_RCV_CRC_ERROR,
72 OID_802_3_PERMANENT_ADDRESS,
73 OID_802_3_CURRENT_ADDRESS,
74 OID_802_3_MULTICAST_LIST,
75 OID_802_3_MAXIMUM_LIST_SIZE,
76 OID_802_3_MAC_OPTIONS,
77 OID_802_3_RCV_ERROR_ALIGNMENT,
78 OID_802_3_XMIT_ONE_COLLISION,
79 OID_802_3_XMIT_MORE_COLLISIONS
80 };
81
82 \f
83 NDIS_STATUS
84 NTAPI
85 MiniportQueryInformation(
86 IN NDIS_HANDLE MiniportAdapterContext,
87 IN NDIS_OID Oid,
88 IN PVOID InformationBuffer,
89 IN ULONG InformationBufferLength,
90 OUT PULONG BytesWritten,
91 OUT PULONG BytesNeeded)
92 /*
93 * FUNCTION: Query an OID from the driver
94 * ARGUMENTS:
95 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
96 * Oid: OID NDIS is querying
97 * InformationBuffer: pointer to buffer into which to write the results of the query
98 * InformationBufferLength: size in bytes of InformationBuffer
99 * BytesWritten: number of bytes written into InformationBuffer in response to the query
100 * BytesNeeded: number of bytes needed to answer the query
101 * RETURNS:
102 * NDIS_STATUS_SUCCESS on all queries
103 * NOTES:
104 * - Called by NDIS at DISPATCH_LEVEL
105 * - If InformationBufferLength is insufficient to store the results, return the amount
106 * needed in BytesNeeded and return NDIS_STATUS_INVALID_LENGTH
107 * TODO:
108 * - Update to verify input buffer & size and return insufficient buffer codes
109 */
110 {
111 NDIS_STATUS Status;
112 PVOID CopyFrom;
113 UINT CopySize;
114 ULONG GenericULONG;
115 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
116
117 DPRINT("Called. OID 0x%x\n", Oid);
118
119 ASSERT(Adapter);
120
121 NdisAcquireSpinLock(&Adapter->Lock);
122
123 Status = NDIS_STATUS_SUCCESS;
124 CopyFrom = (PVOID)&GenericULONG;
125 CopySize = sizeof(ULONG);
126
127 switch (Oid)
128 {
129 case OID_GEN_SUPPORTED_LIST:
130 {
131 CopyFrom = (PVOID)&MiniportOIDList;
132 CopySize = sizeof(MiniportOIDList);
133 break;
134 }
135
136 case OID_GEN_HARDWARE_STATUS:
137 {
138 GenericULONG = (ULONG)NdisHardwareStatusReady;
139 break;
140 }
141
142 case OID_GEN_MEDIA_SUPPORTED:
143 case OID_GEN_MEDIA_IN_USE:
144 {
145 static const NDIS_MEDIUM Medium = NdisMedium802_3;
146 CopyFrom = (PVOID)&Medium;
147 CopySize = sizeof(NDIS_MEDIUM);
148 break;
149 }
150
151 case OID_GEN_CURRENT_LOOKAHEAD:
152 case OID_GEN_MAXIMUM_LOOKAHEAD:
153 {
154 GenericULONG = 1500;
155 break;
156 }
157
158 case OID_GEN_MAXIMUM_FRAME_SIZE:
159 {
160 /*
161 * The value returned by this OID must be equal to
162 * OID_GEN_MAXIMUM_TOTAL_SIZE - sizeof(ETHERNET_HEADER)
163 * where sizeof(ETHERNET_HEADER) is 14.
164 */
165 GenericULONG = 1500;
166 break;
167 }
168
169 case OID_GEN_LINK_SPEED:
170 {
171 GenericULONG = Adapter->MediaSpeed * 10000;
172 break;
173 }
174
175 case OID_GEN_TRANSMIT_BUFFER_SPACE:
176 {
177 /* XXX fix me */
178 GenericULONG = BUFFER_SIZE;
179 break;
180 }
181
182 case OID_GEN_RECEIVE_BUFFER_SPACE:
183 {
184 /* XXX fix me */
185 GenericULONG = BUFFER_SIZE;
186 break;
187 }
188
189 case OID_GEN_TRANSMIT_BLOCK_SIZE:
190 {
191 GenericULONG = BUFFER_SIZE;
192 break;
193 }
194
195 case OID_GEN_RECEIVE_BLOCK_SIZE:
196 {
197 GenericULONG = BUFFER_SIZE;
198 break;
199 }
200
201 case OID_GEN_VENDOR_ID:
202 {
203 UCHAR *CharPtr = (UCHAR *)&GenericULONG;
204 GenericULONG = 0;
205 /* Read the first three bytes of the permanent MAC address */
206 NdisRawReadPortUchar(Adapter->PortOffset, CharPtr);
207 NdisRawReadPortUchar(Adapter->PortOffset + 1, CharPtr + 1);
208 NdisRawReadPortUchar(Adapter->PortOffset + 2, CharPtr + 2);
209 break;
210 }
211
212 case OID_GEN_VENDOR_DESCRIPTION:
213 {
214 static UCHAR VendorDesc[] = "ReactOS Team";
215 CopyFrom = VendorDesc;
216 CopySize = sizeof(VendorDesc);
217 break;
218 }
219
220 case OID_GEN_VENDOR_DRIVER_VERSION:
221 {
222 /* XXX implement me */
223 GenericULONG = 1;
224 break;
225 }
226
227 case OID_GEN_CURRENT_PACKET_FILTER:
228 {
229 GenericULONG = Adapter->CurrentPacketFilter;
230 break;
231 }
232
233 case OID_GEN_DRIVER_VERSION:
234 {
235 /* NDIS version used by the driver. */
236 static const USHORT DriverVersion =
237 (NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION;
238 CopyFrom = (PVOID)&DriverVersion;
239 CopySize = sizeof(DriverVersion);
240 break;
241 }
242
243 case OID_GEN_MAXIMUM_TOTAL_SIZE:
244 {
245 /* See comment in OID_GEN_MAXIMUM_FRAME_SIZE. */
246 GenericULONG = 1514;
247 break;
248 }
249
250 case OID_GEN_PROTOCOL_OPTIONS:
251 {
252 DPRINT("OID_GEN_PROTOCOL_OPTIONS.\n");
253 Status = NDIS_STATUS_NOT_SUPPORTED;
254 break;
255 }
256
257 case OID_GEN_MAC_OPTIONS:
258 {
259 GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
260 NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
261 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
262 NDIS_MAC_OPTION_NO_LOOPBACK;
263 break;
264 }
265
266 case OID_GEN_MEDIA_CONNECT_STATUS:
267 {
268 GenericULONG = (ULONG)NdisMediaStateConnected; /* Adapter->MediaState */
269 break;
270 }
271
272 case OID_GEN_MAXIMUM_SEND_PACKETS:
273 {
274 GenericULONG = 1;
275 break;
276 }
277
278 case OID_802_3_CURRENT_ADDRESS:
279 case OID_802_3_PERMANENT_ADDRESS:
280 {
281 CopyFrom = (PVOID)&Adapter->InitializationBlockVirt->PADR;
282 CopySize = 6;
283 break;
284 }
285
286 case OID_802_3_MAXIMUM_LIST_SIZE:
287 {
288 GenericULONG = MAX_MULTICAST_ADDRESSES;
289 break;
290 }
291
292 case OID_GEN_XMIT_OK:
293 GenericULONG = Adapter->Statistics.XmtGoodFrames;
294 break;
295
296 case OID_GEN_RCV_OK:
297 GenericULONG = Adapter->Statistics.RcvGoodFrames;
298 break;
299
300 case OID_GEN_XMIT_ERROR:
301 GenericULONG = Adapter->Statistics.XmtRetryErrors +
302 Adapter->Statistics.XmtLossesOfCarrier +
303 Adapter->Statistics.XmtCollisions +
304 Adapter->Statistics.XmtLateCollisions +
305 Adapter->Statistics.XmtExcessiveDefferals +
306 Adapter->Statistics.XmtBufferUnderflows +
307 Adapter->Statistics.XmtBufferErrors;
308 break;
309
310 case OID_GEN_RCV_ERROR:
311 GenericULONG = Adapter->Statistics.RcvBufferErrors +
312 Adapter->Statistics.RcvCrcErrors +
313 Adapter->Statistics.RcvOverflowErrors +
314 Adapter->Statistics.RcvFramingErrors;
315 break;
316
317 case OID_GEN_RCV_NO_BUFFER:
318 GenericULONG = Adapter->Statistics.RcvBufferErrors +
319 Adapter->Statistics.RcvOverflowErrors;
320 break;
321
322 case OID_GEN_RCV_CRC_ERROR:
323 GenericULONG = Adapter->Statistics.RcvCrcErrors;
324 break;
325
326 case OID_802_3_RCV_ERROR_ALIGNMENT:
327 GenericULONG = Adapter->Statistics.RcvFramingErrors;
328 break;
329
330 case OID_802_3_XMIT_ONE_COLLISION:
331 GenericULONG = Adapter->Statistics.XmtOneRetry;
332 break;
333
334 case OID_802_3_XMIT_MORE_COLLISIONS:
335 GenericULONG = Adapter->Statistics.XmtMoreThanOneRetry;
336 break;
337
338 default:
339 {
340 DPRINT1("Unknown OID\n");
341 Status = NDIS_STATUS_NOT_SUPPORTED;
342 break;
343 }
344 }
345
346 if (Status == NDIS_STATUS_SUCCESS)
347 {
348 if (CopySize > InformationBufferLength)
349 {
350 *BytesNeeded = CopySize;
351 *BytesWritten = 0;
352 Status = NDIS_STATUS_INVALID_LENGTH;
353 }
354 else
355 {
356 NdisMoveMemory(InformationBuffer, CopyFrom, CopySize);
357 *BytesWritten = CopySize;
358 *BytesNeeded = CopySize;
359 }
360 }
361 else
362 {
363 *BytesWritten = 0;
364 *BytesNeeded = 0;
365 }
366
367 NdisReleaseSpinLock(&Adapter->Lock);
368
369 DPRINT("Leaving. Status is 0x%x\n", Status);
370
371 return Status;
372 }
373
374 NDIS_STATUS
375 NTAPI
376 MiniportSetInformation(
377 IN NDIS_HANDLE MiniportAdapterContext,
378 IN NDIS_OID Oid,
379 IN PVOID InformationBuffer,
380 IN ULONG InformationBufferLength,
381 OUT PULONG BytesRead,
382 OUT PULONG BytesNeeded)
383 /*
384 * FUNCTION: Set a miniport variable (OID)
385 * ARGUMENTS:
386 * MiniportAdapterContext: context originally passed into NdisMSetAttributes
387 * Oid: the variable being set
388 * InformationBuffer: the data to set the variable to
389 * InformationBufferLength: number of bytes in InformationBuffer
390 * BytesRead: number of bytes read by us out of the buffer
391 * BytesNeeded: number of bytes required to satisfy the request if InformationBufferLength
392 * is insufficient
393 * RETURNS:
394 * NDIS_STATUS_SUCCESS on all requests
395 * NOTES:
396 * - Called by NDIS at DISPATCH_LEVEL
397 * - verify buffer space as mentioned in previous function notes
398 */
399 {
400 ULONG GenericULONG;
401 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
402 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
403
404 ASSERT(Adapter);
405
406 DPRINT("Called, OID 0x%x\n", Oid);
407
408 NdisAcquireSpinLock(&Adapter->Lock);
409
410 switch (Oid)
411 {
412 case OID_GEN_CURRENT_PACKET_FILTER:
413 {
414 /* Verify length */
415 if (InformationBufferLength < sizeof(ULONG))
416 {
417 *BytesRead = 0;
418 *BytesNeeded = sizeof(ULONG);
419 Status = NDIS_STATUS_INVALID_LENGTH;
420 break;
421 }
422
423 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
424
425 /* Check for properties the driver don't support */
426 if (GenericULONG &
427 (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
428 NDIS_PACKET_TYPE_FUNCTIONAL |
429 NDIS_PACKET_TYPE_GROUP |
430 NDIS_PACKET_TYPE_MAC_FRAME |
431 NDIS_PACKET_TYPE_SMT |
432 NDIS_PACKET_TYPE_SOURCE_ROUTING)
433 )
434 {
435 *BytesRead = sizeof(ULONG);
436 *BytesNeeded = 0;
437 Status = NDIS_STATUS_NOT_SUPPORTED;
438 break;
439 }
440
441 Adapter->CurrentPacketFilter = GenericULONG;
442
443 /* FIXME: Set filter on hardware */
444
445 break;
446 }
447
448 case OID_GEN_CURRENT_LOOKAHEAD:
449 {
450 /* Verify length */
451 if (InformationBufferLength < sizeof(ULONG))
452 {
453 *BytesRead = 0;
454 *BytesNeeded = sizeof(ULONG);
455 Status = NDIS_STATUS_INVALID_LENGTH;
456 break;
457 }
458
459 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
460
461 if (GenericULONG > 1500)
462 Status = NDIS_STATUS_INVALID_DATA;
463 else
464 Adapter->CurrentLookaheadSize = GenericULONG;
465
466 break;
467 }
468
469 case OID_802_3_MULTICAST_LIST:
470 {
471 /* Verify length. Must be multiple of hardware address length */
472 if ((InformationBufferLength % 6) != 0)
473 {
474 *BytesRead = 0;
475 *BytesNeeded = InformationBufferLength + (InformationBufferLength % 6);
476 Status = NDIS_STATUS_INVALID_LENGTH;
477 break;
478 }
479
480 ASSERT((InformationBufferLength / 6) <= MAX_MULTICAST_ADDRESSES);
481
482 /* Set new multicast address list */
483 //NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength);
484
485 /* Update hardware */
486 Status = MiSetMulticast(Adapter, InformationBuffer, InformationBufferLength / 6);
487
488 break;
489 }
490
491 default:
492 {
493 DPRINT1("Invalid object ID (0x%X).\n", Oid);
494 *BytesRead = 0;
495 *BytesNeeded = 0;
496 Status = NDIS_STATUS_NOT_SUPPORTED;
497 break;
498 }
499 }
500
501 if (Status == NDIS_STATUS_SUCCESS)
502 {
503 *BytesRead = InformationBufferLength;
504 *BytesNeeded = 0;
505 }
506
507 NdisReleaseSpinLock(&Adapter->Lock);
508
509 DPRINT("Leaving. Status (0x%X).\n", Status);
510
511 return Status;
512 }
513