/src/tinyusb/lib/networking/rndis_reports.c
Line | Count | Source |
1 | | /* |
2 | | The original version of this code was lrndis/usbd_rndis_core.c from https://github.com/fetisov/lrndis |
3 | | It has since been overhauled to suit this application |
4 | | */ |
5 | | |
6 | | /* |
7 | | * The MIT License (MIT) |
8 | | * |
9 | | * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com> |
10 | | * |
11 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | | * of this software and associated documentation files (the "Software"), to deal |
13 | | * in the Software without restriction, including without limitation the rights |
14 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
15 | | * copies of the Software, and to permit persons to whom the Software is |
16 | | * furnished to do so, subject to the following conditions: |
17 | | * |
18 | | * The above copyright notice and this permission notice shall be included in all |
19 | | * copies or substantial portions of the Software. |
20 | | * |
21 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
22 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
24 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
26 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
27 | | * SOFTWARE. |
28 | | */ |
29 | | |
30 | | #include <stdalign.h> |
31 | | #include <string.h> |
32 | | #include "tusb.h" |
33 | | |
34 | | #if CFG_TUD_ECM_RNDIS |
35 | | |
36 | | #include "rndis_protocol.h" |
37 | | #include "netif/ethernet.h" |
38 | | |
39 | 0 | #define RNDIS_LINK_SPEED 12000000 /* Link baudrate (12Mbit/s for USB-FS) */ |
40 | | #define RNDIS_VENDOR "TinyUSB" /* NIC vendor name */ |
41 | | |
42 | | static const uint8_t *const station_hwaddr = tud_network_mac_address; |
43 | | static const uint8_t *const permanent_hwaddr = tud_network_mac_address; |
44 | | |
45 | | static usb_eth_stat_t usb_eth_stat = { 0, 0, 0, 0 }; |
46 | | static uint32_t oid_packet_filter = 0x0000000; |
47 | | TU_ATTR_UNUSED static rndis_state_t rndis_state; |
48 | | |
49 | | static const uint32_t OIDSupportedList[] = |
50 | | { |
51 | | OID_GEN_SUPPORTED_LIST, |
52 | | OID_GEN_HARDWARE_STATUS, |
53 | | OID_GEN_MEDIA_SUPPORTED, |
54 | | OID_GEN_MEDIA_IN_USE, |
55 | | OID_GEN_MAXIMUM_FRAME_SIZE, |
56 | | OID_GEN_LINK_SPEED, |
57 | | OID_GEN_TRANSMIT_BLOCK_SIZE, |
58 | | OID_GEN_RECEIVE_BLOCK_SIZE, |
59 | | OID_GEN_VENDOR_ID, |
60 | | OID_GEN_VENDOR_DESCRIPTION, |
61 | | OID_GEN_VENDOR_DRIVER_VERSION, |
62 | | OID_GEN_CURRENT_PACKET_FILTER, |
63 | | OID_GEN_MAXIMUM_TOTAL_SIZE, |
64 | | OID_GEN_PROTOCOL_OPTIONS, |
65 | | OID_GEN_MAC_OPTIONS, |
66 | | OID_GEN_MEDIA_CONNECT_STATUS, |
67 | | OID_GEN_MAXIMUM_SEND_PACKETS, |
68 | | OID_802_3_PERMANENT_ADDRESS, |
69 | | OID_802_3_CURRENT_ADDRESS, |
70 | | OID_802_3_MULTICAST_LIST, |
71 | | OID_802_3_MAXIMUM_LIST_SIZE, |
72 | | OID_802_3_MAC_OPTIONS |
73 | | }; |
74 | | |
75 | 0 | #define OID_LIST_LENGTH TU_ARRAY_SIZE(OIDSupportedList) |
76 | | #define ENC_BUF_SIZE (OID_LIST_LENGTH * 4 + 32) |
77 | | |
78 | | static void *encapsulated_buffer; |
79 | | |
80 | 0 | static void rndis_report(void) { |
81 | 0 | uint8_t ndis_report[8] = { 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; |
82 | 0 | netd_report(ndis_report, sizeof(ndis_report)); |
83 | 0 | } |
84 | | |
85 | | static void rndis_query_cmplt32(int status, uint32_t data) |
86 | 0 | { |
87 | 0 | rndis_query_cmplt_t *c; |
88 | 0 | c = (rndis_query_cmplt_t *)encapsulated_buffer; |
89 | 0 | c->MessageType = REMOTE_NDIS_QUERY_CMPLT; |
90 | 0 | c->MessageLength = sizeof(rndis_query_cmplt_t) + 4; |
91 | 0 | c->InformationBufferLength = 4; |
92 | 0 | c->InformationBufferOffset = 16; |
93 | 0 | c->Status = status; |
94 | 0 | memcpy(c + 1, &data, sizeof(data)); |
95 | 0 | rndis_report(); |
96 | 0 | } |
97 | | |
98 | | static void rndis_query_cmplt(int status, const void *data, int size) |
99 | 0 | { |
100 | 0 | rndis_query_cmplt_t *c; |
101 | 0 | c = (rndis_query_cmplt_t *)encapsulated_buffer; |
102 | 0 | c->MessageType = REMOTE_NDIS_QUERY_CMPLT; |
103 | 0 | c->MessageLength = sizeof(rndis_query_cmplt_t) + size; |
104 | 0 | c->InformationBufferLength = size; |
105 | 0 | c->InformationBufferOffset = 16; |
106 | 0 | c->Status = status; |
107 | 0 | memcpy(c + 1, data, size); |
108 | 0 | rndis_report(); |
109 | 0 | } |
110 | | |
111 | | #define MAC_OPT NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ |
112 | | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | \ |
113 | | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ |
114 | | NDIS_MAC_OPTION_NO_LOOPBACK |
115 | | |
116 | | static const char *rndis_vendor = RNDIS_VENDOR; |
117 | | |
118 | | static void rndis_query(void) |
119 | 0 | { |
120 | 0 | switch (((rndis_query_msg_t *)encapsulated_buffer)->Oid) |
121 | 0 | { |
122 | 0 | case OID_GEN_SUPPORTED_LIST: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, OIDSupportedList, 4 * OID_LIST_LENGTH); return; |
123 | 0 | case OID_GEN_VENDOR_DRIVER_VERSION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00001000); return; |
124 | 0 | case OID_802_3_CURRENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, station_hwaddr, 6); return; |
125 | 0 | case OID_802_3_PERMANENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, permanent_hwaddr, 6); return; |
126 | 0 | case OID_GEN_MEDIA_SUPPORTED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
127 | 0 | case OID_GEN_MEDIA_IN_USE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
128 | 0 | case OID_GEN_PHYSICAL_MEDIUM: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
129 | 0 | case OID_GEN_HARDWARE_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
130 | 0 | case OID_GEN_LINK_SPEED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, RNDIS_LINK_SPEED / 100); return; |
131 | 0 | case OID_GEN_VENDOR_ID: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00FFFFFF); return; |
132 | 0 | case OID_GEN_VENDOR_DESCRIPTION: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, rndis_vendor, strlen(rndis_vendor) + 1); return; |
133 | 0 | case OID_GEN_CURRENT_PACKET_FILTER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, oid_packet_filter); return; |
134 | 0 | case OID_GEN_MAXIMUM_FRAME_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU - SIZEOF_ETH_HDR); return; |
135 | 0 | case OID_GEN_MAXIMUM_TOTAL_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
136 | 0 | case OID_GEN_TRANSMIT_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
137 | 0 | case OID_GEN_RECEIVE_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
138 | 0 | case OID_GEN_MEDIA_CONNECT_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIA_STATE_CONNECTED); return; |
139 | 0 | case OID_GEN_RNDIS_CONFIG_PARAMETER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
140 | 0 | case OID_802_3_MAXIMUM_LIST_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 1); return; |
141 | 0 | case OID_802_3_MULTICAST_LIST: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; |
142 | 0 | case OID_802_3_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; |
143 | 0 | case OID_GEN_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, /*MAC_OPT*/ 0); return; |
144 | 0 | case OID_802_3_RCV_ERROR_ALIGNMENT: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
145 | 0 | case OID_802_3_XMIT_ONE_COLLISION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
146 | 0 | case OID_802_3_XMIT_MORE_COLLISIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
147 | 0 | case OID_GEN_XMIT_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txok); return; |
148 | 0 | case OID_GEN_RCV_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxok); return; |
149 | 0 | case OID_GEN_RCV_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxbad); return; |
150 | 0 | case OID_GEN_XMIT_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txbad); return; |
151 | 0 | case OID_GEN_RCV_NO_BUFFER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
152 | 0 | default: rndis_query_cmplt(RNDIS_STATUS_FAILURE, NULL, 0); return; |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | 0 | #define INFBUF ((uint8_t *)&(m->RequestId) + m->InformationBufferOffset) |
157 | | |
158 | | static void rndis_handle_config_parm(const char *data, int keyoffset, int valoffset, int keylen, int vallen) |
159 | 0 | { |
160 | 0 | (void)data; |
161 | 0 | (void)keyoffset; |
162 | 0 | (void)valoffset; |
163 | 0 | (void)keylen; |
164 | 0 | (void)vallen; |
165 | 0 | } |
166 | | |
167 | | static void rndis_packetFilter(uint32_t newfilter) |
168 | 0 | { |
169 | 0 | (void)newfilter; |
170 | 0 | } |
171 | | |
172 | | static void rndis_handle_set_msg(void) |
173 | 0 | { |
174 | 0 | rndis_set_cmplt_t *c; |
175 | 0 | rndis_set_msg_t *m; |
176 | 0 | rndis_Oid_t oid; |
177 | |
|
178 | 0 | c = (rndis_set_cmplt_t *)encapsulated_buffer; |
179 | 0 | m = (rndis_set_msg_t *)encapsulated_buffer; |
180 | |
|
181 | 0 | oid = m->Oid; |
182 | 0 | c->MessageType = REMOTE_NDIS_SET_CMPLT; |
183 | 0 | c->MessageLength = sizeof(rndis_set_cmplt_t); |
184 | 0 | c->Status = RNDIS_STATUS_SUCCESS; |
185 | |
|
186 | 0 | switch (oid) |
187 | 0 | { |
188 | | /* Parameters set up in 'Advanced' tab */ |
189 | 0 | case OID_GEN_RNDIS_CONFIG_PARAMETER: |
190 | 0 | { |
191 | 0 | rndis_config_parameter_t *p; |
192 | 0 | char *ptr = (char *)m; |
193 | 0 | ptr += sizeof(rndis_generic_msg_t); |
194 | 0 | ptr += m->InformationBufferOffset; |
195 | 0 | p = (rndis_config_parameter_t *) ((void*) ptr); |
196 | 0 | rndis_handle_config_parm(ptr, p->ParameterNameOffset, p->ParameterValueOffset, p->ParameterNameLength, p->ParameterValueLength); |
197 | 0 | } |
198 | 0 | break; |
199 | | |
200 | | /* Mandatory general OIDs */ |
201 | 0 | case OID_GEN_CURRENT_PACKET_FILTER: |
202 | 0 | memcpy(&oid_packet_filter, INFBUF, 4); |
203 | 0 | if (oid_packet_filter) |
204 | 0 | { |
205 | 0 | rndis_packetFilter(oid_packet_filter); |
206 | 0 | rndis_state = rndis_data_initialized; |
207 | 0 | } |
208 | 0 | else |
209 | 0 | { |
210 | 0 | rndis_state = rndis_initialized; |
211 | 0 | } |
212 | 0 | break; |
213 | | |
214 | 0 | case OID_GEN_CURRENT_LOOKAHEAD: |
215 | 0 | break; |
216 | | |
217 | 0 | case OID_GEN_PROTOCOL_OPTIONS: |
218 | 0 | break; |
219 | | |
220 | | /* Mandatory 802_3 OIDs */ |
221 | 0 | case OID_802_3_MULTICAST_LIST: |
222 | 0 | break; |
223 | | |
224 | | /* Power Management: fails for now */ |
225 | 0 | case OID_PNP_ADD_WAKE_UP_PATTERN: |
226 | 0 | case OID_PNP_REMOVE_WAKE_UP_PATTERN: |
227 | 0 | case OID_PNP_ENABLE_WAKE_UP: |
228 | 0 | default: |
229 | 0 | c->Status = RNDIS_STATUS_FAILURE; |
230 | 0 | break; |
231 | 0 | } |
232 | | |
233 | | /* c->MessageID is same as before */ |
234 | 0 | rndis_report(); |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | | void rndis_class_set_handler(uint8_t *data, int size) |
239 | 0 | { |
240 | 0 | encapsulated_buffer = data; |
241 | 0 | (void)size; |
242 | |
|
243 | 0 | switch (((rndis_generic_msg_t *)encapsulated_buffer)->MessageType) |
244 | 0 | { |
245 | 0 | case REMOTE_NDIS_INITIALIZE_MSG: |
246 | 0 | { |
247 | 0 | rndis_initialize_cmplt_t *m; |
248 | 0 | m = ((rndis_initialize_cmplt_t *)encapsulated_buffer); |
249 | | /* m->MessageID is same as before */ |
250 | 0 | m->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; |
251 | 0 | m->MessageLength = sizeof(rndis_initialize_cmplt_t); |
252 | 0 | m->MajorVersion = RNDIS_MAJOR_VERSION; |
253 | 0 | m->MinorVersion = RNDIS_MINOR_VERSION; |
254 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
255 | 0 | m->DeviceFlags = RNDIS_DF_CONNECTIONLESS; |
256 | 0 | m->Medium = RNDIS_MEDIUM_802_3; |
257 | 0 | m->MaxPacketsPerTransfer = 1; |
258 | 0 | m->MaxTransferSize = CFG_TUD_NET_MTU + sizeof(rndis_data_packet_t); |
259 | 0 | m->PacketAlignmentFactor = 0; |
260 | 0 | m->AfListOffset = 0; |
261 | 0 | m->AfListSize = 0; |
262 | 0 | rndis_state = rndis_initialized; |
263 | 0 | rndis_report(); |
264 | 0 | } |
265 | 0 | break; |
266 | | |
267 | 0 | case REMOTE_NDIS_QUERY_MSG: |
268 | 0 | rndis_query(); |
269 | 0 | break; |
270 | | |
271 | 0 | case REMOTE_NDIS_SET_MSG: |
272 | 0 | rndis_handle_set_msg(); |
273 | 0 | break; |
274 | | |
275 | 0 | case REMOTE_NDIS_RESET_MSG: |
276 | 0 | { |
277 | 0 | rndis_reset_cmplt_t * m; |
278 | 0 | m = ((rndis_reset_cmplt_t *)encapsulated_buffer); |
279 | 0 | rndis_state = rndis_uninitialized; |
280 | 0 | m->MessageType = REMOTE_NDIS_RESET_CMPLT; |
281 | 0 | m->MessageLength = sizeof(rndis_reset_cmplt_t); |
282 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
283 | 0 | m->AddressingReset = 1; /* Make it look like we did something */ |
284 | | /* m->AddressingReset = 0; - Windows halts if set to 1 for some reason */ |
285 | 0 | rndis_report(); |
286 | 0 | } |
287 | 0 | break; |
288 | | |
289 | 0 | case REMOTE_NDIS_KEEPALIVE_MSG: |
290 | 0 | { |
291 | 0 | rndis_keepalive_cmplt_t * m; |
292 | 0 | m = (rndis_keepalive_cmplt_t *)encapsulated_buffer; |
293 | 0 | m->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; |
294 | 0 | m->MessageLength = sizeof(rndis_keepalive_cmplt_t); |
295 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
296 | 0 | } |
297 | | /* We have data to send back */ |
298 | 0 | rndis_report(); |
299 | 0 | break; |
300 | | |
301 | 0 | default: |
302 | 0 | break; |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | | #endif |