/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 | | #define RNDIS_VENDOR "TinyUSB" /* NIC vendor name */ |
40 | | |
41 | | // USB link speed in bits/sec, reflected to host via OID_GEN_LINK_SPEED. |
42 | 0 | static inline uint32_t rndis_link_speed_bps(void) { |
43 | 0 | return (tud_speed_get() == TUSB_SPEED_HIGH) ? 480000000U : 12000000U; |
44 | 0 | } |
45 | | |
46 | | static const uint8_t *const station_hwaddr = tud_network_mac_address; |
47 | | static const uint8_t *const permanent_hwaddr = tud_network_mac_address; |
48 | | |
49 | | static usb_eth_stat_t usb_eth_stat = { 0, 0, 0, 0 }; |
50 | | static uint32_t oid_packet_filter = 0x0000000; |
51 | | TU_ATTR_UNUSED static rndis_state_t rndis_state; |
52 | | |
53 | | static const uint32_t OIDSupportedList[] = |
54 | | { |
55 | | OID_GEN_SUPPORTED_LIST, |
56 | | OID_GEN_HARDWARE_STATUS, |
57 | | OID_GEN_MEDIA_SUPPORTED, |
58 | | OID_GEN_MEDIA_IN_USE, |
59 | | OID_GEN_MAXIMUM_FRAME_SIZE, |
60 | | OID_GEN_LINK_SPEED, |
61 | | OID_GEN_TRANSMIT_BLOCK_SIZE, |
62 | | OID_GEN_RECEIVE_BLOCK_SIZE, |
63 | | OID_GEN_VENDOR_ID, |
64 | | OID_GEN_VENDOR_DESCRIPTION, |
65 | | OID_GEN_VENDOR_DRIVER_VERSION, |
66 | | OID_GEN_CURRENT_PACKET_FILTER, |
67 | | OID_GEN_MAXIMUM_TOTAL_SIZE, |
68 | | OID_GEN_PROTOCOL_OPTIONS, |
69 | | OID_GEN_MAC_OPTIONS, |
70 | | OID_GEN_MEDIA_CONNECT_STATUS, |
71 | | OID_GEN_MAXIMUM_SEND_PACKETS, |
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 | | }; |
78 | | |
79 | 0 | #define OID_LIST_LENGTH TU_ARRAY_SIZE(OIDSupportedList) |
80 | | #define ENC_BUF_SIZE (OID_LIST_LENGTH * 4 + 32) |
81 | | |
82 | | static void *encapsulated_buffer; |
83 | | |
84 | 0 | static void rndis_report(void) { |
85 | 0 | uint8_t ndis_report[8] = { 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; |
86 | 0 | netd_report(ndis_report, sizeof(ndis_report)); |
87 | 0 | } |
88 | | |
89 | | static void rndis_query_cmplt32(int status, uint32_t data) |
90 | 0 | { |
91 | 0 | rndis_query_cmplt_t *c; |
92 | 0 | c = (rndis_query_cmplt_t *)encapsulated_buffer; |
93 | 0 | c->MessageType = REMOTE_NDIS_QUERY_CMPLT; |
94 | 0 | c->MessageLength = sizeof(rndis_query_cmplt_t) + 4; |
95 | 0 | c->InformationBufferLength = 4; |
96 | 0 | c->InformationBufferOffset = 16; |
97 | 0 | c->Status = status; |
98 | 0 | memcpy(c + 1, &data, sizeof(data)); |
99 | 0 | rndis_report(); |
100 | 0 | } |
101 | | |
102 | | static void rndis_query_cmplt(int status, const void *data, int size) |
103 | 0 | { |
104 | 0 | rndis_query_cmplt_t *c; |
105 | 0 | c = (rndis_query_cmplt_t *)encapsulated_buffer; |
106 | 0 | c->MessageType = REMOTE_NDIS_QUERY_CMPLT; |
107 | 0 | c->MessageLength = sizeof(rndis_query_cmplt_t) + size; |
108 | 0 | c->InformationBufferLength = size; |
109 | 0 | c->InformationBufferOffset = 16; |
110 | 0 | c->Status = status; |
111 | 0 | memcpy(c + 1, data, size); |
112 | 0 | rndis_report(); |
113 | 0 | } |
114 | | |
115 | | #define MAC_OPT NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ |
116 | | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | \ |
117 | | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ |
118 | | NDIS_MAC_OPTION_NO_LOOPBACK |
119 | | |
120 | | static const char *rndis_vendor = RNDIS_VENDOR; |
121 | | |
122 | | static void rndis_query(void) |
123 | 0 | { |
124 | 0 | switch (((rndis_query_msg_t *)encapsulated_buffer)->Oid) |
125 | 0 | { |
126 | 0 | case OID_GEN_SUPPORTED_LIST: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, OIDSupportedList, 4 * OID_LIST_LENGTH); return; |
127 | 0 | case OID_GEN_VENDOR_DRIVER_VERSION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00001000); return; |
128 | 0 | case OID_802_3_CURRENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, station_hwaddr, 6); return; |
129 | 0 | case OID_802_3_PERMANENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, permanent_hwaddr, 6); return; |
130 | 0 | case OID_GEN_MEDIA_SUPPORTED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
131 | 0 | case OID_GEN_MEDIA_IN_USE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
132 | 0 | case OID_GEN_PHYSICAL_MEDIUM: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; |
133 | 0 | case OID_GEN_HARDWARE_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
134 | 0 | case OID_GEN_LINK_SPEED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, rndis_link_speed_bps() / 100U); return; |
135 | 0 | case OID_GEN_VENDOR_ID: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00FFFFFF); return; |
136 | 0 | case OID_GEN_VENDOR_DESCRIPTION: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, rndis_vendor, strlen(rndis_vendor) + 1); return; |
137 | 0 | case OID_GEN_CURRENT_PACKET_FILTER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, oid_packet_filter); return; |
138 | 0 | case OID_GEN_MAXIMUM_FRAME_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU - SIZEOF_ETH_HDR); return; |
139 | 0 | case OID_GEN_MAXIMUM_TOTAL_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
140 | 0 | case OID_GEN_TRANSMIT_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
141 | 0 | case OID_GEN_RECEIVE_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; |
142 | 0 | case OID_GEN_MEDIA_CONNECT_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIA_STATE_CONNECTED); return; |
143 | 0 | case OID_GEN_RNDIS_CONFIG_PARAMETER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
144 | 0 | case OID_802_3_MAXIMUM_LIST_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 1); return; |
145 | 0 | case OID_802_3_MULTICAST_LIST: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; |
146 | 0 | case OID_802_3_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; |
147 | 0 | case OID_GEN_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, /*MAC_OPT*/ 0); return; |
148 | 0 | case OID_802_3_RCV_ERROR_ALIGNMENT: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
149 | 0 | case OID_802_3_XMIT_ONE_COLLISION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
150 | 0 | case OID_802_3_XMIT_MORE_COLLISIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
151 | 0 | case OID_GEN_XMIT_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txok); return; |
152 | 0 | case OID_GEN_RCV_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxok); return; |
153 | 0 | case OID_GEN_RCV_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxbad); return; |
154 | 0 | case OID_GEN_XMIT_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txbad); return; |
155 | 0 | case OID_GEN_RCV_NO_BUFFER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; |
156 | 0 | default: rndis_query_cmplt(RNDIS_STATUS_FAILURE, NULL, 0); return; |
157 | 0 | } |
158 | 0 | } |
159 | | |
160 | 0 | #define INFBUF ((uint8_t *)&(m->RequestId) + m->InformationBufferOffset) |
161 | | |
162 | | static void rndis_handle_config_parm(const char *data, int keyoffset, int valoffset, int keylen, int vallen) |
163 | 0 | { |
164 | 0 | (void)data; |
165 | 0 | (void)keyoffset; |
166 | 0 | (void)valoffset; |
167 | 0 | (void)keylen; |
168 | 0 | (void)vallen; |
169 | 0 | } |
170 | | |
171 | | static void rndis_packetFilter(uint32_t newfilter) |
172 | 0 | { |
173 | 0 | (void)newfilter; |
174 | 0 | } |
175 | | |
176 | | static void rndis_handle_set_msg(void) |
177 | 0 | { |
178 | 0 | rndis_set_cmplt_t *c; |
179 | 0 | rndis_set_msg_t *m; |
180 | 0 | rndis_Oid_t oid; |
181 | |
|
182 | 0 | c = (rndis_set_cmplt_t *)encapsulated_buffer; |
183 | 0 | m = (rndis_set_msg_t *)encapsulated_buffer; |
184 | |
|
185 | 0 | oid = m->Oid; |
186 | 0 | c->MessageType = REMOTE_NDIS_SET_CMPLT; |
187 | 0 | c->MessageLength = sizeof(rndis_set_cmplt_t); |
188 | 0 | c->Status = RNDIS_STATUS_SUCCESS; |
189 | |
|
190 | 0 | switch (oid) |
191 | 0 | { |
192 | | /* Parameters set up in 'Advanced' tab */ |
193 | 0 | case OID_GEN_RNDIS_CONFIG_PARAMETER: |
194 | 0 | { |
195 | 0 | rndis_config_parameter_t *p; |
196 | 0 | char *ptr = (char *)m; |
197 | 0 | ptr += sizeof(rndis_generic_msg_t); |
198 | 0 | ptr += m->InformationBufferOffset; |
199 | 0 | p = (rndis_config_parameter_t *) ((void*) ptr); |
200 | 0 | rndis_handle_config_parm(ptr, p->ParameterNameOffset, p->ParameterValueOffset, p->ParameterNameLength, p->ParameterValueLength); |
201 | 0 | } |
202 | 0 | break; |
203 | | |
204 | | /* Mandatory general OIDs */ |
205 | 0 | case OID_GEN_CURRENT_PACKET_FILTER: |
206 | 0 | memcpy(&oid_packet_filter, INFBUF, 4); |
207 | 0 | if (oid_packet_filter) |
208 | 0 | { |
209 | 0 | rndis_packetFilter(oid_packet_filter); |
210 | 0 | rndis_state = rndis_data_initialized; |
211 | 0 | } |
212 | 0 | else |
213 | 0 | { |
214 | 0 | rndis_state = rndis_initialized; |
215 | 0 | } |
216 | 0 | break; |
217 | | |
218 | 0 | case OID_GEN_CURRENT_LOOKAHEAD: |
219 | 0 | break; |
220 | | |
221 | 0 | case OID_GEN_PROTOCOL_OPTIONS: |
222 | 0 | break; |
223 | | |
224 | | /* Mandatory 802_3 OIDs */ |
225 | 0 | case OID_802_3_MULTICAST_LIST: |
226 | 0 | break; |
227 | | |
228 | | /* Power Management: fails for now */ |
229 | 0 | case OID_PNP_ADD_WAKE_UP_PATTERN: |
230 | 0 | case OID_PNP_REMOVE_WAKE_UP_PATTERN: |
231 | 0 | case OID_PNP_ENABLE_WAKE_UP: |
232 | 0 | default: |
233 | 0 | c->Status = RNDIS_STATUS_FAILURE; |
234 | 0 | break; |
235 | 0 | } |
236 | | |
237 | | /* c->MessageID is same as before */ |
238 | 0 | rndis_report(); |
239 | 0 | return; |
240 | 0 | } |
241 | | |
242 | | void rndis_class_set_handler(uint8_t *data, int size) |
243 | 0 | { |
244 | 0 | encapsulated_buffer = data; |
245 | 0 | (void)size; |
246 | |
|
247 | 0 | switch (((rndis_generic_msg_t *)encapsulated_buffer)->MessageType) |
248 | 0 | { |
249 | 0 | case REMOTE_NDIS_INITIALIZE_MSG: |
250 | 0 | { |
251 | 0 | rndis_initialize_cmplt_t *m; |
252 | 0 | m = ((rndis_initialize_cmplt_t *)encapsulated_buffer); |
253 | | /* m->MessageID is same as before */ |
254 | 0 | m->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; |
255 | 0 | m->MessageLength = sizeof(rndis_initialize_cmplt_t); |
256 | 0 | m->MajorVersion = RNDIS_MAJOR_VERSION; |
257 | 0 | m->MinorVersion = RNDIS_MINOR_VERSION; |
258 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
259 | 0 | m->DeviceFlags = RNDIS_DF_CONNECTIONLESS; |
260 | 0 | m->Medium = RNDIS_MEDIUM_802_3; |
261 | 0 | m->MaxPacketsPerTransfer = 1; |
262 | 0 | m->MaxTransferSize = CFG_TUD_NET_MTU + sizeof(rndis_data_packet_t); |
263 | 0 | m->PacketAlignmentFactor = 0; |
264 | 0 | m->AfListOffset = 0; |
265 | 0 | m->AfListSize = 0; |
266 | 0 | rndis_state = rndis_initialized; |
267 | 0 | rndis_report(); |
268 | 0 | } |
269 | 0 | break; |
270 | | |
271 | 0 | case REMOTE_NDIS_QUERY_MSG: |
272 | 0 | rndis_query(); |
273 | 0 | break; |
274 | | |
275 | 0 | case REMOTE_NDIS_SET_MSG: |
276 | 0 | rndis_handle_set_msg(); |
277 | 0 | break; |
278 | | |
279 | 0 | case REMOTE_NDIS_RESET_MSG: |
280 | 0 | { |
281 | 0 | rndis_reset_cmplt_t * m; |
282 | 0 | m = ((rndis_reset_cmplt_t *)encapsulated_buffer); |
283 | 0 | rndis_state = rndis_uninitialized; |
284 | 0 | m->MessageType = REMOTE_NDIS_RESET_CMPLT; |
285 | 0 | m->MessageLength = sizeof(rndis_reset_cmplt_t); |
286 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
287 | 0 | m->AddressingReset = 1; /* Make it look like we did something */ |
288 | | /* m->AddressingReset = 0; - Windows halts if set to 1 for some reason */ |
289 | 0 | rndis_report(); |
290 | 0 | } |
291 | 0 | break; |
292 | | |
293 | 0 | case REMOTE_NDIS_KEEPALIVE_MSG: |
294 | 0 | { |
295 | 0 | rndis_keepalive_cmplt_t * m; |
296 | 0 | m = (rndis_keepalive_cmplt_t *)encapsulated_buffer; |
297 | 0 | m->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; |
298 | 0 | m->MessageLength = sizeof(rndis_keepalive_cmplt_t); |
299 | 0 | m->Status = RNDIS_STATUS_SUCCESS; |
300 | 0 | } |
301 | | /* We have data to send back */ |
302 | 0 | rndis_report(); |
303 | 0 | break; |
304 | | |
305 | 0 | default: |
306 | 0 | break; |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | #endif |