diff --git a/OAT.xml b/OAT.xml
index 00f6be9157cf78d625d6caccccbe0db740a4f2cf..560bf567b1ab74619d130e5689bd55393c6b2bbb 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -67,6 +67,7 @@ Note:If the text contains special characters, please escape them according to th
+
diff --git a/adapter/khdf/linux/model/usb/host/Makefile b/adapter/khdf/linux/model/usb/host/Makefile
index 4a392d9a83c9edd5091e81fdf320d2f8f3637ec1..afd1a6eed95405fbf46620018ffb6c8064356c3f 100644
--- a/adapter/khdf/linux/model/usb/host/Makefile
+++ b/adapter/khdf/linux/model/usb/host/Makefile
@@ -11,7 +11,8 @@
USB_PNP_NOTIFY_ROOT_DIR = ./
obj-$(CONFIG_DRIVERS_HDF_USB_PNP_NOTIFY) += \
- $(USB_PNP_NOTIFY_ROOT_DIR)/src/usb_pnp_notify.o
+ $(USB_PNP_NOTIFY_ROOT_DIR)/src/usb_pnp_notify.o \
+ $(USB_PNP_NOTIFY_ROOT_DIR)/src/usb_net_adapter.o
ccflags-y += -lm -lc -lgcc \
-I$(srctree)/drivers/hdf/khdf/model/usb/host/include \
diff --git a/adapter/khdf/linux/model/usb/host/include/usb_net_adapter.h b/adapter/khdf/linux/model/usb/host/include/usb_net_adapter.h
new file mode 100755
index 0000000000000000000000000000000000000000..983b37167fc3d455246e95811fd7edbdee3f1f14
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/include/usb_net_adapter.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2024 Archermind Technology (Nanjing) Co. Ltd.
+ *
+ * HDF is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ * See the LICENSE file in the root of this repository for complete details.
+ */
+
+#ifndef HDF_NET_USB_ADAPTER_H
+#define HDF_NET_USB_ADAPTER_H
+
+#include "osal_mutex.h"
+#include "hdf_log.h"
+#include "hdf_usb_net_manager.h"
+
+#define MODULE_PARAM module_param
+#define HARCH_LOG_TAG "[-net-hdf-]"
+#define HARCH_NET_INFO_PRINT(fmt, ...) \
+do { \
+ if (1) { \
+ HDF_LOGI(HARCH_LOG_TAG"[%{public}s][%{public}d]:" fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__);} \
+} while (0)
+
+typedef struct pcpu_sw_netstats PcpuSwNetstats;
+typedef struct net_device NetDevice;
+typedef struct timer_list TimerList;
+typedef struct work_struct WorkStruct;
+typedef struct tasklet_struct TaskletStruct;
+typedef struct device_type DeviceType;
+typedef struct ethtool_ops EthtoolOps;
+typedef struct rndis_data_hdr RndisDataHdr;
+typedef struct sk_buff SkBuff;
+typedef struct sk_buff_head SkBuff_Head;
+typedef struct net_device_ops NetDevice_Ops;
+
+struct rndis_data_hdr {
+ __le32 msg_type; /* RNDIS_MSG_PACKET */
+ __le32 msg_len; /* rndis_data_hdr + data_len + pad */
+ __le32 data_offset; /* 36 -- right after header */
+ __le32 data_len; /* ... real packet size */
+
+ __le32 oob_data_offset; /* zero */
+ __le32 oob_data_len; /* zero */
+ __le32 num_oob; /* zero */
+ __le32 packet_data_offset; /* zero */
+
+ __le32 packet_data_len; /* zero */
+ __le32 vc_handle; /* zero */
+ __le32 reserved; /* zero */
+} __attribute__ ((packed));
+
+struct UsbnetAdapter {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *deviceObject;
+ unsigned canDmaSg : 1;
+ NetDevice *net;
+ int32_t msg_enable;
+ struct UsbnetTransInfo usbnetInfo;
+ struct OsalMutex sendSkbClock;
+
+ unsigned char pktCnt, pktErr;
+
+ /* various kinds of pending driver work */
+ wait_queue_head_t wait;
+ TimerList delay;
+
+ SkBuff_Head rxq;
+ SkBuff_Head txq;
+
+ SkBuff_Head done;
+ SkBuff_Head rxq_pause;
+ TaskletStruct bh;
+
+ struct pcpu_sw_netstats __percpu *stats64;
+
+ WorkStruct kevent;
+ WorkStruct TxCompleteWorkqueue;
+ WorkStruct RxCompleteWorkqueue;
+ unsigned int txLen;
+ unsigned int rxLen;
+ unsigned long flags;
+# define EVENT_TX_HALT 0
+# define EVENT_RX_HALT 1
+# define EVENT_RX_MEMORY 2
+# define EVENT_STS_SPLIT 3
+# define EVENT_LINK_RESET 4
+# define EVENT_RX_PAUSED 5
+# define EVENT_DEV_ASLEEP 6
+# define EVENT_DEV_OPEN 7
+# define EVENT_DEVICE_REPORT_IDLE 8
+# define EVENT_NO_RUNTIME_PM 9
+# define EVENT_RX_KILL 10
+# define EVENT_LINK_CHANGE 11
+# define EVENT_SET_RX_MODE 12
+# define EVENT_NO_IP_ALIGN 13
+};
+
+/* we record the state for each of our queued skbs */
+enum SkbState {
+ ILLEGAL = 0,
+ TX_START,
+ TX_DONE,
+ RX_START,
+ RX_DONE,
+ RX_CLEANUP,
+ UNLINK_START
+};
+
+struct SkbData { /* skb->cb is one of these */
+ enum SkbState state;
+ long length;
+ unsigned long packets;
+};
+
+#endif
diff --git a/adapter/khdf/linux/model/usb/host/src/usb_net_adapter.c b/adapter/khdf/linux/model/usb/host/src/usb_net_adapter.c
new file mode 100755
index 0000000000000000000000000000000000000000..f2c12f9586552e37594ce7c17d57ee8f4223acec
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/src/usb_net_adapter.c
@@ -0,0 +1,1206 @@
+/*
+ * Copyright (c) 2024 Archermind Technology (Nanjing) Co. Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#if defined(CONFIG_DRIVERS_HDF_IMX8MM_ETHERNET)
+#include
+#include
+#endif
+
+#include
+#include
+#include "osal_mem.h"
+#include "securec.h"
+
+#include "hdf_device_desc.h"
+#include "usb_net_adapter.h"
+
+#define HDF_LOG_TAG UsbnetAdapter
+#define TX_TIMEOUT_JIFFIES (5*HZ)
+#define RNDIS_MSG_PACKET 0x00000001 /* 1-N packets */
+
+// between wakeups
+#define UNLINK_TIMEOUT_MS 3
+#define PKT_COUNT_CLEAR 30
+#define PKT_COUNT_RXKILL 20
+#define SHIFT_LINE_NUM 32
+
+/* use ethtool to change the level for any given device */
+static int g_msgLevel = -1;
+MODULE_PARAM(g_msgLevel, int, 0);
+MODULE_PARM_DESC(g_msgLevel, "Override default message level");
+
+static inline int UsbnetAdapterGetTxQlen(struct UsbnetAdapter *usbNet)
+{
+ return usbNet->usbnetInfo.txQlen;
+}
+
+static int printf_char_buffer(char *buff, int size, bool isPrint)
+{
+ if (isPrint) {
+ int i = 0;
+ printk("===-harch-=== printf_char_buffer begin\n");
+ for (i = 0; i < size; i++) {
+ printk(KERN_CONT"%02x ", buff[i]);
+ if ((i + 1) % SHIFT_LINE_NUM == 0) {
+ printk(KERN_CONT"\n");
+ }
+ }
+ printk("===-harch-=== printf_char_buffer end\n");
+ }
+ return 0;
+}
+
+static int32_t UsbnetAdapterSendBufToUsb(const struct HdfDeviceObject *device, uint32_t id,
+ const void *buf, uint32_t writeSize)
+{
+ HARCH_NET_INFO_PRINT("writeSize=%d", writeSize);
+ int32_t ret = HDF_SUCCESS;
+ if ((device == NULL) || (buf == NULL)) {
+ HDF_LOGE("%s param is null", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ struct HdfSBuf *data = HdfSbufObtainDefaultSize();
+ if (data == NULL) {
+ HDF_LOGE("fail to obtain sbuf data");
+ return HDF_FAILURE;
+ }
+
+ if (!HdfSbufWriteBuffer(data, buf, writeSize)) {
+ HDF_LOGE("fail to write sbuf");
+ ret = HDF_FAILURE;
+ goto out;
+ }
+
+ if (HdfDeviceSendEvent(device, id, data) != HDF_SUCCESS) {
+ HDF_LOGE("%s: send sensor data event failed", __func__);
+ ret = HDF_FAILURE;
+ goto out;
+ }
+ ret = HDF_SUCCESS;
+
+out:
+ HdfSbufRecycle(data);
+ return ret;
+}
+
+static void RxComplete(WorkStruct *work)
+{
+ unsigned long flags = 0;
+ struct UsbnetAdapter *usbNet = container_of(work, struct UsbnetAdapter, RxCompleteWorkqueue);
+ PcpuSwNetstats *stats64 = this_cpu_ptr(usbNet->stats64);
+
+ HARCH_NET_INFO_PRINT("rx_complete stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT("rx_complete stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+
+ flags = u64_stats_update_begin_irqsave(&stats64->syncp);
+ stats64->rx_packets++;
+ stats64->rx_bytes += usbNet->rxLen;
+ u64_stats_update_end_irqrestore(&stats64->syncp, flags);
+
+ HARCH_NET_INFO_PRINT("rx_complete stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT("rx_complete stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+}
+
+/* Passes this packet up the stack, updating its accounting.
+ * Some link protocols batch packets, so their rx_fixup paths
+ * can return clones as well as just modify the original skb.
+ */
+static void UsbnetAdapterSkbReturn(struct UsbnetAdapter *usbNet, SkBuff *skb)
+{
+ if (test_bit(EVENT_RX_PAUSED, &usbNet->flags)) {
+ skb_queue_tail(&usbNet->rxq_pause, skb);
+ return;
+ }
+
+ /* only update if unset to allow minidriver rx_fixup override */
+ if (skb->protocol == 0) {
+ skb->protocol = eth_type_trans (skb, usbNet->net);
+ }
+
+ usbNet->rxLen = skb->len;
+ schedule_work_on(0, &usbNet->RxCompleteWorkqueue);
+ HARCH_NET_INFO_PRINT("< rx, len %zu, type 0x%x\n", skb->len + sizeof (struct ethhdr), skb->protocol);
+ (void)memset_s(skb->cb, sizeof(struct SkbData), 0, sizeof(struct SkbData));
+
+ if (skb_defer_rx_timestamp(skb)) {
+ return;
+ }
+ HARCH_NET_INFO_PRINT("-------rx before netif_rx");
+ printf_char_buffer(skb->data, skb->len, false);
+
+ int status = NET_RX_SUCCESS;
+ status = netif_rx (skb);
+
+ HARCH_NET_INFO_PRINT("netif_rx status %d\n", status);
+ if (status != NET_RX_SUCCESS) {
+ HARCH_NET_INFO_PRINT("netif_rx status %d\n", status);
+ }
+}
+
+
+/*
+ * DATA -- host must not write zlps
+ */
+static int RndisRxFixup(struct UsbnetAdapter *usbNet, SkBuff *skb)
+{
+ /* This check is no longer done by usbnet */
+ if (skb->len < usbNet->net->hard_header_len) {
+ return 0;
+ }
+ /* peripheral may have batched packets to us... */
+ while (likely(skb->len)) {
+ RndisDataHdr *hdr = (void *)skb->data;
+ SkBuff *skb2 = NULL;
+ u32 msg_type = 0;
+ u32 msg_len = 0;
+ u32 data_len = 0;
+ u32 data_offset = 0;
+
+ msg_type = le32_to_cpu(hdr->msg_type);
+ msg_len = le32_to_cpu(hdr->msg_len);
+ data_offset = le32_to_cpu(hdr->data_offset);
+ data_len = le32_to_cpu(hdr->data_len);
+ unsigned int totalLen = data_offset + data_len + 8;
+
+ /* don't choke if we see oob, per-packet data, etc */
+ if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len
+ || totalLen > msg_len)) {
+ usbNet->net->stats.rx_frame_errors++;
+ netdev_dbg(usbNet->net, "bad rndis message %d/%d/%d/%d, len %d\n",
+ le32_to_cpu(hdr->msg_type), msg_len, data_offset, data_len, skb->len);
+ return 0;
+ }
+ unsigned int offset = 8 + data_offset;
+ skb_pull(skb, offset);
+
+ /* at most one packet left? */
+ if (likely((data_len - skb->len) <= sizeof(RndisDataHdr))) {
+ skb_trim(skb, data_len);
+ break;
+ }
+
+ /* try to return all the packets in the batch */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(!skb2)) {
+ break;
+ }
+ skb_pull(skb, msg_len - sizeof(RndisDataHdr));
+ skb_trim(skb2, data_len);
+ UsbnetAdapterSkbReturn(usbNet, skb2);
+ }
+ return 1;
+}
+
+static void UsbnetAdapterRxProcess(struct UsbnetAdapter *usbNet, SkBuff *skb)
+{
+ HARCH_NET_INFO_PRINT("-------rx before fix");
+ printf_char_buffer(skb->data, skb->len, false);
+
+ if (!RndisRxFixup(usbNet, skb)) {
+ /* With RX_ASSEMBLE, rx_fixup() must update counters */
+ if (!(usbNet->usbnetInfo.usbFlags & FLAG_RX_ASSEMBLE)) {
+ usbNet->net->stats.rx_errors++;
+ }
+ goto done;
+ }
+ // else network stack removes extra byte if we forced a short packet
+ HARCH_NET_INFO_PRINT("--------rx after fix");
+ printf_char_buffer(skb->data, skb->len, false);
+
+ /* all data was already cloned from skb inside the driver */
+ if (usbNet->usbnetInfo.usbFlags & FLAG_MULTI_PACKET) {
+ HARCH_NET_INFO_PRINT("usbNet->driver_info->flags = %d", usbNet->usbnetInfo.usbFlags);
+ goto done;
+ }
+
+ if (skb->len < ETH_HLEN) {
+ usbNet->net->stats.rx_errors++;
+ usbNet->net->stats.rx_length_errors++;
+ HARCH_NET_INFO_PRINT("rx length %d\n", skb->len);
+ } else {
+ HARCH_NET_INFO_PRINT("UsbnetAdapterSkbReturn");
+ UsbnetAdapterSkbReturn(usbNet, skb);
+ return;
+ }
+
+done:
+ skb_queue_tail(&usbNet->done, skb);
+}
+
+static void UsbnetAdapterBh(TimerList *t)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ struct UsbnetAdapter *usbNet = from_timer(usbNet, t, delay);
+
+ SkBuff *skb = NULL;
+ struct SkbData *entry = NULL;
+
+ while ((skb = skb_dequeue (&usbNet->done))) {
+ entry = (struct SkbData *) skb->cb;
+ HARCH_NET_INFO_PRINT("entry->state = %d", entry->state);
+
+ switch (entry->state) {
+ case RX_DONE:
+ HARCH_NET_INFO_PRINT("rx_done");
+ entry->state = RX_CLEANUP;
+ UsbnetAdapterRxProcess (usbNet, skb);
+ continue;
+ case TX_DONE:
+ HARCH_NET_INFO_PRINT("tx_done");
+ /* fall-through */
+ fallthrough;
+ case RX_CLEANUP:
+ HARCH_NET_INFO_PRINT("rx_cleanup");
+ dev_kfree_skb (skb);
+ continue;
+ default:
+ HARCH_NET_INFO_PRINT("bogus skb state %d\n", entry->state);
+ /* fall-through */
+ }
+ }
+ HARCH_NET_INFO_PRINT();
+ /* restart RX again after disabling due to high error rate */
+ clear_bit(EVENT_RX_KILL, &usbNet->flags);
+
+ /* waiting for all pending urbs to complete?
+ * only then can we forgo submitting anew
+ */
+ if (waitqueue_active(&usbNet->wait)) {
+ HARCH_NET_INFO_PRINT("waitqueue_active");
+ if (usbNet->rxq.qlen + usbNet->txq.qlen + usbNet->done.qlen == 0) {
+ HARCH_NET_INFO_PRINT();
+ wake_up_all(&usbNet->wait);
+ }
+ }
+
+ if (usbNet->txq.qlen < UsbnetAdapterGetTxQlen(usbNet)) {
+ netif_wake_queue (usbNet->net);
+ HARCH_NET_INFO_PRINT("usbNet->txq.qlen = %d, TX_QLEN (usbNet) = %d",
+ usbNet->txq.qlen, UsbnetAdapterGetTxQlen(usbNet));
+ }
+ HARCH_NET_INFO_PRINT("end");
+}
+
+static void UsbnetAdapterBhTasklet(unsigned long data)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ TimerList *t = (TimerList *)data;
+
+ UsbnetAdapterBh(t);
+ HARCH_NET_INFO_PRINT("end");
+}
+
+/* The caller must hold list->lock */
+static void UsbnetAdapterQueueSkb(SkBuff_Head *list,
+ SkBuff *newsk, enum SkbState state)
+{
+ struct SkbData *entry = (struct SkbData *) newsk->cb;
+
+ __skb_queue_tail(list, newsk);
+ entry->state = state;
+}
+
+static enum SkbState UsbnetAdapterDeferBh(struct UsbnetAdapter *usbNet, SkBuff *skb,
+ SkBuff_Head *list, enum SkbState state)
+{
+ unsigned long flags = 0;
+ enum SkbState old_state = ILLEGAL;
+ struct SkbData *entry = (struct SkbData *) skb->cb;
+
+ spin_lock_irqsave(&list->lock, flags);
+ old_state = entry->state;
+ entry->state = state;
+ __skb_unlink(skb, list);
+
+ /* UsbnetAdapterDeferBh() is never called with list == &usbNet->done.
+ * spin_lock_nested() tells lockdep that it is OK to take
+ * usbNet->done.lock here with list->lock held.
+ */
+ spin_lock_nested(&usbNet->done.lock, SINGLE_DEPTH_NESTING);
+
+ __skb_queue_tail(&usbNet->done, skb);
+ if (usbNet->done.qlen == 1) {
+ tasklet_schedule(&usbNet->bh);
+ }
+
+ spin_unlock(&usbNet->done.lock);
+ spin_unlock_irqrestore(&list->lock, flags);
+ return old_state;
+}
+
+static int32_t UsbnetAdapterOpen(NetDevice *net)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == net) {
+ HDF_LOGE("net device object is invalid");
+ return HDF_FAILURE;
+ }
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (NULL == usbNet) {
+ HDF_LOGE("usb net adapter object is invalid");
+ return HDF_FAILURE;
+ }
+
+ set_bit(EVENT_DEV_OPEN, &usbNet->flags);
+
+ netif_start_queue (net);
+
+ /* set device param, if find usb net host need, then it should send to it */
+ /* reset rx error state */
+ usbNet->pktCnt = 0;
+ usbNet->pktErr = 0;
+ clear_bit(EVENT_RX_KILL, &usbNet->flags);
+
+ /* send info to usb start usb function */
+ /* need transform usb_net_host change about usbNet->driverInfo->flags and set it on usb_net_host */
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_OPEN_USB,
+ (const void *)&usbNet->flags, sizeof(usbNet->flags));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return HDF_FAILURE;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+
+ tasklet_schedule (&usbNet->bh);
+ return HDF_SUCCESS;
+}
+
+static void WaitSkbQueueEmpty(SkBuff_Head *q)
+{
+ unsigned long flags = 0;
+ HARCH_NET_INFO_PRINT();
+ spin_lock_irqsave(&q->lock, flags);
+ while (!skb_queue_empty(q)) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ spin_lock_irqsave(&q->lock, flags);
+ }
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+// precondition: never called in_interrupt
+static void UsbnetAdapterTerminateUrbs(struct UsbnetAdapter *usbNet)
+{
+ HARCH_NET_INFO_PRINT();
+
+ DECLARE_WAITQUEUE(wait, current);
+ /* ensure there are no more active urbs */
+ add_wait_queue(&usbNet->wait, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ /* maybe wait for deletions to finish. */
+ WaitSkbQueueEmpty(&usbNet->rxq);
+ WaitSkbQueueEmpty(&usbNet->txq);
+
+ WaitSkbQueueEmpty(&usbNet->done);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&usbNet->wait, &wait);
+}
+
+static int32_t UsbnetAdapterStop(NetDevice *net)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == net) {
+ HDF_LOGE("net device object is invalid");
+ return HDF_FAILURE;
+ }
+
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (NULL == usbNet) {
+ HDF_LOGE("usb net adapter object is invalid");
+ return HDF_FAILURE;
+ }
+
+ PcpuSwNetstats *stats64 = this_cpu_ptr(usbNet->stats64);
+
+ HARCH_NET_INFO_PRINT("usbNet stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT("usbNet stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+
+ /* 1. clear_bit EVENT_DEV_OPEN dev->flags */
+ clear_bit(EVENT_DEV_OPEN, &usbNet->flags);
+ /* 2. netif_stop_queue net */
+ netif_stop_queue (net);
+ HARCH_NET_INFO_PRINT("stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
+ net->stats.rx_packets, net->stats.tx_packets,
+ net->stats.rx_errors, net->stats.tx_errors);
+
+ /* 3. pm = usb_autopm_get_interface(dev->intf); do nothing */
+ /* 4. if (info->stop) { no stop interface impl in rndis driver info */
+ /* 5. if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) do nothing*/
+ if (!(usbNet->usbnetInfo.usbFlags & FLAG_AVOID_UNLINK_URBS)) {
+ UsbnetAdapterTerminateUrbs(usbNet);
+ }
+
+ /* 6. usbnet_status_stop none */
+ /* 7. usbnet_purge_paused_rxq none */
+ skb_queue_purge(&usbNet->rxq_pause);
+ /* 8. test_and_clear_bit and no manage_power interface impl in rndis driver info*/
+ /* 9. dev flags */
+ usbNet->flags = 0;
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_CLOSE_USB,
+ (const void *)&usbNet->flags, sizeof(usbNet->flags));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return HDF_FAILURE;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ /* 10. del_timer_sync */
+ del_timer_sync (&usbNet->delay);
+ /* 11. tasklet_kill */
+ tasklet_kill (&usbNet->bh);
+ /* 12. cancel_work_sync dev->kevent */
+ cancel_work_sync(&usbNet->TxCompleteWorkqueue);
+ cancel_work_sync(&usbNet->RxCompleteWorkqueue);
+ return HDF_SUCCESS;
+}
+
+static SkBuff *RndisTxFixup(SkBuff *skb, gfp_t flags)
+{
+ RndisDataHdr *hdr = NULL;
+ SkBuff *skb2 = NULL;
+ unsigned len = skb->len;
+
+ if (likely(!skb_cloned(skb))) {
+ int room = skb_headroom(skb);
+ /* enough head room as-is? */
+ if (unlikely((sizeof(RndisDataHdr)) <= room)) {
+ goto fill;
+ }
+ /* enough room, but needs to be readjusted? */
+ room += skb_tailroom(skb);
+ if (likely((sizeof(RndisDataHdr)) <= room)) {
+ skb->data = memmove_s(skb->head + sizeof(RndisDataHdr), len, skb->data, len);
+ skb_set_tail_pointer(skb, len);
+ goto fill;
+ }
+ }
+
+ /* create a new skb, with the correct size (and tailpad) */
+ skb2 = skb_copy_expand(skb, sizeof(RndisDataHdr), 1, flags);
+ dev_kfree_skb_any(skb);
+ if (unlikely(!skb2)) {
+ return skb2;
+ }
+ skb = skb2;
+
+ /* fill out the RNDIS header. we won't bother trying to batch
+ * packets; Linux minimizes wasted bandwidth through tx queues.
+ */
+fill:
+ HARCH_NET_INFO_PRINT("%s:%d fill skb by rndis host", __func__, __LINE__);
+ hdr = __skb_push(skb, sizeof(*hdr));
+ (void)memset_s(hdr, sizeof(*hdr), 0, sizeof(*hdr));
+ hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET);
+ hdr->msg_len = cpu_to_le32(skb->len);
+ unsigned int offset = sizeof(*hdr) - 8;
+ hdr->data_offset = cpu_to_le32(offset);
+ hdr->data_len = cpu_to_le32(len);
+
+ return skb;
+}
+
+static void TxComplete(WorkStruct *work)
+{
+ unsigned long flags = 0;
+ struct UsbnetAdapter *usbNet = container_of(work, struct UsbnetAdapter, TxCompleteWorkqueue);
+ PcpuSwNetstats *stats64 = this_cpu_ptr(usbNet->stats64);
+ HARCH_NET_INFO_PRINT ("tx_complete stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT ("tx_complete stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+
+ flags = u64_stats_update_begin_irqsave(&stats64->syncp);
+ stats64->tx_packets++;
+ stats64->tx_bytes += usbNet->txLen;
+ u64_stats_update_end_irqrestore(&stats64->syncp, flags);
+
+ HARCH_NET_INFO_PRINT ("tx_complete stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT ("tx_complete stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+}
+
+static netdev_tx_t UsbnetAdapterStartXmit(SkBuff *skb, NetDevice *net)
+{
+ HARCH_NET_INFO_PRINT ("netif_running=%d, netif_device_present=%d, netif_carrier_ok=%d", netif_running(net),
+ netif_device_present(net), netif_carrier_ok(net));
+ HARCH_NET_INFO_PRINT ("skb->data = %x, len = %d", skb->data, skb->len);
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ //1.time tamp
+ if (skb) {
+ skb_tx_timestamp(skb);
+ }
+ //2.fix up
+ SkBuff* skbFixup = RndisTxFixup(skb, GFP_ATOMIC);
+ if (NULL == skbFixup) {
+ if (usbNet->usbnetInfo.usbFlags & FLAG_MULTI_PACKET) {
+ goto not_drop;
+ }
+ HDF_LOGE("fail to tx fixup by rndis host");
+ goto drop;
+ }
+ HARCH_NET_INFO_PRINT("skb_fixup->data = %x, len = %d", skbFixup->data, skbFixup->len);
+ /* print org skb data info */
+ printf_char_buffer(skbFixup->data, skbFixup->len, false);
+ //3.send msg to usb
+ unsigned long flags = 0;
+ spin_lock_irqsave(&usbNet->txq.lock, flags);
+ if (netif_queue_stopped(usbNet->net)) {
+ goto drop;
+ }
+
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_SEND_DATA_TO_USB,
+ (unsigned char *)(skbFixup->data), skbFixup->len);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetHost SendEvent!");
+drop:
+ net->stats.tx_dropped++;
+not_drop:
+ spin_unlock_irqrestore(&usbNet->txq.lock, flags);
+ if (skbFixup) {
+ dev_kfree_skb_any (skbFixup);
+ }
+ } else {
+ netif_trans_update(usbNet->net);
+ UsbnetAdapterQueueSkb(&usbNet->txq, skbFixup, TX_START);
+
+ if (usbNet->txq.qlen >= UsbnetAdapterGetTxQlen(usbNet)) {
+ HARCH_NET_INFO_PRINT("usbNet->txq.qlen = %d, TX_QLEN (usbNet) = %d",
+ usbNet->txq.qlen, UsbnetAdapterGetTxQlen(usbNet));
+ netif_stop_queue (usbNet->net);
+ }
+ spin_unlock_irqrestore(&usbNet->txq.lock, flags);
+ usbNet->txLen = skbFixup->len;
+ schedule_work_on(0, &usbNet->TxCompleteWorkqueue);
+
+ enum SkbState state = UsbnetAdapterDeferBh(usbNet, skbFixup, &usbNet->txq, TX_DONE);
+ HARCH_NET_INFO_PRINT("state= %d", state);
+ }
+ return NETDEV_TX_OK;
+}
+
+static void UsbnetAdapterTXTimeout(NetDevice *net, unsigned int txqueue)
+{
+ //send to device
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == net) {
+ HDF_LOGE("%s net device object is invalid", __func__);
+ return;
+ }
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return;
+ }
+ /* 1. unlink_urbs (dev, &dev->txq); maybe later be used */
+
+ /* 2. tasklet_schedule (&dev->bh) */
+ tasklet_schedule (&usbNet->bh);
+
+ /* 3. if (dev->driver_info->recover) none, rndis host no recover impl */
+
+ return;
+}
+
+/* some work can't be done in tasklets, so we use keventd
+ *
+ * NOTE: annoying asymmetry: if it's active, schedule_work() fails,
+ * but tasklet_schedule() doesn't. hope the failure is rare.
+ */
+static void UsbnetAdapterDeferKevent(struct UsbnetAdapter *usbNet, int work)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return;
+ }
+ set_bit (work, &usbNet->flags);
+ /* need update flags to usb_net_host */
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_UPDATE_FLAGS,
+ (const void *)&usbNet->flags, sizeof(usbNet->flags));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+
+ if (!schedule_work (&usbNet->kevent)) {
+ HARCH_NET_INFO_PRINT("kevent %d may have been dropped\n", work);
+ } else {
+ HARCH_NET_INFO_PRINT("kevent %d scheduled\n", work);
+ }
+}
+
+static void UsbnetAdapterSetRxMode(NetDevice *net)
+{
+ return;
+}
+
+static void UsbnetAdapterPauseRx(struct UsbnetAdapter *usbNet)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return;
+ }
+ set_bit(EVENT_RX_PAUSED, &usbNet->flags);
+ /* need update flags to usb_net_host */
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_UPDATE_FLAGS,
+ (const void *)&usbNet->flags, sizeof(usbNet->flags));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+
+ HARCH_NET_INFO_PRINT("paused rx queue enabled\n");
+}
+
+static void UsbnetAdapterUnlinkRxUrbs(struct UsbnetAdapter *usbNet)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return;
+ }
+
+ if (netif_running(usbNet->net)) {
+ /* unlink_urbs usbNet usbNet->rxq */
+ tasklet_schedule(&usbNet->bh);
+ }
+}
+
+static void UsbnetAdapterResumeRx(struct UsbnetAdapter *usbNet)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ int num = 0;
+ SkBuff *skb = NULL;
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return;
+ }
+
+ clear_bit(EVENT_RX_PAUSED, &usbNet->flags);
+ /* need update flags to usb_net_host */
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_UPDATE_FLAGS,
+ (const void *)&usbNet->flags, sizeof(usbNet->flags));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+
+ while ((skb = skb_dequeue(&usbNet->rxq_pause)) != NULL) {
+ UsbnetAdapterSkbReturn(usbNet, skb);
+ num++;
+ }
+
+ tasklet_schedule(&usbNet->bh);
+ HARCH_NET_INFO_PRINT("paused rx queue disabled, %d skbs requeued\n", num);
+}
+
+
+static int32_t UsbnetAdapterChangeMtu(NetDevice *net, int newMtu)
+{
+ //send to device
+ HARCH_NET_INFO_PRINT("begin");
+ if (NULL == net) {
+ HDF_LOGE("%s net device object is invalid", __func__);
+ return HDF_FAILURE;
+ }
+
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (NULL == usbNet) {
+ HDF_LOGE("%s UsbnetAdapter object is invalid", __func__);
+ return HDF_FAILURE;
+ }
+
+ /* 1. ll_mtu old_hard_mtu old_rx_urb_size */
+ HARCH_NET_INFO_PRINT("newMtu:%d", newMtu);
+ int llMtu = newMtu + net->hard_header_len;
+ int oldHardMtu = usbNet->usbnetInfo.hardMtu;
+ int oldRxUrbSize = usbNet->usbnetInfo.rxUrbSize;
+
+ /* 2. no second zero-length packet read wanted after mtu-sized packets */
+ if ((llMtu % usbNet->usbnetInfo.maxpacket) == 0) {
+ HARCH_NET_INFO_PRINT("");
+ return -EDOM;
+ }
+
+ /* 3. set usbNet->hard_mtu */
+ net->mtu = newMtu;
+ usbNet->usbnetInfo.hardMtu = net->mtu + net->hard_header_len;
+
+ /* 4. pause and resume usbnet */
+ if (usbNet->usbnetInfo.rxUrbSize == oldHardMtu) {
+ usbNet->usbnetInfo.rxUrbSize = usbNet->usbnetInfo.hardMtu;
+ if (usbNet->usbnetInfo.rxUrbSize > oldRxUrbSize) {
+ UsbnetAdapterPauseRx(usbNet);
+ UsbnetAdapterUnlinkRxUrbs(usbNet);
+ UsbnetAdapterResumeRx(usbNet);
+ }
+ }
+
+ /* need transmit hard_mtu to usb net host, UsbnetHostUpdateMaxQlen need this param */
+ HARCH_NET_INFO_PRINT("name = %s, flags = %d, usbFlags = %x mtu = %d, hardHeaderLen = %d,\
+ link = %d needReset = %d, hardMtu = %d, rxUrbSize = %d, maxpacket =%d",
+ usbNet->usbnetInfo.name,usbNet->usbnetInfo.flags,usbNet->usbnetInfo.usbFlags,\
+ usbNet->usbnetInfo.mtu,usbNet->usbnetInfo.hardHeaderLen,usbNet->usbnetInfo.link,\
+ usbNet->usbnetInfo.needReset,usbNet->usbnetInfo.hardMtu,usbNet->usbnetInfo.rxUrbSize,\
+ usbNet->usbnetInfo.maxpacket);
+ /* 5. max qlen depend on hard_mtu and rx_urb_size */
+ /* need update flags to usb_net_host */
+ OsalMutexLock(&usbNet->sendSkbClock);
+ int32_t ret = UsbnetAdapterSendBufToUsb(usbNet->deviceObject, USB_NET_UPDATE_MAXQLEN,
+ (const void *)&usbNet->usbnetInfo, sizeof(usbNet->usbnetInfo));
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("fail to UsbnetAdapterSendBufToUsb SendEvent!");
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return ret;
+ }
+ OsalMutexUnlock(&usbNet->sendSkbClock);
+ return HDF_SUCCESS;
+}
+
+static void UsbnetAdapterGetStats64(NetDevice *net, struct rtnl_link_stats64 *stats)
+{
+ //send to device
+ HARCH_NET_INFO_PRINT("begin");
+
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ netdev_stats_to_stats64(stats, &net->stats);
+ dev_fetch_sw_netstats(stats, usbNet->stats64);
+
+ PcpuSwNetstats *stats64 = this_cpu_ptr(usbNet->stats64);
+
+ HARCH_NET_INFO_PRINT ("usbNet stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ HARCH_NET_INFO_PRINT ("usbNet stats64->tx_packets = %lu,usbNet stats64->tx_bytes = %lu",
+ stats64->tx_packets, stats64->tx_bytes);
+
+ HARCH_NET_INFO_PRINT("end");
+ return;
+}
+
+static NetDevice_Ops g_UsbnetAdapterDeviceOps = {
+ .ndo_open = UsbnetAdapterOpen,
+ .ndo_stop = UsbnetAdapterStop,
+ .ndo_start_xmit = UsbnetAdapterStartXmit,
+ .ndo_tx_timeout = UsbnetAdapterTXTimeout,
+ .ndo_set_rx_mode = UsbnetAdapterSetRxMode,
+ .ndo_change_mtu = UsbnetAdapterChangeMtu,
+ .ndo_get_stats64 = UsbnetAdapterGetStats64,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/* drivers may override default ethtool_ops in their bind() routine */
+static const EthtoolOps g_UsbnetAdapterEthtoolOps = {
+};
+
+static void UsbnetAdapterLinkChange(struct UsbnetAdapter *usbNet, bool link, bool need_reset)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ /* update link after link is reseted */
+ if (link && !need_reset) {
+ netif_carrier_on(usbNet->net);
+ } else {
+ netif_carrier_off(usbNet->net);
+ }
+}
+
+static int32_t UsbnetAdapterSetSkb(struct UsbnetAdapter *usbNet, gfp_t flags,
+ uint32_t infoSize, unsigned char *buff, SkBuff *skb)
+{
+ if (!skb) {
+ HARCH_NET_INFO_PRINT("no rx skb\n");
+ UsbnetAdapterDeferKevent(usbNet, EVENT_RX_MEMORY);
+ return HDF_DEV_ERR_NO_MEMORY;
+ }
+
+ skb_put(skb, infoSize);
+ if (memcpy_s(skb->data, infoSize, buff, infoSize) != EOK) {
+ HARCH_NET_INFO_PRINT("memcpy_s error ");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ printf_char_buffer(skb->data, skb->len, false);
+ return HDF_SUCCESS;
+}
+
+static void UsbnetAdapterSetUsbNetInfo(struct UsbnetAdapter *usbNet, SkBuff *skb, enum SkbState state)
+{
+ unsigned long lockflags = 0;
+ spin_lock_irqsave (&usbNet->rxq.lock, lockflags);
+ UsbnetAdapterQueueSkb(&usbNet->rxq, skb, RX_START);
+ spin_unlock_irqrestore (&usbNet->rxq.lock, lockflags);
+
+ PcpuSwNetstats *stats64 = this_cpu_ptr(usbNet->stats64);
+ HARCH_NET_INFO_PRINT("usbNet stats64->rx_packets = %lu,usbNet stats64->rx_bytes = %lu",
+ stats64->rx_packets, stats64->rx_bytes);
+
+ if (++usbNet->pktCnt > PKT_COUNT_CLEAR) {
+ HARCH_NET_INFO_PRINT("usbNet->pktCnt = %d, pktErr = %d", usbNet->pktCnt, usbNet->pktErr);
+ usbNet->pktCnt = 0;
+ usbNet->pktErr = 0;
+ } else {
+ HARCH_NET_INFO_PRINT("usbNet->pktCnt = %d,pktErr = %d", usbNet->pktCnt, usbNet->pktErr);
+ if (state == RX_CLEANUP) {
+ usbNet->pktErr++;
+ }
+
+ if (usbNet->pktErr > PKT_COUNT_RXKILL) {
+ set_bit(EVENT_RX_KILL, &usbNet->flags);
+ }
+ }
+}
+
+static int32_t UsbnetAdapterRxComplete(struct HdfDeviceObject *device, struct HdfSBuf *data, gfp_t flags)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ unsigned char *buff = NULL;
+ uint32_t infoSize = 0;
+ bool flag = HdfSbufReadBuffer(data, (const void **)(&(buff)), &infoSize);
+ if ((!flag) || buff == NULL) {
+ HDF_LOGE("%s: fail to read infoTable in event data, flag = %d", __func__, flag);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ NetDevice *net = (NetDevice *)device->priv;
+ if (net == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+ printf_char_buffer(buff, infoSize, false);
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (usbNet == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ SkBuff *skb = NULL;
+ uint32_t skb_size = sizeof(struct iphdr) + sizeof(struct udphdr) + infoSize;
+ size_t size = skb_size > usbNet->usbnetInfo.rxUrbSize ? usbNet->usbnetInfo.rxUrbSize : skb_size;
+ if (test_bit(EVENT_NO_IP_ALIGN, &usbNet->flags)) {
+ skb = __netdev_alloc_skb(usbNet->net, size, flags);
+ } else {
+ skb = __netdev_alloc_skb_ip_align(usbNet->net, size, flags);
+ }
+ int32_t ret = UsbnetAdapterSetSkb(usbNet, flags, infoSize, buff, skb);
+ if (ret != HDF_SUCCESS || skb == NULL) {
+ HDF_LOGE("%s: fail to set skb, flag = %d", __func__, flag);
+ return ret;
+ }
+ HARCH_NET_INFO_PRINT("infoSize= %d, size = %d, skb->len = %d", infoSize, size, skb->len);
+
+ struct SkbData *entry = (struct SkbData *)skb->cb;
+ entry->length = 0;
+
+ //success recv
+ enum SkbState state = RX_DONE;
+ UsbnetAdapterSetUsbNetInfo(usbNet, skb, state);
+
+ state = UsbnetAdapterDeferBh(usbNet, skb, &usbNet->rxq, state);
+ HARCH_NET_INFO_PRINT("usbNet->pktCnt = %d, pktErr = %d, state = %d", usbNet->pktCnt, usbNet->pktErr, state);
+ return HDF_SUCCESS;
+}
+
+// precondition: never called in_interrupt
+static DeviceType wlanType = {
+ .name = "wlan",
+};
+
+static DeviceType wwanType = {
+ .name = "wwan",
+};
+
+static void UsbnetAdapterSetUsbNet(struct HdfDeviceObject *device,
+ NetDevice *net, struct UsbnetTransInfo *uNetTransInfo)
+{
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ usbNet->deviceObject = device;
+
+ //info from usb
+ if (memcpy_s(&(usbNet->usbnetInfo), sizeof(struct UsbnetTransInfo),
+ uNetTransInfo, sizeof(struct UsbnetTransInfo)) != EOK) {
+ HARCH_NET_INFO_PRINT("memcpy_s error ");
+ }
+
+ HARCH_NET_INFO_PRINT("name = %s, flags = %d, usbFlags = %x, mtu = %d, \
+ hardHeaderLen = %d, link = %d, needReset = %d, \
+ hardMtu = %d, rxUrbSize = %d, maxpacket = %d",
+ usbNet->usbnetInfo.name, usbNet->usbnetInfo.flags,
+ usbNet->usbnetInfo.usbFlags, usbNet->usbnetInfo.mtu,
+ usbNet->usbnetInfo.hardHeaderLen, usbNet->usbnetInfo.link,
+ usbNet->usbnetInfo.needReset, usbNet->usbnetInfo.hardMtu,
+ usbNet->usbnetInfo.rxUrbSize, usbNet->usbnetInfo.maxpacket);
+
+ usbNet->stats64 = netdev_alloc_pcpu_stats(PcpuSwNetstats);
+ if (!usbNet->stats64) {
+ return;
+ }
+
+ usbNet->msg_enable = netif_msg_init (g_msgLevel, NETIF_MSG_DRV
+ | NETIF_MSG_PROBE | NETIF_MSG_LINK| NETIF_MSG_RX_ERR|NETIF_MSG_TX_ERR);
+
+ OsalMutexInit(&usbNet->sendSkbClock);
+
+ init_waitqueue_head(&usbNet->wait);
+ skb_queue_head_init (&usbNet->rxq);
+ skb_queue_head_init (&usbNet->txq);
+ skb_queue_head_init (&usbNet->done);
+ skb_queue_head_init(&usbNet->rxq_pause);
+
+ // init work for tx_complete rx_complete
+ INIT_WORK(&usbNet->TxCompleteWorkqueue, TxComplete);
+ INIT_WORK(&usbNet->RxCompleteWorkqueue, RxComplete);
+
+ usbNet->bh.func = (void (*)(unsigned long))UsbnetAdapterBhTasklet;
+ usbNet->bh.data = (unsigned long)&usbNet->delay; //TimerList delay;
+
+ timer_setup(&usbNet->delay, UsbnetAdapterBh, 0);
+
+ usbNet->net = net;
+}
+
+
+static void UsbnetAdapterSetNetDevice(struct UsbnetAdapter *usbNet, NetDevice *net)
+{
+ // 1.addr
+ static u8 node_id[ETH_ALEN];
+ if (usbNet->usbnetInfo.isGetmacAddr) {
+ if (memcpy_s(node_id, ETH_ALEN, usbNet->usbnetInfo.macAddr, ETH_ALEN) != EOK) {
+ return;
+ }
+ } else {
+ eth_random_addr(node_id);
+ }
+ memcpy_s(net->dev_addr, sizeof(node_id)/sizeof(node_id[0]), node_id, sizeof(node_id)/sizeof(node_id[0]));
+ HARCH_NET_INFO_PRINT("macAddr addr %pM", net->dev_addr);
+ // 2. mtu
+ net->min_mtu = 0;
+ net->max_mtu = ETH_MAX_MTU;
+ net->netdev_ops = &g_UsbnetAdapterDeviceOps;
+ net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
+ net->ethtool_ops = &g_UsbnetAdapterEthtoolOps;
+
+ //3. name and mtu
+ strcpy_s (net->name, sizeof(net->name)/sizeof(net->name[0]), "usb%d");
+ if (usbNet->usbnetInfo.isBindDevice) {
+ if ((usbNet->usbnetInfo.usbFlags & HDF_FLAG_ETHER) != 0 &&
+ ((usbNet->usbnetInfo.usbFlags & HDF_FLAG_POINTTOPOINT) == 0 ||
+ (net->dev_addr[0] & 0x02) == 0)) {
+ HARCH_NET_INFO_PRINT();
+ strcpy_s (net->name, sizeof(net->name)/sizeof(net->name[0]), "eth%d");
+ }
+
+ /* WLAN devices should always be named "wlan%d" */
+ if ((usbNet->usbnetInfo.usbFlags & FLAG_WLAN) != 0) {
+ HARCH_NET_INFO_PRINT();
+ strcpy_s(net->name, sizeof(net->name)/sizeof(net->name[0]), "wlan%d");
+ }
+ /* WWAN devices should always be named "wwan%d" */
+ if ((usbNet->usbnetInfo.usbFlags & FLAG_WWAN) != 0) {
+ HARCH_NET_INFO_PRINT();
+ strcpy_s(net->name, sizeof(net->name)/sizeof(net->name[0]), "wwan%d");
+ }
+
+ /* devices that cannot do ARP */
+ if ((usbNet->usbnetInfo.usbFlags & FLAG_NOARP) != 0) {
+ net->flags |= IFF_NOARP;
+ }
+
+ HARCH_NET_INFO_PRINT("usbNet->usbnetInfo.mtu = %d, net->name= %s", usbNet->usbnetInfo.mtu, net->name);
+ /* maybe the remote can't receive an Ethernet MTU */
+ net->mtu = usbNet->usbnetInfo.mtu;
+ net->hard_header_len = usbNet->usbnetInfo.hardHeaderLen;
+ }
+
+ /* let userspace know we have a random address */
+ if (ether_addr_equal(net->dev_addr, node_id)) {
+ net->addr_assign_type = NET_ADDR_RANDOM;
+ }
+}
+
+static int32_t UsbnetAdapterProbe(struct HdfDeviceObject *device, struct HdfSBuf *data)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ int ret = HDF_SUCCESS;
+ uint32_t infoSize = 0;
+ struct UsbnetTransInfo *uNetTransInfo = NULL;
+
+ bool flag = HdfSbufReadBuffer(data, (const void **)(&(uNetTransInfo)), &infoSize);
+ if ((!flag) || uNetTransInfo == NULL) {
+ ret = HDF_ERR_INVALID_PARAM;
+ HDF_LOGE("%s: fail to read infoTable in event data, flag = %d", __func__, flag);
+ return ret;
+ }
+ NetDevice *net = alloc_etherdev(sizeof(struct UsbnetAdapter));
+ if (net == NULL) {
+ HARCH_NET_INFO_PRINT();
+ goto out;
+ }
+ device->priv = net;
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ UsbnetAdapterSetUsbNet(device, net, uNetTransInfo);
+ UsbnetAdapterSetNetDevice(usbNet, net);
+ HARCH_NET_INFO_PRINT("after usbNet->usbnetInfo.mtu = %d, net->name= %s", usbNet->usbnetInfo.mtu, net->name);
+ ret = register_netdev(net);
+ if (ret) {
+ goto out0;
+ }
+ HARCH_NET_INFO_PRINT("register net %pM\n", net->dev_addr);
+ netif_device_attach(net);
+ HARCH_NET_INFO_PRINT("netif_device_attach net %pM\n", net->dev_addr);
+
+ if (usbNet->usbnetInfo.usbFlags & FLAG_LINK_INTR) {
+ HARCH_NET_INFO_PRINT();
+ UsbnetAdapterLinkChange(usbNet, 0, 0);
+ }
+ return HDF_SUCCESS;
+
+out0:
+ cancel_work_sync(&usbNet->TxCompleteWorkqueue);
+ cancel_work_sync(&usbNet->RxCompleteWorkqueue);
+ free_netdev(net);
+out:
+ return ret;
+}
+
+
+static int32_t UsbnetAdapterDisconnect(struct HdfDeviceObject *device)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (device == NULL) {
+ HDF_LOGI("%s: device is null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ //free net
+ NetDevice *net = (NetDevice *)device->priv;
+ unregister_netdev (net);
+
+ struct UsbnetAdapter *usbNet = netdev_priv(net);
+ if (usbNet->stats64) {
+ free_percpu(usbNet->stats64);
+ }
+
+ UsbnetAdapterTerminateUrbs(usbNet);
+ skb_queue_purge(&usbNet->rxq_pause);
+ OsalMutexDestroy(&usbNet->sendSkbClock);
+
+ free_netdev(net);
+ return HDF_SUCCESS;
+}
+
+static int32_t UsbnetAdapterDispatch(
+ struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
+{
+ HARCH_NET_INFO_PRINT("begin, received cmd = %d", cmd);
+
+ int32_t ret = HDF_ERR_INVALID_PARAM;
+ switch (cmd) {
+ case USB_NET_REGISTER_NET:
+ //add new usbnet device
+ ret = UsbnetAdapterProbe(client->device, data);
+ break;
+ case USB_NET_CLOSE_NET:
+ ret = UsbnetAdapterDisconnect(client->device);
+ break;
+ case USB_NET_RECIVE_DATA_FROM_USB:
+ ret = UsbnetAdapterRxComplete(client->device, data, GFP_ATOMIC);
+ break;
+ default:
+ HDF_LOGI("%s: no this cmd: %d", __func__, cmd);
+ break;
+ }
+
+ if (!HdfSbufWriteInt32(reply, ret)) {
+ HDF_LOGE("%s: reply int32 fail", __func__);
+ }
+
+ return ret;
+}
+
+static int32_t UsbnetAdapterBind(struct HdfDeviceObject *device)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ static struct IDeviceIoService UsbnetAdapterService = {
+ .Dispatch = UsbnetAdapterDispatch,
+ };
+
+ if (device == NULL) {
+ HARCH_NET_INFO_PRINT("device is NULL!");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ device->service = &UsbnetAdapterService;
+ return HDF_SUCCESS;
+}
+
+static int32_t UsbnetAdapterInit(struct HdfDeviceObject *device)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ if (device == NULL) {
+ HARCH_NET_INFO_PRINT("device is null!");
+ return HDF_FAILURE;
+ }
+
+ HARCH_NET_INFO_PRINT("UsbnetAdapterInit Init success");
+ return HDF_SUCCESS;
+}
+
+static void UsbnetAdapterRelease(struct HdfDeviceObject *device)
+{
+ HARCH_NET_INFO_PRINT("begin");
+ return;
+}
+
+struct HdfDriverEntry g_UsbnetAdapterEntry = {
+ .moduleVersion = 1,
+ .Bind = UsbnetAdapterBind,
+ .Init = UsbnetAdapterInit,
+ .Release = UsbnetAdapterRelease,
+ .moduleName = "HDF_USB_NET",
+};
+
+HDF_INIT(g_UsbnetAdapterEntry);
diff --git a/framework/model/usb/include/hdf_usb_net_manager.h b/framework/model/usb/include/hdf_usb_net_manager.h
new file mode 100755
index 0000000000000000000000000000000000000000..652b5791512319b9c15a7aea2f35562fab9221f6
--- /dev/null
+++ b/framework/model/usb/include/hdf_usb_net_manager.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024 Archermind Technology (Nanjing) Co. Ltd.
+ *
+ * HDF is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ * See the LICENSE file in the root of this repository for complete details.
+ */
+
+#ifndef HDF_USB_NET_MANAGE_H
+#define HDF_USB_NET_MANAGE_H
+
+#include "hdf_base.h"
+#include "hdf_device_desc.h"
+
+
+#define MAC_ADDR_SIZE 6
+#define IFNAMSIZ 16
+
+/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
+#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
+#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
+#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
+
+#define HDF_FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
+#define HDF_FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
+
+#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
+#define FLAG_WLAN 0x0080 /* use "wlan%d" names */
+#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
+#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */
+#define FLAG_WWAN 0x0400 /* use "wwan%d" names */
+
+#define FLAG_LINK_INTR 0x0800 /* updates link (carrier) status */
+#define HDF_FLAG_POINTTOPOINT 0x1000 /* possibly use "usb%d" names */
+
+/*
+ * Indicates to usbnet, that USB driver accumulates multiple IP packets.
+ * Affects statistic (counters) and short packet handling.
+ */
+#define FLAG_MULTI_PACKET 0x2000
+#define FLAG_RX_ASSEMBLE 0x4000 /* rx packets may span >1 frames */
+#define FLAG_NOARP 0x8000 /* device can't do ARP */
+
+enum UsbnetServiceCmd {
+ USB_NET_REGISTER_NET,
+ USB_NET_CLOSE_NET,
+ USB_NET_SEND_DATA_TO_USB,
+ USB_NET_RECIVE_DATA_FROM_USB,
+ USB_NET_OPEN_USB,
+ USB_NET_CLOSE_USB,
+ USB_NET_UPDATE_FLAGS,
+ USB_NET_UPDATE_MAXQLEN
+};
+
+struct UsbnetTransInfo {
+ uint8_t isBindDevice;
+ char name[IFNAMSIZ]; /**< Network device name {@link IFNAMSIZ} */
+ uint8_t isGetmacAddr;
+ uint8_t macAddr[MAC_ADDR_SIZE]; /**< MAC address {@link MAC_ADDR_SIZE} */
+ uint32_t flags; /**< Network port status */
+ uint32_t mtu; /**< Maximum transmission unit */
+ uint16_t hardHeaderLen; /**< Header length */
+ uint8_t link;
+ uint8_t needReset;
+ uint32_t usbFlags; /**< usb device match flags */
+ uint32_t rxUrbSize; /* size for rx urbs */
+ uint32_t hardMtu; /* count any extra framing */
+ uint32_t maxpacket;
+ int txQlen;
+};
+
+#endif
\ No newline at end of file
diff --git a/framework/model/usb/include/hdf_usb_pnp_manage.h b/framework/model/usb/include/hdf_usb_pnp_manage.h
index 0f0c811d12aaf8e4a49fbbfa03f6a1e3a4f19c6b..bc0cd9d23a197de81bf8fc0eaf1323ca09c141da 100644
--- a/framework/model/usb/include/hdf_usb_pnp_manage.h
+++ b/framework/model/usb/include/hdf_usb_pnp_manage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
@@ -54,6 +54,7 @@ enum {
};
struct UsbPnpNotifyServiceInfo {
+ uint8_t curInterfaceNumber;
uint32_t length;
int32_t devNum;