]> git.gir.st - tmk_keyboard.git/blob - protocol/lufa/LUFA-git/Demos/Device/LowLevel/RNDISEthernet/Lib/RNDIS.c
Squashed 'tmk_core/' changes from d5c5ac6..8da1898
[tmk_keyboard.git] / protocol / lufa / LUFA-git / Demos / Device / LowLevel / RNDISEthernet / Lib / RNDIS.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2014.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * RNDIS command handler functions. This handles RNDIS commands according to
34 * the Microsoft RNDIS specification, creating a USB Ethernet network adapter.
35 */
36
37 #define INCLUDE_FROM_RNDIS_C
38 #include "RNDIS.h"
39
40 /** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */
41 static const MAC_Address_t PROGMEM AdapterMACAddress = {ADAPTER_MAC_ADDRESS};
42
43 /** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for
44 * the device, but may still be used by the OS in some circumstances.
45 */
46 static const char PROGMEM AdapterVendorDescription[] = "LUFA RNDIS Adapter";
47
48 /** List of RNDIS OID commands supported by this adapter. */
49 static const uint32_t PROGMEM AdapterSupportedOIDList[] =
50 {
51 OID_GEN_SUPPORTED_LIST,
52 OID_GEN_PHYSICAL_MEDIUM,
53 OID_GEN_HARDWARE_STATUS,
54 OID_GEN_MEDIA_SUPPORTED,
55 OID_GEN_MEDIA_IN_USE,
56 OID_GEN_MAXIMUM_FRAME_SIZE,
57 OID_GEN_MAXIMUM_TOTAL_SIZE,
58 OID_GEN_LINK_SPEED,
59 OID_GEN_TRANSMIT_BLOCK_SIZE,
60 OID_GEN_RECEIVE_BLOCK_SIZE,
61 OID_GEN_VENDOR_ID,
62 OID_GEN_VENDOR_DESCRIPTION,
63 OID_GEN_CURRENT_PACKET_FILTER,
64 OID_GEN_MAXIMUM_TOTAL_SIZE,
65 OID_GEN_MEDIA_CONNECT_STATUS,
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_802_3_PERMANENT_ADDRESS,
72 OID_802_3_CURRENT_ADDRESS,
73 OID_802_3_MULTICAST_LIST,
74 OID_802_3_MAXIMUM_LIST_SIZE,
75 OID_802_3_RCV_ERROR_ALIGNMENT,
76 OID_802_3_XMIT_ONE_COLLISION,
77 OID_802_3_XMIT_MORE_COLLISIONS,
78 };
79
80 /** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire
81 * Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this
82 * reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses.
83 */
84 uint8_t RNDISMessageBuffer[sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_Query_Complete_t)];
85
86 /** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */
87 RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISMessageBuffer;
88
89 /** Indicates if a RNDIS message response is ready to be sent back to the host. */
90 bool ResponseReady = false;
91
92 /** Current RNDIS adapter state, a value from the \c RNDIS_States_t enum. */
93 uint8_t CurrRNDISState = RNDIS_Uninitialized;
94
95 /** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */
96 uint32_t CurrPacketFilter = 0;
97
98
99 /** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is
100 * created, the ResponseReady global is updated so that the response is written back to the host upon request.
101 */
102 void ProcessRNDISControlMessage(void)
103 {
104 /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
105 this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
106
107 switch (MessageHeader->MessageType)
108 {
109 case REMOTE_NDIS_INITIALIZE_MSG:
110 /* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */
111
112 ResponseReady = true;
113
114 RNDIS_Initialize_Message_t* INITIALIZE_Message = (RNDIS_Initialize_Message_t*)&RNDISMessageBuffer;
115 RNDIS_Initialize_Complete_t* INITIALIZE_Response = (RNDIS_Initialize_Complete_t*)&RNDISMessageBuffer;
116
117 INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
118 INITIALIZE_Response->MessageLength = sizeof(RNDIS_Initialize_Complete_t);
119 INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
120 INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
121
122 INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
123 INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
124 INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
125 INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
126 INITIALIZE_Response->MaxPacketsPerTransfer = 1;
127 INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_Packet_Message_t) + ETHERNET_FRAME_SIZE_MAX);
128 INITIALIZE_Response->PacketAlignmentFactor = 0;
129 INITIALIZE_Response->AFListOffset = 0;
130 INITIALIZE_Response->AFListSize = 0;
131
132 CurrRNDISState = RNDIS_Initialized;
133
134 break;
135 case REMOTE_NDIS_HALT_MSG:
136 /* Halt the adapter, reset the adapter state - note that no response should be returned when completed */
137
138 ResponseReady = false;
139 MessageHeader->MessageLength = 0;
140
141 CurrRNDISState = RNDIS_Uninitialized;
142
143 break;
144 case REMOTE_NDIS_QUERY_MSG:
145 /* Request for information about a parameter about the adapter, specified as an OID token */
146
147 ResponseReady = true;
148
149 RNDIS_Query_Message_t* QUERY_Message = (RNDIS_Query_Message_t*)&RNDISMessageBuffer;
150 RNDIS_Query_Complete_t* QUERY_Response = (RNDIS_Query_Complete_t*)&RNDISMessageBuffer;
151 uint32_t Query_Oid = QUERY_Message->Oid;
152
153 void* QueryData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
154 QUERY_Message->InformationBufferOffset];
155 void* ResponseData = &RNDISMessageBuffer[sizeof(RNDIS_Query_Complete_t)];
156 uint16_t ResponseSize;
157
158 QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
159 QUERY_Response->MessageLength = sizeof(RNDIS_Query_Complete_t);
160
161 if (ProcessNDISQuery(Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
162 ResponseData, &ResponseSize))
163 {
164 QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
165 QUERY_Response->MessageLength += ResponseSize;
166
167 QUERY_Response->InformationBufferLength = ResponseSize;
168 QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_Query_Complete_t) - sizeof(RNDIS_Message_Header_t));
169 }
170 else
171 {
172 QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
173
174 QUERY_Response->InformationBufferLength = 0;
175 QUERY_Response->InformationBufferOffset = 0;
176 }
177
178 break;
179 case REMOTE_NDIS_SET_MSG:
180 /* Request to set a parameter of the adapter, specified as an OID token */
181
182 ResponseReady = true;
183
184 RNDIS_Set_Message_t* SET_Message = (RNDIS_Set_Message_t*)&RNDISMessageBuffer;
185 RNDIS_Set_Complete_t* SET_Response = (RNDIS_Set_Complete_t*)&RNDISMessageBuffer;
186 uint32_t SET_Oid = SET_Message->Oid;
187
188 SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
189 SET_Response->MessageLength = sizeof(RNDIS_Set_Complete_t);
190 SET_Response->RequestId = SET_Message->RequestId;
191
192 void* SetData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
193 SET_Message->InformationBufferOffset];
194
195 if (ProcessNDISSet(SET_Oid, SetData, SET_Message->InformationBufferLength))
196 SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
197 else
198 SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
199
200 break;
201 case REMOTE_NDIS_RESET_MSG:
202 /* Soft reset the adapter */
203
204 ResponseReady = true;
205
206 RNDIS_Reset_Complete_t* RESET_Response = (RNDIS_Reset_Complete_t*)&RNDISMessageBuffer;
207
208 RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
209 RESET_Response->MessageLength = sizeof(RNDIS_Reset_Complete_t);
210 RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
211 RESET_Response->AddressingReset = 0;
212
213 break;
214 case REMOTE_NDIS_KEEPALIVE_MSG:
215 /* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */
216
217 ResponseReady = true;
218
219 RNDIS_KeepAlive_Message_t* KEEPALIVE_Message = (RNDIS_KeepAlive_Message_t*)&RNDISMessageBuffer;
220 RNDIS_KeepAlive_Complete_t* KEEPALIVE_Response = (RNDIS_KeepAlive_Complete_t*)&RNDISMessageBuffer;
221
222 KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
223 KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KeepAlive_Complete_t);
224 KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
225 KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
226
227 break;
228 }
229 }
230
231 /** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested
232 * parameter is given as an OID value.
233 *
234 * \param[in] OId OId value of the parameter being queried
235 * \param[in] QueryData Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer
236 * \param[in] QuerySize Size in bytes of the extra query data being sent by the host
237 * \param[out] ResponseData Pointer to the start of the query response inside the RNDIS message buffer
238 * \param[out] ResponseSize Pointer to the size in bytes of the response data being sent to the host
239 *
240 * \return Boolean \c true if the query was handled, \c false otherwise
241 */
242 static bool ProcessNDISQuery(const uint32_t OId, void* QueryData, uint16_t QuerySize,
243 void* ResponseData, uint16_t* ResponseSize)
244 {
245 /* Handler for REMOTE_NDIS_QUERY_MSG messages */
246
247 switch (OId)
248 {
249 case OID_GEN_SUPPORTED_LIST:
250 *ResponseSize = sizeof(AdapterSupportedOIDList);
251
252 /* Copy the list of supported NDIS OID tokens to the response buffer */
253 memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
254
255 return true;
256 case OID_GEN_PHYSICAL_MEDIUM:
257 *ResponseSize = sizeof(uint32_t);
258
259 /* Indicate that the device is a true ethernet link */
260 *((uint32_t*)ResponseData) = 0;
261
262 return true;
263 case OID_GEN_HARDWARE_STATUS:
264 *ResponseSize = sizeof(uint32_t);
265
266 /* Always indicate hardware ready */
267 *((uint32_t*)ResponseData) = NDIS_HardwareStatus_Ready;
268
269 return true;
270 case OID_GEN_MEDIA_SUPPORTED:
271 case OID_GEN_MEDIA_IN_USE:
272 *ResponseSize = sizeof(uint32_t);
273
274 /* Indicate 802.3 (Ethernet) supported by the adapter */
275 *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
276
277 return true;
278 case OID_GEN_VENDOR_ID:
279 *ResponseSize = sizeof(uint32_t);
280
281 /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
282 *((uint32_t*)ResponseData) = 0x00FFFFFF;
283
284 return true;
285 case OID_GEN_MAXIMUM_FRAME_SIZE:
286 case OID_GEN_TRANSMIT_BLOCK_SIZE:
287 case OID_GEN_RECEIVE_BLOCK_SIZE:
288 *ResponseSize = sizeof(uint32_t);
289
290 /* Indicate that the maximum frame size is the size of the ethernet frame buffer */
291 *((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
292
293 return true;
294 case OID_GEN_VENDOR_DESCRIPTION:
295 *ResponseSize = sizeof(AdapterVendorDescription);
296
297 /* Copy vendor description string to the response buffer */
298 memcpy_P(ResponseData, AdapterVendorDescription, sizeof(AdapterVendorDescription));
299
300 return true;
301 case OID_GEN_MEDIA_CONNECT_STATUS:
302 *ResponseSize = sizeof(uint32_t);
303
304 /* Always indicate that the adapter is connected to a network */
305 *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
306
307 return true;
308 case OID_GEN_LINK_SPEED:
309 *ResponseSize = sizeof(uint32_t);
310
311 /* Indicate 10Mb/s link speed */
312 *((uint32_t*)ResponseData) = 100000;
313
314 return true;
315 case OID_802_3_PERMANENT_ADDRESS:
316 case OID_802_3_CURRENT_ADDRESS:
317 *ResponseSize = sizeof(MAC_Address_t);
318
319 /* Copy over the fixed adapter MAC to the response buffer */
320 memcpy_P(ResponseData, &AdapterMACAddress, sizeof(MAC_Address_t));
321
322 return true;
323 case OID_802_3_MAXIMUM_LIST_SIZE:
324 *ResponseSize = sizeof(uint32_t);
325
326 /* Indicate only one multicast address supported */
327 *((uint32_t*)ResponseData) = 1;
328
329 return true;
330 case OID_GEN_CURRENT_PACKET_FILTER:
331 *ResponseSize = sizeof(uint32_t);
332
333 /* Indicate the current packet filter mask */
334 *((uint32_t*)ResponseData) = CurrPacketFilter;
335
336 return true;
337 case OID_GEN_XMIT_OK:
338 case OID_GEN_RCV_OK:
339 case OID_GEN_XMIT_ERROR:
340 case OID_GEN_RCV_ERROR:
341 case OID_GEN_RCV_NO_BUFFER:
342 case OID_802_3_RCV_ERROR_ALIGNMENT:
343 case OID_802_3_XMIT_ONE_COLLISION:
344 case OID_802_3_XMIT_MORE_COLLISIONS:
345 *ResponseSize = sizeof(uint32_t);
346
347 /* Unused statistic OIDs - always return 0 for each */
348 *((uint32_t*)ResponseData) = 0;
349
350 return true;
351 case OID_GEN_MAXIMUM_TOTAL_SIZE:
352 *ResponseSize = sizeof(uint32_t);
353
354 /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
355 *((uint32_t*)ResponseData) = (sizeof(RNDISMessageBuffer) + ETHERNET_FRAME_SIZE_MAX);
356
357 return true;
358 default:
359 return false;
360 }
361 }
362
363 /** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given
364 * as an OID value.
365 *
366 * \param[in] OId OId value of the parameter being set
367 * \param[in] SetData Pointer to the parameter value in the RNDIS message buffer
368 * \param[in] SetSize Size in bytes of the parameter value being sent by the host
369 *
370 * \return Boolean \c true if the set was handled, \c false otherwise
371 */
372 static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize)
373 {
374 /* Handler for REMOTE_NDIS_SET_MSG messages */
375
376 switch (OId)
377 {
378 case OID_GEN_CURRENT_PACKET_FILTER:
379 /* Save the packet filter mask in case the host queries it again later */
380 CurrPacketFilter = *((uint32_t*)SetData);
381
382 /* Set the RNDIS state to initialized if the packet filter is non-zero */
383 CurrRNDISState = ((CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_Data_Initialized);
384
385 return true;
386 case OID_802_3_MULTICAST_LIST:
387 /* Do nothing - throw away the value from the host as it is unused */
388
389 return true;
390 default:
391 return false;
392 }
393 }
394
Imprint / Impressum