/* * Copyright (c) 2024, sakumisu * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "usbh_core.h" // #define CONFIG_USBHOST_PLATFORM_CDC_ECM #define CONFIG_USBHOST_PLATFORM_CDC_RNDIS // #define CONFIG_USBHOST_PLATFORM_CDC_NCM // #define CONFIG_USBHOST_PLATFORM_ASIX // #define CONFIG_USBHOST_PLATFORM_RTL8152 struct usbh_net { struct net_driver_s netdev; struct work_s txpollwork; bool linkup; }; void usbh_net_eth_output_common(struct net_driver_s *dev, uint8_t *buf) { usb_memcpy(buf, dev->d_buf, dev->d_len); } void usbh_net_eth_input_common(struct net_driver_s *dev, uint8_t *buf, size_t len, int (*eth_output)(uint32_t buflen)) { FAR struct eth_hdr_s *hdr; net_lock(); NETDEV_RXPACKETS(dev); /* Any ACK or other response packet generated by the network stack * will always be shorter than the received packet, therefore it is * safe to pass the received frame buffer directly. */ dev->d_buf = buf; dev->d_len = len; hdr = (FAR struct eth_hdr_s *)dev->d_buf; #ifdef CONFIG_NET_IPv4 if (hdr->type == HTONS(ETHTYPE_IP)) { NETDEV_RXIPV4(dev); /* Receive an IPv4 packet from the network device */ ipv4_input(dev); if (dev->d_len > 0) { /* And send the packet */ usbh_net_eth_output_common(dev, usbh_rndis_get_eth_txbuf()); eth_output(dev->d_len); } } else #endif #ifdef CONFIG_NET_IPv6 if (hdr->type == HTONS(ETHTYPE_IP6)) { NETDEV_RXIPV6(dev); /* Give the IPv6 packet to the network layer */ ipv6_input(dev); if (dev->d_len > 0) { /* And send the packet */ usbh_net_eth_output_common(dev, usbh_rndis_get_eth_txbuf()); eth_output(dev->d_len); } } else #endif #ifdef CONFIG_NET_ARP if (hdr->type == HTONS(ETHTYPE_ARP)) { NETDEV_RXARP(dev); arp_input(dev); if (dev->d_len > 0) { usbh_net_eth_output_common(dev, usbh_rndis_get_eth_txbuf()); eth_output(dev->d_len); } } else #endif { NETDEV_RXDROPPED(dev); } net_unlock(); } #ifdef CONFIG_USBHOST_PLATFORM_CDC_RNDIS #include "usbh_rndis.h" struct usbh_net g_rndis_dev; static int rndis_ifup(struct net_driver_s *dev) { printf("rndis if up\r\n"); g_rndis_dev.linkup = true; usb_osal_thread_create("usbh_rndis_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, NULL); return OK; } static int rndis_ifdown(struct net_driver_s *dev) { printf("rndis if down\r\n"); g_rndis_dev.linkup = false; return OK; } static int rndis_txpoll(struct net_driver_s *dev) { usbh_net_eth_output_common(&g_rndis_dev, usbh_rndis_get_eth_txbuf()); return usbh_rndis_eth_output(g_rndis_dev.netdev.d_len); } static void rndis_txavail_work(void *arg) { net_lock(); if (g_rndis_dev.linkup) { devif_poll(&g_rndis_dev.netdev, rndis_txpoll); } else { } net_unlock(); } static int rndis_txavail(struct net_driver_s *dev) { if (work_available(&g_rndis_dev.txpollwork)) { work_queue(LPWORK, &g_rndis_dev.txpollwork, rndis_txavail_work, NULL, 0); } else { return -1; } return OK; } void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen) { usbh_net_eth_input_common(&g_rndis_dev.netdev, buf, buflen, usbh_rndis_eth_output); } void usbh_rndis_run(struct usbh_rndis *rndis_class) { memset(&g_rndis_dev.netdev, 0, sizeof(struct net_driver_s)); g_rndis_dev.netdev.d_ifup = rndis_ifup; g_rndis_dev.netdev.d_ifdown = rndis_ifdown; g_rndis_dev.netdev.d_txavail = rndis_txavail; g_rndis_dev.netdev.d_private = rndis_class; for (uint8_t j = 0; j < 6; j++) { g_rndis_dev.netdev.d_mac.ether.ether_addr_octet[j] = rndis_class->mac[j]; } netdev_register(&g_rndis_dev.netdev, NET_LL_ETHERNET); } void usbh_rndis_stop(struct usbh_rndis *rndis_class) { } #endif