1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT zephyr_cdc_ncm_ethernet
8
9 #include <zephyr/net/net_pkt.h>
10 #include <zephyr/net/ethernet.h>
11
12 #include <eth.h>
13
14 #include <zephyr/usb/usbd.h>
15 #include <zephyr/usb/usb_ch9.h>
16 #include <zephyr/usb/class/usb_cdc.h>
17 #include <zephyr/drivers/usb/udc.h>
18
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(cdc_ncm, CONFIG_USBD_CDC_NCM_LOG_LEVEL);
21
22 /* Set to 1 if you want to see hexdump of the packet in debug log level */
23 #define DUMP_PKT 0
24
25 #define CDC_NCM_ALIGNMENT 4U
26 #define CDC_NCM_EP_MPS_INT 64U
27 #define CDC_NCM_INTERVAL_DEFAULT 50000UL
28 #define CDC_NCM_FS_INT_EP_INTERVAL USB_FS_INT_EP_INTERVAL(10000U)
29 #define CDC_NCM_HS_INT_EP_INTERVAL USB_HS_INT_EP_INTERVAL(10000U)
30
31 #define NCM_USB_SPEED_FS 12000000UL
32 #define NCM_USB_SPEED_HS 480000000UL
33
34 enum {
35 CDC_NCM_IFACE_UP,
36 CDC_NCM_DATA_IFACE_ENABLED,
37 CDC_NCM_CLASS_SUSPENDED,
38 CDC_NCM_OUT_ENGAGED,
39 };
40
41 /* Chapter 6.2.7 table 6-4 */
42 #define CDC_NCM_RECV_MAX_DATAGRAMS_PER_NTB CONFIG_USBD_CDC_NCM_MAX_DGRAM_PER_NTB
43 #define CDC_NCM_RECV_NTB_MAX_SIZE 2048
44
45 #define CDC_NCM_SEND_MAX_DATAGRAMS_PER_NTB 1
46 #define CDC_NCM_SEND_NTB_MAX_SIZE 2048
47
48 /* Chapter 6.3 table 6-5 and 6-6 */
49 struct cdc_ncm_notification {
50 union {
51 uint8_t bmRequestType;
52 struct usb_req_type_field RequestType;
53 };
54 uint8_t bNotificationType;
55 uint16_t wValue;
56 uint16_t wIndex;
57 uint16_t wLength;
58 } __packed;
59
60 enum ncm_notification_code {
61 NETWORK_CONNECTION = 0x00,
62 RESPONSE_AVAILABLE = 0x01,
63 CONNECTION_SPEED_CHANGE = 0x2A,
64 };
65
66 /* Chapter 3.2.1 table 3-1 */
67 #define NTH16_SIGNATURE 0x484D434E /* HMCN */
68
69 struct nth16 {
70 uint32_t dwSignature;
71 uint16_t wHeaderLength;
72 uint16_t wSequence;
73 uint16_t wBlockLength;
74 uint16_t wNdpIndex;
75 } __packed;
76
77 /* Chapter 3.2.2 table 3-2 */
78 #define NTH32_SIGNATURE 0x686D636E /* hmcn */
79
80 struct nth32 {
81 uint32_t dwSignature;
82 uint16_t wHeaderLength;
83 uint16_t wSequence;
84 uint32_t wBlockLength;
85 uint32_t wNdpIndex;
86 } __packed;
87
88 /* Chapter 3.3.1 table 3-3 */
89 #define NDP16_SIGNATURE_NCM0 0x304D434E /* 0MCN */
90 #define NDP16_SIGNATURE_NCM1 0x314D434E /* 1MCN */
91
92 struct ndp16_datagram {
93 uint16_t wDatagramIndex;
94 uint16_t wDatagramLength;
95 } __packed;
96
97 /* Chapter 3.3.2 table 3-4 */
98 #define NDP32_SIGNATURE_NCM0 0x306D636E /* 0mcn */
99 #define NDP32_SIGNATURE_NCM1 0x316D636E /* 1mcn */
100
101 struct ndp32_datagram {
102 uint32_t wDatagramIndex;
103 uint32_t wDatagramLength;
104 } __packed;
105
106 struct ndp16 {
107 uint32_t dwSignature;
108 uint16_t wLength;
109 uint16_t wNextNdpIndex;
110 struct ndp16_datagram datagram[];
111 } __packed;
112
113 /* Chapter 6.2.1 table 6-3 */
114 struct ntb_parameters {
115 uint16_t wLength;
116 uint16_t bmNtbFormatsSupported;
117 uint32_t dwNtbInMaxSize;
118 uint16_t wNdbInDivisor;
119 uint16_t wNdbInPayloadRemainder;
120 uint16_t wNdbInAlignment;
121 uint16_t wReserved;
122 uint32_t dwNtbOutMaxSize;
123 uint16_t wNdbOutDivisor;
124 uint16_t wNdbOutPayloadRemainder;
125 uint16_t wNdbOutAlignment;
126 uint16_t wNtbOutMaxDatagrams;
127 } __packed;
128
129 /* Chapter 6.2.7 table 6-4 */
130 struct ntb_input_size {
131 uint32_t dwNtbInMaxSize;
132 uint16_t wNtbInMaxDatagrams;
133 uint16_t wReserved;
134 } __packed;
135
136 #define NTB16_FORMAT_SUPPORTED BIT(0)
137 #define NTB32_FORMAT_SUPPORTED BIT(1)
138
139 #define NTB_FORMAT_SUPPORTED (NTB16_FORMAT_SUPPORTED | \
140 COND_CODE_1(CONFIG_USBD_CDC_NCM_SUPPORT_NTB32, \
141 (NTB32_FORMAT_SUPPORTED), (0)))
142
143 BUILD_ASSERT(!IS_ENABLED(CONFIG_USBD_CDC_NCM_SUPPORT_NTB32), "NTB32 not yet supported!");
144
145 struct ncm_notify_network_connection {
146 struct usb_setup_packet header;
147 } __packed;
148
149 struct ncm_notify_connection_speed_change {
150 struct usb_setup_packet header;
151 uint32_t downlink;
152 uint32_t uplink;
153 } __packed;
154
155 union send_ntb {
156 struct {
157 struct nth16 nth;
158 struct ndp16 ndp;
159 struct ndp16_datagram ndp_datagram[CDC_NCM_SEND_MAX_DATAGRAMS_PER_NTB + 1];
160 };
161
162 uint8_t data[CDC_NCM_SEND_NTB_MAX_SIZE];
163 } __packed;
164
165 union recv_ntb {
166 struct {
167 struct nth16 nth;
168 };
169
170 uint8_t data[CDC_NCM_RECV_NTB_MAX_SIZE];
171 } __packed;
172
173 /*
174 * Transfers through two endpoints proceed in a synchronous manner,
175 * with maximum block of CDC_NCM_SEND_NTB_MAX_SIZE.
176 */
177 UDC_BUF_POOL_DEFINE(cdc_ncm_ep_pool,
178 DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) * 2,
179 MAX(CDC_NCM_SEND_NTB_MAX_SIZE, CDC_NCM_RECV_NTB_MAX_SIZE),
180 sizeof(struct udc_buf_info), NULL);
181
182 /*
183 * Collection of descriptors used to assemble specific function descriptors.
184 * This structure is used by CDC NCM implementation to update and fetch
185 * properties at runtime. We currently support full and high speed.
186 */
187 struct usbd_cdc_ncm_desc {
188 struct usb_association_descriptor iad;
189
190 struct usb_if_descriptor if0;
191 struct cdc_header_descriptor if0_header;
192 struct cdc_union_descriptor if0_union;
193 struct cdc_ecm_descriptor if0_ecm;
194 struct cdc_ncm_descriptor if0_ncm;
195 struct usb_ep_descriptor if0_int_ep;
196 struct usb_ep_descriptor if0_hs_int_ep;
197
198 struct usb_if_descriptor if1_0;
199
200 struct usb_if_descriptor if1_1;
201 struct usb_ep_descriptor if1_1_in_ep;
202 struct usb_ep_descriptor if1_1_out_ep;
203 struct usb_ep_descriptor if1_1_hs_in_ep;
204 struct usb_ep_descriptor if1_1_hs_out_ep;
205
206 struct usb_desc_header nil_desc;
207 };
208
209 enum iface_state {
210 IF_STATE_INIT,
211 IF_STATE_CONNECTION_STATUS_SUBMITTED,
212 IF_STATE_CONNECTION_STATUS_SENT,
213 IF_STATE_SPEED_CHANGE_SUBMITTED,
214 IF_STATE_SPEED_CHANGE_SENT,
215 IF_STATE_DONE,
216 };
217
218 struct cdc_ncm_eth_data {
219 struct usbd_class_data *c_data;
220 struct usbd_desc_node *const mac_desc_data;
221 struct usbd_cdc_ncm_desc *const desc;
222 const struct usb_desc_header **const fs_desc;
223 const struct usb_desc_header **const hs_desc;
224
225 struct net_if *iface;
226 uint8_t mac_addr[6];
227
228 atomic_t state;
229 enum iface_state if_state;
230 uint16_t tx_seq;
231 uint16_t rx_seq;
232
233 struct k_sem sync_sem;
234
235 struct k_work_delayable notif_work;
236 };
237
cdc_ncm_get_ctrl_if(struct cdc_ncm_eth_data * const data)238 static uint8_t cdc_ncm_get_ctrl_if(struct cdc_ncm_eth_data *const data)
239 {
240 struct usbd_cdc_ncm_desc *desc = data->desc;
241
242 return desc->if0.bInterfaceNumber;
243 }
244
cdc_ncm_get_int_in(struct usbd_class_data * const c_data)245 static uint8_t cdc_ncm_get_int_in(struct usbd_class_data *const c_data)
246 {
247 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
248 const struct device *dev = usbd_class_get_private(c_data);
249 struct cdc_ncm_eth_data *data = dev->data;
250 struct usbd_cdc_ncm_desc *desc = data->desc;
251
252 if (USBD_SUPPORTS_HIGH_SPEED &&
253 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
254 return desc->if0_hs_int_ep.bEndpointAddress;
255 }
256
257 return desc->if0_int_ep.bEndpointAddress;
258 }
259
cdc_ncm_get_bulk_in(struct usbd_class_data * const c_data)260 static uint8_t cdc_ncm_get_bulk_in(struct usbd_class_data *const c_data)
261 {
262 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
263 const struct device *dev = usbd_class_get_private(c_data);
264 struct cdc_ncm_eth_data *data = dev->data;
265 struct usbd_cdc_ncm_desc *desc = data->desc;
266
267 if (USBD_SUPPORTS_HIGH_SPEED &&
268 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
269 return desc->if1_1_hs_in_ep.bEndpointAddress;
270 }
271
272 return desc->if1_1_in_ep.bEndpointAddress;
273 }
274
cdc_ncm_get_bulk_in_mps(struct usbd_class_data * const c_data)275 static uint16_t cdc_ncm_get_bulk_in_mps(struct usbd_class_data *const c_data)
276 {
277 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
278
279 if (USBD_SUPPORTS_HIGH_SPEED &&
280 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
281 return 512U;
282 }
283
284 return 64U;
285 }
286
cdc_ncm_get_bulk_out(struct usbd_class_data * const c_data)287 static uint8_t cdc_ncm_get_bulk_out(struct usbd_class_data *const c_data)
288 {
289 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
290 const struct device *dev = usbd_class_get_private(c_data);
291 struct cdc_ncm_eth_data *data = dev->data;
292 struct usbd_cdc_ncm_desc *desc = data->desc;
293
294 if (USBD_SUPPORTS_HIGH_SPEED &&
295 usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
296 return desc->if1_1_hs_out_ep.bEndpointAddress;
297 }
298
299 return desc->if1_1_out_ep.bEndpointAddress;
300 }
301
cdc_ncm_buf_alloc(const uint8_t ep)302 static struct net_buf *cdc_ncm_buf_alloc(const uint8_t ep)
303 {
304 struct net_buf *buf = NULL;
305 struct udc_buf_info *bi;
306
307 buf = net_buf_alloc(&cdc_ncm_ep_pool, K_NO_WAIT);
308 if (!buf) {
309 return NULL;
310 }
311
312 bi = udc_get_buf_info(buf);
313 bi->ep = ep;
314
315 return buf;
316 }
317
cdc_ncm_out_start(struct usbd_class_data * const c_data)318 static int cdc_ncm_out_start(struct usbd_class_data *const c_data)
319 {
320 const struct device *dev = usbd_class_get_private(c_data);
321 struct cdc_ncm_eth_data *data = dev->data;
322 struct net_buf *buf;
323 uint8_t ep;
324 int ret;
325
326 if (atomic_test_and_set_bit(&data->state, CDC_NCM_OUT_ENGAGED)) {
327 return -EBUSY;
328 }
329
330 ep = cdc_ncm_get_bulk_out(c_data);
331 buf = cdc_ncm_buf_alloc(ep);
332 if (buf == NULL) {
333 return -ENOMEM;
334 }
335
336 ret = usbd_ep_enqueue(c_data, buf);
337 if (ret) {
338 LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep);
339 net_buf_unref(buf);
340 } else {
341 LOG_DBG("enqueue out %u", buf->size);
342 }
343
344 return ret;
345 }
346
verify_nth16(struct cdc_ncm_eth_data * const data,const union recv_ntb * const ntb,const uint16_t len)347 static int verify_nth16(struct cdc_ncm_eth_data *const data,
348 const union recv_ntb *const ntb, const uint16_t len)
349 {
350 const struct nth16 *nthdr16 = &ntb->nth;
351 const struct ndp16 *ndphdr16;
352
353 if (len < sizeof(ntb->nth)) {
354 LOG_DBG("DROP: %s len %d", "", len);
355 return -EINVAL;
356 }
357
358 if (sys_le16_to_cpu(nthdr16->wHeaderLength) != sizeof(struct nth16)) {
359 LOG_DBG("DROP: %s len %d", "nth16",
360 sys_le16_to_cpu(nthdr16->wHeaderLength));
361 return -EINVAL;
362 }
363
364 if (sys_le32_to_cpu(nthdr16->dwSignature) != NTH16_SIGNATURE) {
365 LOG_DBG("DROP: %s signature 0x%04x", "nth16",
366 (unsigned int)sys_le32_to_cpu(nthdr16->dwSignature));
367 return -EINVAL;
368 }
369
370 if (sys_le16_to_cpu(nthdr16->wSequence) != data->rx_seq) {
371 LOG_WRN("OUT NTH wSequence %u mismatch expected %u",
372 sys_le16_to_cpu(nthdr16->wSequence), data->rx_seq);
373 data->rx_seq = sys_le16_to_cpu(nthdr16->wSequence);
374 }
375
376 data->rx_seq++;
377
378 if (len < (sizeof(struct nth16) + sizeof(struct ndp16) +
379 2U * sizeof(struct ndp16_datagram))) {
380 LOG_DBG("DROP: %s len %d", "min", len);
381 return -EINVAL;
382 }
383
384 if (sys_le16_to_cpu(nthdr16->wBlockLength) != len) {
385 LOG_DBG("DROP: %s len %d", "block",
386 sys_le16_to_cpu(nthdr16->wBlockLength));
387 return -EINVAL;
388 }
389
390 if (sys_le16_to_cpu(nthdr16->wBlockLength) > CDC_NCM_RECV_NTB_MAX_SIZE) {
391 LOG_DBG("DROP: %s len %d", "block max",
392 sys_le16_to_cpu(nthdr16->wBlockLength));
393 return -EINVAL;
394 }
395
396 if ((sys_le16_to_cpu(nthdr16->wNdpIndex) < sizeof(struct nth16)) ||
397 (sys_le16_to_cpu(nthdr16->wNdpIndex) >
398 (len - (sizeof(struct ndp16) + 2U * sizeof(struct ndp16_datagram))))) {
399 LOG_DBG("DROP: ndp pos %d (%d)",
400 sys_le16_to_cpu(nthdr16->wNdpIndex), len);
401 return -EINVAL;
402 }
403
404 ndphdr16 = (const struct ndp16 *)(ntb->data +
405 sys_le16_to_cpu(nthdr16->wNdpIndex));
406
407 if (sys_le16_to_cpu(ndphdr16->wLength) <
408 (sizeof(struct ndp16) + 2U * sizeof(struct ndp16_datagram))) {
409 LOG_DBG("DROP: %s len %d", "ndp16",
410 sys_le16_to_cpu(ndphdr16->wLength));
411 return -EINVAL;
412 }
413
414 if ((sys_le32_to_cpu(ndphdr16->dwSignature) != NDP16_SIGNATURE_NCM0) &&
415 (sys_le32_to_cpu(ndphdr16->dwSignature) != NDP16_SIGNATURE_NCM1)) {
416 LOG_DBG("DROP: %s signature 0x%04x", "ndp16",
417 (unsigned int)sys_le32_to_cpu(ndphdr16->dwSignature));
418 return -EINVAL;
419 }
420
421 if (sys_le16_to_cpu(ndphdr16->wNextNdpIndex) != 0) {
422 LOG_DBG("DROP: wNextNdpIndex %d",
423 sys_le16_to_cpu(ndphdr16->wNextNdpIndex));
424 return -EINVAL;
425 }
426
427 return 0;
428 }
429
check_frame(struct cdc_ncm_eth_data * data,struct net_buf * const buf)430 static int check_frame(struct cdc_ncm_eth_data *data, struct net_buf *const buf)
431 {
432 const union recv_ntb *ntb = (union recv_ntb *)buf->data;
433 const struct nth16 *nthdr16 = &ntb->nth;
434 uint16_t len = buf->len;
435 int ndx = 0;
436 const struct ndp16_datagram *ndp_datagram;
437 const struct ndp16 *ndptr16;
438 uint16_t max_ndx;
439 int ret;
440
441 /* TODO: support nth32 */
442 ret = verify_nth16(data, ntb, len);
443 if (ret < 0) {
444 LOG_ERR("Failed to verify NTH16");
445 return ret;
446 }
447
448 ndp_datagram = (const struct ndp16_datagram *)
449 (ntb->data + sys_le16_to_cpu(nthdr16->wNdpIndex) +
450 sizeof(struct ndp16));
451
452 ndptr16 = (const struct ndp16 *)(ntb->data + sys_le16_to_cpu(nthdr16->wNdpIndex));
453
454 max_ndx = (uint16_t)((sys_le16_to_cpu(ndptr16->wLength) - sizeof(struct ndp16)) /
455 sizeof(struct ndp16_datagram));
456
457 if (max_ndx > (CDC_NCM_RECV_MAX_DATAGRAMS_PER_NTB + 1)) {
458 LOG_DBG("DROP: dgram count %d (%d)", max_ndx - 1,
459 sys_le16_to_cpu(ntb->nth.wBlockLength));
460 return -EINVAL;
461 }
462
463 if ((sys_le16_to_cpu(ndp_datagram[max_ndx-1].wDatagramIndex) != 0) ||
464 (sys_le16_to_cpu(ndp_datagram[max_ndx-1].wDatagramLength) != 0)) {
465 LOG_DBG("DROP: max_ndx");
466 return -EINVAL;
467 }
468
469 while (sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex) != 0 &&
470 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramLength) != 0) {
471
472 LOG_DBG("idx %d len %d",
473 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex),
474 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramLength));
475
476 if (sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex) > len) {
477 LOG_DBG("DROP: %s datagram[%d] %d (%d)", "start",
478 ndx,
479 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex),
480 len);
481 return -EINVAL;
482 }
483
484 if (sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex) +
485 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramLength) > len) {
486 LOG_DBG("DROP: %s datagram[%d] %d (%d)", "stop",
487 ndx,
488 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramIndex) +
489 sys_le16_to_cpu(ndp_datagram[ndx].wDatagramLength),
490 len);
491 return -EINVAL;
492 }
493
494 ndx++;
495 }
496
497 if (DUMP_PKT) {
498 LOG_HEXDUMP_DBG(ntb->data, len, "NTB");
499 }
500
501 return 0;
502 }
503
504 #define NET_PKT_ALLOC_TIMEOUT 100 /* ms */
505
cdc_ncm_acl_out_cb(struct usbd_class_data * const c_data,struct net_buf * const buf,const int err)506 static int cdc_ncm_acl_out_cb(struct usbd_class_data *const c_data,
507 struct net_buf *const buf, const int err)
508 {
509 const struct device *dev = usbd_class_get_private(c_data);
510 const union recv_ntb *ntb = (union recv_ntb *)buf->data;
511 struct cdc_ncm_eth_data *data = dev->data;
512 const struct ndp16_datagram *ndp_datagram;
513 const struct nth16 *nthdr16;
514 const struct ndp16 *ndp;
515 struct net_pkt *pkt, *src;
516 uint16_t start, len;
517 uint16_t count;
518 int ret;
519
520 if (err || buf->len == 0) {
521 if (err != -ECONNABORTED) {
522 LOG_ERR("Bulk OUT transfer error (%d) or zero length", err);
523 }
524
525 goto restart_out_transfer;
526 }
527
528 ret = check_frame(data, buf);
529 if (ret < 0) {
530 LOG_ERR("check frame failed (%d)", ret);
531 goto restart_out_transfer;
532 }
533
534 /* Temporary source pkt we use to copy one Ethernet frame from
535 * the list of USB net_buf's.
536 */
537 src = net_pkt_alloc(K_MSEC(NET_PKT_ALLOC_TIMEOUT));
538 if (src == NULL) {
539 LOG_ERR("src packet alloc fail");
540 goto restart_out_transfer;
541 }
542
543 net_pkt_append_buffer(src, buf);
544 net_pkt_set_overwrite(src, true);
545
546 nthdr16 = &ntb->nth;
547 LOG_DBG("NTH16: wSequence %u wBlockLength %u wNdpIndex %u",
548 nthdr16->wSequence, nthdr16->wBlockLength, nthdr16->wNdpIndex);
549
550 /* NDP may be anywhere in the transfer buffer. Offsets, like wNdpIndex
551 * or wDatagramIndex are always of from byte zero of the NTB.
552 */
553 ndp = (const struct ndp16 *)(ntb->data + sys_le16_to_cpu(nthdr16->wNdpIndex));
554 LOG_DBG("NDP16: wLength %u", sys_le16_to_cpu(ndp->wLength));
555
556 ndp_datagram = (struct ndp16_datagram *)&ndp->datagram[0];
557
558 /* There is one (terminating zero) or more datagram pointer
559 * entries starting after 8 bytes of header information.
560 */
561 count = (sys_le16_to_cpu(ndp->wLength) - 8U) / 4U;
562 LOG_DBG("%u datagram%s received", count, count == 1 ? "" : "s");
563
564 for (int i = 0; i < count; i++) {
565 start = sys_le16_to_cpu(ndp_datagram[i].wDatagramIndex);
566 len = sys_le16_to_cpu(ndp_datagram[i].wDatagramLength);
567
568 LOG_DBG("[%d] start %u len %u", i, start, len);
569 if (start == 0 || len == 0) {
570 LOG_DBG("Terminating zero datagram %u", i);
571 break;
572 }
573
574 pkt = net_pkt_rx_alloc_with_buffer(data->iface, len, AF_UNSPEC, 0, K_FOREVER);
575 if (!pkt) {
576 LOG_ERR("No memory for net_pkt");
577 goto unref_packet;
578 }
579
580 net_pkt_cursor_init(src);
581
582 ret = net_pkt_skip(src, start);
583 if (ret < 0) {
584 LOG_ERR("Cannot advance pkt by %u bytes (%d)", start, ret);
585 net_pkt_unref(pkt);
586 goto unref_packet;
587 }
588
589 ret = net_pkt_copy(pkt, src, len);
590 if (ret < 0) {
591 LOG_ERR("Cannot copy data (%d)", ret);
592 net_pkt_unref(pkt);
593 goto unref_packet;
594 }
595
596 LOG_DBG("Received packet len %zu", net_pkt_get_len(pkt));
597
598 if (net_recv_data(data->iface, pkt) < 0) {
599 LOG_ERR("Packet %p dropped by network stack", pkt);
600 net_pkt_unref(pkt);
601 }
602 }
603
604 unref_packet:
605 src->buffer = NULL;
606 net_pkt_unref(src);
607
608 restart_out_transfer:
609 net_buf_unref(buf);
610
611 atomic_clear_bit(&data->state, CDC_NCM_OUT_ENGAGED);
612 if (atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED)) {
613 return cdc_ncm_out_start(c_data);
614 }
615
616 return 0;
617 }
618
ncm_handle_notifications(const struct device * dev,const int err)619 static void ncm_handle_notifications(const struct device *dev, const int err)
620 {
621 struct cdc_ncm_eth_data *data = dev->data;
622
623 if (err != 0) {
624 LOG_WRN("Notification request %s",
625 err == -ECONNABORTED ? "cancelled" : "failed");
626 data->if_state = IF_STATE_INIT;
627 }
628
629 if (data->if_state == IF_STATE_SPEED_CHANGE_SUBMITTED) {
630 data->if_state = IF_STATE_SPEED_CHANGE_SENT;
631 LOG_INF("Speed change sent");
632 (void)k_work_reschedule(&data->notif_work, K_MSEC(1));
633 }
634
635 if (data->if_state == IF_STATE_CONNECTION_STATUS_SUBMITTED) {
636 data->if_state = IF_STATE_CONNECTION_STATUS_SENT;
637 LOG_INF("Connection status sent");
638 }
639 }
640
usbd_cdc_ncm_request(struct usbd_class_data * const c_data,struct net_buf * buf,int err)641 static int usbd_cdc_ncm_request(struct usbd_class_data *const c_data,
642 struct net_buf *buf, int err)
643 {
644 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
645 const struct device *dev = usbd_class_get_private(c_data);
646 struct cdc_ncm_eth_data *data = dev->data;
647 struct udc_buf_info *bi;
648
649 bi = udc_get_buf_info(buf);
650 LOG_DBG("finished %x len %u", bi->ep, buf->len);
651
652 if (bi->ep == cdc_ncm_get_bulk_out(c_data)) {
653 return cdc_ncm_acl_out_cb(c_data, buf, err);
654 }
655
656 if (bi->ep == cdc_ncm_get_bulk_in(c_data)) {
657 k_sem_give(&data->sync_sem);
658 return 0;
659 }
660
661 if (bi->ep == cdc_ncm_get_int_in(c_data)) {
662 ncm_handle_notifications(dev, err);
663 net_buf_unref(buf);
664 return 0;
665 }
666
667 return usbd_ep_buf_free(uds_ctx, buf);
668 }
669
cdc_ncm_send_notification(const struct device * dev,void * notification,size_t notification_size)670 static int cdc_ncm_send_notification(const struct device *dev,
671 void *notification, size_t notification_size)
672 {
673 struct cdc_ncm_eth_data *data = dev->data;
674 struct usbd_class_data *c_data = data->c_data;
675 struct net_buf *buf;
676 uint8_t ep;
677 int ret;
678
679 if (!atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED)) {
680 LOG_INF("USB configuration is not enabled");
681 return -EBUSY;
682 }
683
684 if (atomic_test_bit(&data->state, CDC_NCM_CLASS_SUSPENDED)) {
685 LOG_INF("USB device is suspended (FIXME)");
686 return -EBUSY;
687 }
688
689 ep = cdc_ncm_get_int_in(c_data);
690
691 buf = usbd_ep_buf_alloc(c_data, ep, notification_size);
692 if (buf == NULL) {
693 return -ENOMEM;
694 }
695
696 net_buf_add_mem(buf, notification, notification_size);
697
698 ret = usbd_ep_enqueue(c_data, buf);
699 if (ret) {
700 LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep);
701 net_buf_unref(buf);
702 }
703
704 return ret;
705 }
706
cdc_ncm_send_connected(const struct device * dev,const bool connected)707 static int cdc_ncm_send_connected(const struct device *dev,
708 const bool connected)
709 {
710 struct cdc_ncm_eth_data *data = dev->data;
711 struct cdc_ncm_notification notify_connection = {
712 .RequestType = {
713 .direction = USB_REQTYPE_DIR_TO_HOST,
714 .type = USB_REQTYPE_TYPE_CLASS,
715 .recipient = USB_REQTYPE_RECIPIENT_INTERFACE,
716 },
717 .bNotificationType = USB_CDC_NETWORK_CONNECTION,
718 .wValue = sys_cpu_to_le16((uint16_t)connected),
719 .wIndex = sys_cpu_to_le16(cdc_ncm_get_ctrl_if(data)),
720 .wLength = 0,
721 };
722 int ret;
723
724 ret = cdc_ncm_send_notification(dev, ¬ify_connection,
725 sizeof(notify_connection));
726 if (ret < 0) {
727 LOG_DBG("Cannot send %s (%d)",
728 connected ? "connected" : "disconnected", ret);
729 }
730
731 return ret;
732 }
733
cdc_ncm_send_speed_change(const struct device * dev)734 static int cdc_ncm_send_speed_change(const struct device *dev)
735 {
736 struct cdc_ncm_eth_data *data = dev->data;
737 struct usbd_class_data *c_data = data->c_data;
738 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
739 uint32_t usb_speed = (usbd_bus_speed(uds_ctx) == USBD_SPEED_FS) ?
740 NCM_USB_SPEED_FS : NCM_USB_SPEED_HS;
741 struct ncm_notify_connection_speed_change notify_speed_change = {
742 .header = {
743 .RequestType = {
744 .recipient = USB_REQTYPE_RECIPIENT_INTERFACE,
745 .type = USB_REQTYPE_TYPE_CLASS,
746 .direction = USB_REQTYPE_DIR_TO_HOST
747 },
748 .bRequest = CONNECTION_SPEED_CHANGE,
749 .wLength = sys_cpu_to_le16(8),
750 .wIndex = sys_cpu_to_le16(cdc_ncm_get_ctrl_if(data)),
751 },
752 .downlink = sys_cpu_to_le32(usb_speed),
753 .uplink = sys_cpu_to_le32(usb_speed),
754 };
755 int ret;
756
757 ret = cdc_ncm_send_notification(dev,
758 ¬ify_speed_change,
759 sizeof(notify_speed_change));
760 if (ret < 0) {
761 LOG_DBG("Cannot send %s (%d)", "speed change", ret);
762 return ret;
763 }
764
765 return ret;
766 }
767
768
ncm_send_notification_sequence(const struct device * dev)769 static int ncm_send_notification_sequence(const struct device *dev)
770 {
771 struct cdc_ncm_eth_data *data = dev->data;
772 int ret;
773
774 /* Speed change must be sent first, chapter 7.1 */
775 if (data->if_state == IF_STATE_INIT) {
776 ret = cdc_ncm_send_speed_change(dev);
777 if (ret < 0) {
778 LOG_INF("Cannot send %s (%d)", "speed change", ret);
779 return ret;
780 }
781
782 LOG_INF("Speed change submitted");
783 data->if_state = IF_STATE_SPEED_CHANGE_SUBMITTED;
784 return -EAGAIN;
785 }
786
787 if (data->if_state == IF_STATE_SPEED_CHANGE_SENT) {
788 ret = cdc_ncm_send_connected(dev, true);
789 if (ret < 0) {
790 LOG_INF("Cannot send %s (%d)", "connected status", ret);
791 return ret;
792 }
793
794 LOG_INF("Connected status submitted");
795 data->if_state = IF_STATE_CONNECTION_STATUS_SUBMITTED;
796 return -EAGAIN;
797 }
798
799 if (data->if_state == IF_STATE_CONNECTION_STATUS_SENT) {
800 LOG_INF("Connected status done");
801 data->if_state = IF_STATE_DONE;
802 }
803
804 return 0;
805 }
806
send_notification_work(struct k_work * work)807 static void send_notification_work(struct k_work *work)
808 {
809 struct k_work_delayable *notif_work = k_work_delayable_from_work(work);
810 struct cdc_ncm_eth_data *data;
811 struct device *dev;
812 int ret;
813
814 data = CONTAINER_OF(notif_work, struct cdc_ncm_eth_data, notif_work);
815 dev = usbd_class_get_private(data->c_data);
816
817 if (atomic_test_bit(&data->state, CDC_NCM_IFACE_UP)) {
818 ret = ncm_send_notification_sequence(dev);
819 } else {
820 data->if_state = IF_STATE_INIT;
821 ret = cdc_ncm_send_connected(dev, false);
822 }
823
824 if (ret) {
825 (void)k_work_reschedule(&data->notif_work, K_MSEC(100));
826 }
827 }
828
usbd_cdc_ncm_update(struct usbd_class_data * const c_data,const uint8_t iface,const uint8_t alternate)829 static void usbd_cdc_ncm_update(struct usbd_class_data *const c_data,
830 const uint8_t iface, const uint8_t alternate)
831 {
832 const struct device *dev = usbd_class_get_private(c_data);
833 struct cdc_ncm_eth_data *data = dev->data;
834 struct usbd_cdc_ncm_desc *desc = data->desc;
835 uint8_t data_iface = desc->if1_1.bInterfaceNumber;
836 int ret;
837
838 LOG_INF("New configuration, interface %u alternate %u",
839 iface, alternate);
840
841 if (data_iface == iface && alternate == 0) {
842 atomic_clear_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED);
843 data->tx_seq = 0;
844 data->rx_seq = 0;
845 }
846
847 if (data_iface == iface && alternate == 1) {
848 atomic_set_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED);
849 data->if_state = IF_STATE_INIT;
850 (void)k_work_reschedule(&data->notif_work, K_MSEC(100));
851 ret = cdc_ncm_out_start(c_data);
852 if (ret < 0) {
853 LOG_ERR("Failed to start OUT transfer (%d)", ret);
854 }
855 }
856 }
857
usbd_cdc_ncm_enable(struct usbd_class_data * const c_data)858 static void usbd_cdc_ncm_enable(struct usbd_class_data *const c_data)
859 {
860 LOG_INF("Enabled %s", c_data->name);
861 }
862
usbd_cdc_ncm_disable(struct usbd_class_data * const c_data)863 static void usbd_cdc_ncm_disable(struct usbd_class_data *const c_data)
864 {
865 const struct device *dev = usbd_class_get_private(c_data);
866 struct cdc_ncm_eth_data *data = dev->data;
867
868 atomic_clear_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED);
869 atomic_clear_bit(&data->state, CDC_NCM_CLASS_SUSPENDED);
870
871 LOG_INF("Disabled %s", c_data->name);
872 }
873
usbd_cdc_ncm_suspended(struct usbd_class_data * const c_data)874 static void usbd_cdc_ncm_suspended(struct usbd_class_data *const c_data)
875 {
876 const struct device *dev = usbd_class_get_private(c_data);
877 struct cdc_ncm_eth_data *data = dev->data;
878
879 atomic_set_bit(&data->state, CDC_NCM_CLASS_SUSPENDED);
880 }
881
usbd_cdc_ncm_resumed(struct usbd_class_data * const c_data)882 static void usbd_cdc_ncm_resumed(struct usbd_class_data *const c_data)
883 {
884 const struct device *dev = usbd_class_get_private(c_data);
885 struct cdc_ncm_eth_data *data = dev->data;
886
887 atomic_clear_bit(&data->state, CDC_NCM_CLASS_SUSPENDED);
888 }
889
usbd_cdc_ncm_ctd(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,const struct net_buf * const buf)890 static int usbd_cdc_ncm_ctd(struct usbd_class_data *const c_data,
891 const struct usb_setup_packet *const setup,
892 const struct net_buf *const buf)
893 {
894 if (setup->RequestType.recipient == USB_REQTYPE_RECIPIENT_INTERFACE) {
895 if (setup->bRequest == SET_ETHERNET_PACKET_FILTER) {
896 LOG_DBG("bRequest 0x%02x (%s) not implemented",
897 setup->bRequest, "SetPacketFilter");
898 return 0;
899 }
900
901 if (setup->bRequest == SET_NTB_INPUT_SIZE) {
902 LOG_DBG("bRequest 0x%02x (%s) not implemented",
903 setup->bRequest, "SetNtbInputSize");
904 return 0;
905 }
906
907 if (setup->bRequest == SET_NTB_FORMAT) {
908 LOG_DBG("bRequest 0x%02x (%s) not implemented",
909 setup->bRequest, "SetNtbFormat");
910 return 0;
911 }
912 }
913
914 LOG_DBG("bmRequestType 0x%02x bRequest 0x%02x unsupported",
915 setup->bmRequestType, setup->bRequest);
916 errno = -ENOTSUP;
917
918 return 0;
919 }
920
usbd_cdc_ncm_cth(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)921 static int usbd_cdc_ncm_cth(struct usbd_class_data *const c_data,
922 const struct usb_setup_packet *const setup,
923 struct net_buf *const buf)
924 {
925 LOG_DBG("%d: %d %d %d %d", setup->RequestType.type, setup->bRequest,
926 setup->wLength, setup->wIndex, setup->wValue);
927
928 if (setup->RequestType.type != USB_REQTYPE_TYPE_CLASS) {
929 errno = ENOTSUP;
930 goto out;
931 }
932
933 switch (setup->bRequest) {
934 case GET_NTB_PARAMETERS: {
935 struct ntb_parameters ntb_params = {
936 .wLength = sys_cpu_to_le16(sizeof(struct ntb_parameters)),
937 .bmNtbFormatsSupported = sys_cpu_to_le16(NTB_FORMAT_SUPPORTED),
938 .dwNtbInMaxSize = sys_cpu_to_le32(CDC_NCM_SEND_NTB_MAX_SIZE),
939 .wNdbInDivisor = sys_cpu_to_le16(4),
940 .wNdbInPayloadRemainder = sys_cpu_to_le16(0),
941 .wNdbInAlignment = sys_cpu_to_le16(CDC_NCM_ALIGNMENT),
942 .wReserved = sys_cpu_to_le16(0),
943 .dwNtbOutMaxSize = sys_cpu_to_le32(CDC_NCM_RECV_NTB_MAX_SIZE),
944 .wNdbOutDivisor = sys_cpu_to_le16(4),
945 .wNdbOutPayloadRemainder = sys_cpu_to_le16(0),
946 .wNdbOutAlignment = sys_cpu_to_le16(CDC_NCM_ALIGNMENT),
947 .wNtbOutMaxDatagrams = sys_cpu_to_le16(CDC_NCM_RECV_MAX_DATAGRAMS_PER_NTB),
948 };
949
950 LOG_DBG("GET_NTB_PARAMETERS");
951 net_buf_add_mem(buf, &ntb_params, sizeof(ntb_params));
952 break;
953 }
954
955 case GET_NTB_INPUT_SIZE: {
956 struct ntb_input_size input_size = {
957 .dwNtbInMaxSize = sys_cpu_to_le32(CDC_NCM_SEND_NTB_MAX_SIZE),
958 .wNtbInMaxDatagrams = sys_cpu_to_le16(CDC_NCM_SEND_MAX_DATAGRAMS_PER_NTB),
959 .wReserved = sys_cpu_to_le16(0),
960 };
961
962 LOG_DBG("GET_NTB_INPUT_SIZE");
963 net_buf_add_mem(buf, &input_size, sizeof(input_size));
964 break;
965 }
966
967 default:
968 LOG_DBG("bRequest 0x%02x not supported", setup->bRequest);
969 errno = ENOTSUP;
970 break;
971 }
972
973 out:
974 return 0;
975 }
976
usbd_cdc_ncm_init(struct usbd_class_data * const c_data)977 static int usbd_cdc_ncm_init(struct usbd_class_data *const c_data)
978 {
979 struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
980 const struct device *dev = usbd_class_get_private(c_data);
981 struct cdc_ncm_eth_data *const data = dev->data;
982 struct usbd_cdc_ncm_desc *desc = data->desc;
983 uint8_t if_num = desc->if0.bInterfaceNumber;
984
985 /* Update relevant b*Interface fields */
986 desc->iad.bFirstInterface = if_num;
987 desc->if0_union.bControlInterface = if_num;
988 desc->if0_union.bSubordinateInterface0 = if_num + 1;
989
990 LOG_DBG("CDC NCM class initialized");
991
992 if (usbd_add_descriptor(uds_ctx, data->mac_desc_data)) {
993 LOG_ERR("Failed to add iMACAddress string descriptor");
994 } else {
995 desc->if0_ecm.iMACAddress = usbd_str_desc_get_idx(data->mac_desc_data);
996 }
997
998 return 0;
999 }
1000
usbd_cdc_ncm_shutdown(struct usbd_class_data * const c_data)1001 static void usbd_cdc_ncm_shutdown(struct usbd_class_data *const c_data)
1002 {
1003 const struct device *dev = usbd_class_get_private(c_data);
1004 struct cdc_ncm_eth_data *const data = dev->data;
1005 struct usbd_cdc_ncm_desc *desc = data->desc;
1006
1007 desc->if0_ecm.iMACAddress = 0;
1008 sys_dlist_remove(&data->mac_desc_data->node);
1009 }
1010
usbd_cdc_ncm_get_desc(struct usbd_class_data * const c_data,const enum usbd_speed speed)1011 static void *usbd_cdc_ncm_get_desc(struct usbd_class_data *const c_data,
1012 const enum usbd_speed speed)
1013 {
1014 const struct device *dev = usbd_class_get_private(c_data);
1015 struct cdc_ncm_eth_data *const data = dev->data;
1016
1017 if (USBD_SUPPORTS_HIGH_SPEED && speed == USBD_SPEED_HS) {
1018 return data->hs_desc;
1019 }
1020
1021 return data->fs_desc;
1022 }
1023
cdc_ncm_send(const struct device * dev,struct net_pkt * const pkt)1024 static int cdc_ncm_send(const struct device *dev, struct net_pkt *const pkt)
1025 {
1026 struct cdc_ncm_eth_data *const data = dev->data;
1027 struct usbd_class_data *c_data = data->c_data;
1028 size_t len = net_pkt_get_len(pkt);
1029 struct net_buf *buf;
1030 union send_ntb *ntb;
1031
1032 if (len > NET_ETH_MAX_FRAME_SIZE) {
1033 LOG_WRN("Trying to send too large packet, drop");
1034 return -ENOMEM;
1035 }
1036
1037 if (!atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED) ||
1038 !atomic_test_bit(&data->state, CDC_NCM_IFACE_UP)) {
1039 LOG_DBG("Configuration is not enabled or interface not ready (%d / %d)",
1040 atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED),
1041 atomic_test_bit(&data->state, CDC_NCM_IFACE_UP));
1042 return -EACCES;
1043 }
1044
1045 buf = cdc_ncm_buf_alloc(cdc_ncm_get_bulk_in(c_data));
1046 if (buf == NULL) {
1047 LOG_ERR("Failed to allocate buffer");
1048 return -ENOMEM;
1049 }
1050
1051 ntb = (union send_ntb *)buf->data;
1052
1053 ntb->nth.dwSignature = sys_cpu_to_le32(NTH16_SIGNATURE);
1054 ntb->nth.wHeaderLength = sys_cpu_to_le16(sizeof(struct nth16));
1055 ntb->nth.wSequence = sys_cpu_to_le16(++data->tx_seq);
1056 ntb->nth.wNdpIndex = sys_cpu_to_le16(sizeof(struct nth16));
1057 ntb->ndp.dwSignature = sys_cpu_to_le32(NDP16_SIGNATURE_NCM0);
1058 ntb->ndp.wLength = sys_cpu_to_le16(sizeof(struct ndp16) +
1059 (CDC_NCM_SEND_MAX_DATAGRAMS_PER_NTB + 1) *
1060 sizeof(struct ndp16_datagram));
1061 ntb->ndp.wNextNdpIndex = 0;
1062 ntb->ndp_datagram[0].wDatagramIndex =
1063 sys_cpu_to_le16(sys_le16_to_cpu(ntb->nth.wHeaderLength) +
1064 sys_le16_to_cpu(ntb->ndp.wLength));
1065 ntb->ndp_datagram[0].wDatagramLength = sys_cpu_to_le16(len);
1066 ntb->ndp_datagram[1].wDatagramIndex = 0;
1067 ntb->ndp_datagram[1].wDatagramLength = 0;
1068 ntb->nth.wBlockLength = sys_cpu_to_le16(
1069 sys_le16_to_cpu(ntb->ndp_datagram[0].wDatagramIndex) + len);
1070
1071 net_buf_add(buf, sys_le16_to_cpu(ntb->ndp_datagram[0].wDatagramIndex));
1072
1073 if (net_pkt_read(pkt, buf->data + buf->len, len)) {
1074 LOG_ERR("Failed copy net_pkt");
1075 net_buf_unref(buf);
1076
1077 return -ENOBUFS;
1078 }
1079
1080 net_buf_add(buf, len);
1081
1082 if (sys_le16_to_cpu(ntb->nth.wBlockLength) % cdc_ncm_get_bulk_in_mps(c_data) == 0) {
1083 udc_ep_buf_set_zlp(buf);
1084 }
1085
1086 usbd_ep_enqueue(c_data, buf);
1087 k_sem_take(&data->sync_sem, K_FOREVER);
1088
1089 net_buf_unref(buf);
1090
1091 return 0;
1092 }
1093
cdc_ncm_set_config(const struct device * dev,const enum ethernet_config_type type,const struct ethernet_config * config)1094 static int cdc_ncm_set_config(const struct device *dev,
1095 const enum ethernet_config_type type,
1096 const struct ethernet_config *config)
1097 {
1098 struct cdc_ncm_eth_data *data = dev->data;
1099
1100 if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
1101 memcpy(data->mac_addr, config->mac_address.addr,
1102 sizeof(data->mac_addr));
1103
1104 return 0;
1105 }
1106
1107 return -ENOTSUP;
1108 }
1109
cdc_ncm_get_capabilities(const struct device * dev)1110 static enum ethernet_hw_caps cdc_ncm_get_capabilities(const struct device *dev)
1111 {
1112 ARG_UNUSED(dev);
1113
1114 return ETHERNET_LINK_10BASE;
1115 }
1116
cdc_ncm_iface_start(const struct device * dev)1117 static int cdc_ncm_iface_start(const struct device *dev)
1118 {
1119 struct cdc_ncm_eth_data *data = dev->data;
1120
1121 LOG_DBG("Start interface %d", net_if_get_by_iface(data->iface));
1122
1123 atomic_set_bit(&data->state, CDC_NCM_IFACE_UP);
1124 net_if_carrier_on(data->iface);
1125
1126 if (atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED)) {
1127 (void)k_work_reschedule(&data->notif_work, K_MSEC(1));
1128 }
1129
1130 return 0;
1131 }
1132
cdc_ncm_iface_stop(const struct device * dev)1133 static int cdc_ncm_iface_stop(const struct device *dev)
1134 {
1135 struct cdc_ncm_eth_data *data = dev->data;
1136
1137 LOG_DBG("Stop interface %d", net_if_get_by_iface(data->iface));
1138
1139 atomic_clear_bit(&data->state, CDC_NCM_IFACE_UP);
1140
1141 if (atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED)) {
1142 (void)k_work_reschedule(&data->notif_work, K_MSEC(1));
1143 }
1144
1145 return 0;
1146 }
1147
cdc_ncm_iface_init(struct net_if * const iface)1148 static void cdc_ncm_iface_init(struct net_if *const iface)
1149 {
1150 const struct device *dev = net_if_get_device(iface);
1151 struct cdc_ncm_eth_data *data = dev->data;
1152
1153 data->iface = iface;
1154 ethernet_init(iface);
1155 net_if_set_link_addr(iface, data->mac_addr,
1156 sizeof(data->mac_addr),
1157 NET_LINK_ETHERNET);
1158
1159 net_if_carrier_off(iface);
1160
1161 LOG_DBG("CDC NCM interface initialized");
1162 }
1163
usbd_cdc_ncm_preinit(const struct device * dev)1164 static int usbd_cdc_ncm_preinit(const struct device *dev)
1165 {
1166 struct cdc_ncm_eth_data *data = dev->data;
1167
1168 k_work_init_delayable(&data->notif_work, send_notification_work);
1169
1170 if (sys_get_le48(data->mac_addr) == sys_cpu_to_le48(0)) {
1171 gen_random_mac(data->mac_addr, 0, 0, 0);
1172 }
1173
1174 LOG_DBG("CDC NCM device initialized");
1175
1176 return 0;
1177 }
1178
1179 static struct usbd_class_api usbd_cdc_ncm_api = {
1180 .request = usbd_cdc_ncm_request,
1181 .update = usbd_cdc_ncm_update,
1182 .enable = usbd_cdc_ncm_enable,
1183 .disable = usbd_cdc_ncm_disable,
1184 .suspended = usbd_cdc_ncm_suspended,
1185 .resumed = usbd_cdc_ncm_resumed,
1186 .control_to_dev = usbd_cdc_ncm_ctd,
1187 .control_to_host = usbd_cdc_ncm_cth,
1188 .init = usbd_cdc_ncm_init,
1189 .shutdown = usbd_cdc_ncm_shutdown,
1190 .get_desc = usbd_cdc_ncm_get_desc,
1191 };
1192
1193 static const struct ethernet_api cdc_ncm_eth_api = {
1194 .iface_api.init = cdc_ncm_iface_init,
1195 .set_config = cdc_ncm_set_config,
1196 .get_capabilities = cdc_ncm_get_capabilities,
1197 .send = cdc_ncm_send,
1198 .start = cdc_ncm_iface_start,
1199 .stop = cdc_ncm_iface_stop,
1200 };
1201
1202 #define CDC_NCM_DEFINE_DESCRIPTOR(n) \
1203 static struct usbd_cdc_ncm_desc cdc_ncm_desc_##n = { \
1204 .iad = { \
1205 .bLength = sizeof(struct usb_association_descriptor), \
1206 .bDescriptorType = USB_DESC_INTERFACE_ASSOC, \
1207 .bFirstInterface = 0, \
1208 .bInterfaceCount = 0x02, \
1209 .bFunctionClass = USB_BCC_CDC_CONTROL, \
1210 .bFunctionSubClass = NCM_SUBCLASS, \
1211 .bFunctionProtocol = 0, \
1212 .iFunction = 0, \
1213 }, \
1214 \
1215 .if0 = { \
1216 .bLength = sizeof(struct usb_if_descriptor), \
1217 .bDescriptorType = USB_DESC_INTERFACE, \
1218 .bInterfaceNumber = 0, \
1219 .bAlternateSetting = 0, \
1220 .bNumEndpoints = 1, \
1221 .bInterfaceClass = USB_BCC_CDC_CONTROL, \
1222 .bInterfaceSubClass = NCM_SUBCLASS, \
1223 .bInterfaceProtocol = 0, \
1224 .iInterface = 0, \
1225 }, \
1226 \
1227 .if0_header = { \
1228 .bFunctionLength = sizeof(struct cdc_header_descriptor), \
1229 .bDescriptorType = USB_DESC_CS_INTERFACE, \
1230 .bDescriptorSubtype = HEADER_FUNC_DESC, \
1231 .bcdCDC = sys_cpu_to_le16(USB_SRN_1_1), \
1232 }, \
1233 \
1234 .if0_union = { \
1235 .bFunctionLength = sizeof(struct cdc_union_descriptor), \
1236 .bDescriptorType = USB_DESC_CS_INTERFACE, \
1237 .bDescriptorSubtype = UNION_FUNC_DESC, \
1238 .bControlInterface = 0, \
1239 .bSubordinateInterface0 = 1, \
1240 }, \
1241 \
1242 .if0_ecm = { \
1243 .bFunctionLength = sizeof(struct cdc_ecm_descriptor), \
1244 .bDescriptorType = USB_DESC_CS_INTERFACE, \
1245 .bDescriptorSubtype = ETHERNET_FUNC_DESC, \
1246 .iMACAddress = 4, \
1247 .bmEthernetStatistics = sys_cpu_to_le32(0), \
1248 .wMaxSegmentSize = sys_cpu_to_le16(NET_ETH_MAX_FRAME_SIZE), \
1249 .wNumberMCFilters = sys_cpu_to_le16(0), \
1250 .bNumberPowerFilters = 0, \
1251 }, \
1252 \
1253 .if0_ncm = { \
1254 .bFunctionLength = sizeof(struct cdc_ncm_descriptor), \
1255 .bDescriptorType = USB_DESC_CS_INTERFACE, \
1256 .bDescriptorSubtype = ETHERNET_FUNC_DESC_NCM, \
1257 .bcdNcmVersion = sys_cpu_to_le16(0x100), \
1258 .bmNetworkCapabilities = 0, \
1259 }, \
1260 \
1261 .if0_int_ep = { \
1262 .bLength = sizeof(struct usb_ep_descriptor), \
1263 .bDescriptorType = USB_DESC_ENDPOINT, \
1264 .bEndpointAddress = 0x81, \
1265 .bmAttributes = USB_EP_TYPE_INTERRUPT, \
1266 .wMaxPacketSize = sys_cpu_to_le16(CDC_NCM_EP_MPS_INT), \
1267 .bInterval = CDC_NCM_FS_INT_EP_INTERVAL, \
1268 }, \
1269 \
1270 .if0_hs_int_ep = { \
1271 .bLength = sizeof(struct usb_ep_descriptor), \
1272 .bDescriptorType = USB_DESC_ENDPOINT, \
1273 .bEndpointAddress = 0x82, \
1274 .bmAttributes = USB_EP_TYPE_INTERRUPT, \
1275 .wMaxPacketSize = sys_cpu_to_le16(CDC_NCM_EP_MPS_INT), \
1276 .bInterval = CDC_NCM_HS_INT_EP_INTERVAL, \
1277 }, \
1278 \
1279 .if1_0 = { \
1280 .bLength = sizeof(struct usb_if_descriptor), \
1281 .bDescriptorType = USB_DESC_INTERFACE, \
1282 .bInterfaceNumber = 1, \
1283 .bAlternateSetting = 0, \
1284 .bNumEndpoints = 0, \
1285 .bInterfaceClass = USB_BCC_CDC_DATA, \
1286 .bInterfaceSubClass = 0, \
1287 .bInterfaceProtocol = NCM_DATA_PROTOCOL, \
1288 .iInterface = 0, \
1289 }, \
1290 \
1291 .if1_1 = { \
1292 .bLength = sizeof(struct usb_if_descriptor), \
1293 .bDescriptorType = USB_DESC_INTERFACE, \
1294 .bInterfaceNumber = 1, \
1295 .bAlternateSetting = 1, \
1296 .bNumEndpoints = 2, \
1297 .bInterfaceClass = USB_BCC_CDC_DATA, \
1298 .bInterfaceSubClass = 0, \
1299 .bInterfaceProtocol = NCM_DATA_PROTOCOL, \
1300 .iInterface = 0, \
1301 }, \
1302 \
1303 .if1_1_in_ep = { \
1304 .bLength = sizeof(struct usb_ep_descriptor), \
1305 .bDescriptorType = USB_DESC_ENDPOINT, \
1306 .bEndpointAddress = 0x81, \
1307 .bmAttributes = USB_EP_TYPE_BULK, \
1308 .wMaxPacketSize = sys_cpu_to_le16(64U), \
1309 .bInterval = 0, \
1310 }, \
1311 \
1312 .if1_1_out_ep = { \
1313 .bLength = sizeof(struct usb_ep_descriptor), \
1314 .bDescriptorType = USB_DESC_ENDPOINT, \
1315 .bEndpointAddress = 0x01, \
1316 .bmAttributes = USB_EP_TYPE_BULK, \
1317 .wMaxPacketSize = sys_cpu_to_le16(64U), \
1318 .bInterval = 0, \
1319 }, \
1320 \
1321 .if1_1_hs_in_ep = { \
1322 .bLength = sizeof(struct usb_ep_descriptor), \
1323 .bDescriptorType = USB_DESC_ENDPOINT, \
1324 .bEndpointAddress = 0x82, \
1325 .bmAttributes = USB_EP_TYPE_BULK, \
1326 .wMaxPacketSize = sys_cpu_to_le16(512U), \
1327 .bInterval = 0, \
1328 }, \
1329 \
1330 .if1_1_hs_out_ep = { \
1331 .bLength = sizeof(struct usb_ep_descriptor), \
1332 .bDescriptorType = USB_DESC_ENDPOINT, \
1333 .bEndpointAddress = 0x02, \
1334 .bmAttributes = USB_EP_TYPE_BULK, \
1335 .wMaxPacketSize = sys_cpu_to_le16(512U), \
1336 .bInterval = 0, \
1337 }, \
1338 \
1339 .nil_desc = { \
1340 .bLength = 0, \
1341 .bDescriptorType = 0, \
1342 }, \
1343 }; \
1344 \
1345 const static struct usb_desc_header *cdc_ncm_fs_desc_##n[] = { \
1346 (struct usb_desc_header *) &cdc_ncm_desc_##n.iad, \
1347 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0, \
1348 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_header, \
1349 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_union, \
1350 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_ecm, \
1351 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_ncm, \
1352 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_int_ep, \
1353 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_0, \
1354 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1, \
1355 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1_in_ep, \
1356 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1_out_ep, \
1357 (struct usb_desc_header *) &cdc_ncm_desc_##n.nil_desc, \
1358 }; \
1359 \
1360 const static struct usb_desc_header *cdc_ncm_hs_desc_##n[] = { \
1361 (struct usb_desc_header *) &cdc_ncm_desc_##n.iad, \
1362 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0, \
1363 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_header, \
1364 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_union, \
1365 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_ecm, \
1366 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_ncm, \
1367 (struct usb_desc_header *) &cdc_ncm_desc_##n.if0_hs_int_ep, \
1368 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_0, \
1369 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1, \
1370 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1_hs_in_ep, \
1371 (struct usb_desc_header *) &cdc_ncm_desc_##n.if1_1_hs_out_ep, \
1372 (struct usb_desc_header *) &cdc_ncm_desc_##n.nil_desc, \
1373 }
1374
1375 #define USBD_CDC_NCM_DT_DEVICE_DEFINE(n) \
1376 CDC_NCM_DEFINE_DESCRIPTOR(n); \
1377 USBD_DESC_STRING_DEFINE(mac_desc_data_##n, \
1378 DT_INST_PROP(n, remote_mac_address), \
1379 USBD_DUT_STRING_INTERFACE); \
1380 \
1381 USBD_DEFINE_CLASS(cdc_ncm_##n, \
1382 &usbd_cdc_ncm_api, \
1383 (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL); \
1384 \
1385 static struct cdc_ncm_eth_data eth_data_##n = { \
1386 .c_data = &cdc_ncm_##n, \
1387 .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
1388 .sync_sem = Z_SEM_INITIALIZER(eth_data_##n.sync_sem, 0, 1), \
1389 .mac_desc_data = &mac_desc_data_##n, \
1390 .desc = &cdc_ncm_desc_##n, \
1391 .fs_desc = cdc_ncm_fs_desc_##n, \
1392 .hs_desc = cdc_ncm_hs_desc_##n, \
1393 }; \
1394 \
1395 ETH_NET_DEVICE_DT_INST_DEFINE(n, usbd_cdc_ncm_preinit, NULL, \
1396 ð_data_##n, NULL, \
1397 CONFIG_ETH_INIT_PRIORITY, \
1398 &cdc_ncm_eth_api, \
1399 NET_ETH_MTU);
1400
1401 DT_INST_FOREACH_STATUS_OKAY(USBD_CDC_NCM_DT_DEVICE_DEFINE);
1402