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