648154ab创建于 2022年5月12日历史提交
/*
 * net_device_adapter.c
 *
 * net device adapter of linux
 *
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 */

#include "net_device_adapter.h"
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/version.h>
#include "net_device.h"
#include "net_device_impl.h"
#include "osal_mem.h"
#include "securec.h"

#define HDF_LOG_TAG NetDeviceFull

static int32_t NetDevXmitCheck(struct sk_buff *skb, struct net_device *dev)
{
    struct FullNetDevicePriv *priv = NULL;

    if (dev == NULL || skb == NULL) {
        HDF_LOGE("%s : dev = NUll or skb = NULL!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    priv = (struct FullNetDevicePriv *)netdev_priv(dev);
    if (priv == NULL || priv->dev == NULL || priv->impl == NULL) {
        HDF_LOGE("%s fail : priv NULL!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

static netdev_tx_t NetDevXmit(struct sk_buff *skb, struct net_device *dev)
{
    struct FullNetDevicePriv *priv = NULL;
    struct NetDevice *netDev = NULL;
    struct NetDeviceInterFace *netDevIf = NULL;

    if (NetDevXmitCheck(skb, dev) != HDF_SUCCESS) {
        NetBufFree(skb);
        return NETDEV_TX_OK;
    }
    priv = (struct FullNetDevicePriv *)netdev_priv(dev);
    netDev = priv->impl->netDevice;

    skb->dev = dev;
    netDevIf = netDev->netDeviceIf;
    if (netDevIf != NULL && netDevIf->xmit != NULL) {
        netDevIf->xmit(netDev, skb);
    } else {
        HDF_LOGE("%s fail : netdevIf = null or xmit = null!", __func__);
        NetBufFree(skb);
    }
    return NETDEV_TX_OK;
}

static int NetDevChangeMtu(struct net_device *dev, int mtu)
{
    if (mtu > WLAN_MAX_MTU || mtu < WLAN_MIN_MTU || dev == NULL) {
        return -EINVAL;
    }

    dev->mtu = (uint32_t)mtu;
    return HDF_SUCCESS;
}

static int NetDevOpen(struct net_device *dev)
{
    if (dev == NULL) {
        return -EINVAL;
    }

    netif_start_queue(dev);
    return HDF_SUCCESS;
}

static int NetDevStop(struct net_device *dev)
{
    if (dev == NULL) {
        return -EINVAL;
    }

    netif_stop_queue(dev);
    return HDF_SUCCESS;
}

static struct net_device_ops g_netDeviceOps = {
    .ndo_start_xmit = NetDevXmit,
    .ndo_change_mtu = NetDevChangeMtu,
    .ndo_open = NetDevOpen,
    .ndo_stop = NetDevStop
};

static struct net_device *CreateNetDevice(struct NetDevice *hdfDev)
{
    struct net_device *dev = NULL;

    dev = alloc_etherdev(sizeof(struct FullNetDevicePriv));
    if (dev == NULL) {
        return NULL;
    }

    if (memcpy_s(dev->name, IFNAMSIZ, hdfDev->name, IFNAMSIZ) != EOK) {
        free_netdev(dev);
        return NULL;
    }
    dev->mtu = DEFAULT_MTU;
    dev->netdev_ops = &g_netDeviceOps;

    return dev;
}

static void DestroyNetDevice(struct net_device *dev)
{
    free_netdev(dev);
}

static struct net_device *GetDevFromDevImpl(const struct NetDeviceImpl *impl)
{
    struct FullNetDevicePriv *priv = NULL;

    if (impl == NULL || impl->osPrivate == NULL) {
        return NULL;
    }
    priv = (struct FullNetDevicePriv *)impl->osPrivate;
    return priv->dev;
}

static int32_t NetDevInit(struct NetDeviceImpl *impl)
{
    struct FullNetDevicePriv *priv = NULL;
    struct net_device *dev = NULL;

    if (impl == NULL || impl->netDevice == NULL) {
        HDF_LOGE("%s fail: impl null , netDevice null", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    dev = CreateNetDevice(impl->netDevice);
    if (dev == NULL) {
        HDF_LOGE("%s fail : CreateNetDevice fail!", __func__);
        return HDF_FAILURE;
    }

    priv = (struct FullNetDevicePriv *)netdev_priv(dev);
    priv->dev = dev;
    priv->impl = impl;
    impl->osPrivate = (void *)priv;
    HDF_LOGI("%s Success!", __func__);

    return HDF_SUCCESS;
}

static int32_t NetDevDeInit(struct NetDeviceImpl *impl)
{
    struct FullNetDevicePriv *priv = NULL;

    if (impl == NULL) {
        HDF_LOGE("netdevice linux deinit already free.");
        return HDF_SUCCESS;
    }
    if (impl->osPrivate != NULL) {
        priv = (struct FullNetDevicePriv *)impl->osPrivate;
        DestroyNetDevice(priv->dev);
        impl->osPrivate = NULL;
    }
    HDF_LOGI("net device linux deinit success!");

    return HDF_SUCCESS;
}

static int32_t NetDevAdd(struct NetDeviceImpl *impl)
{
    struct net_device *dev = NULL;
    int ret;

    if ((dev = GetDevFromDevImpl(impl)) == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    if (impl->netDevice == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    if (memcpy_s(dev->dev_addr, ETH_ALEN, impl->netDevice->macAddr,
        MAC_ADDR_SIZE) != EOK) {
        HDF_LOGE("%s : memcpy fail!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    dev->needed_headroom = impl->netDevice->neededHeadRoom;
    dev->needed_tailroom = impl->netDevice->neededTailRoom;

    if ((ret = register_netdev(dev)) < 0) {
        HDF_LOGE("%s : register_netdev fail!,ret=%d", __func__, ret);
        return HDF_FAILURE;
    }

    HDF_LOGI("%s success!!", __func__);
    return HDF_SUCCESS;
}

static int32_t NetDevDelete(struct NetDeviceImpl *impl)
{
    struct FullNetDevicePriv *priv = NULL;
    struct net_device *dev = NULL;

    if (impl == NULL || impl->osPrivate == NULL) {
        HDF_LOGE("%s fail : impl = null or osPrivate = null!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    priv = (struct FullNetDevicePriv *)impl->osPrivate;

    dev = priv->dev;
    if (dev != NULL) {
        unregister_netdev(dev);
    }
    HDF_LOGI("%s success!", __func__);
    return HDF_SUCCESS;
}

static int32_t NetDevSetStatus(struct NetDeviceImpl *impl,
    NetIfStatus status)
{
    struct net_device *dev = GetDevFromDevImpl(impl);
    int32_t ret;

    if (dev == NULL) {
        HDF_LOGE("%s fail : net dev null!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    rtnl_lock();
    if (status == NETIF_DOWN) {
        dev_close(dev);
        ret = HDF_SUCCESS;
    } else if (status == NETIF_UP) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
        ret = dev_open(dev, NULL);
#else
        ret = dev_open(dev);
#endif
    } else {
        HDF_LOGE("%s fail : status error!", __func__);
        rtnl_unlock();
        return HDF_ERR_INVALID_PARAM;
    }
    rtnl_unlock();

    if (!ret) {
        return HDF_SUCCESS;
    }
    HDF_LOGE("%s fail ret = %d!", __func__, ret);
    return HDF_FAILURE;
}

static int32_t NetDevReceive(struct NetDeviceImpl *impl,
    NetBuf *buff, ReceiveFlag flag)
{
    struct net_device *dev = GetDevFromDevImpl(impl);

    if (dev == NULL) {
        HDF_LOGE("%s fail : dev = null!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (flag >= MAX_RECEIVE_FLAG || buff == NULL) {
        HDF_LOGE("%s fail : flag = %d or buff = null!", __func__, flag);
        return HDF_ERR_INVALID_PARAM;
    }

    buff->dev = dev;
    buff->protocol = eth_type_trans(buff, dev);
    if (flag & IN_INTERRUPT) {
        netif_rx(buff);
    } else {
        netif_rx_ni(buff);
    }
    return HDF_SUCCESS;
}

int32_t NetDevChangeMacAddr(struct NetDeviceImpl *impl)
{
    struct net_device *dev = NULL;

    if ((dev = GetDevFromDevImpl(impl)) == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    if (impl->netDevice == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    if (memcpy_s(dev->dev_addr, ETH_ALEN, impl->netDevice->macAddr, MAC_ADDR_SIZE) != EOK) {
        HDF_LOGE("%s : memcpy fail!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

static struct NetDeviceImplOp g_ndImplOps = {
    .init = NetDevInit,
    .deInit = NetDevDeInit,
    .add = NetDevAdd,
    .delete = NetDevDelete,
    .setStatus = NetDevSetStatus,
    .receive = NetDevReceive,
    .changeMacAddr = NetDevChangeMacAddr,
};

int32_t RegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl)
{
    if (ndImpl == NULL) {
        HDF_LOGE("%s fail : impl = null!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    ndImpl->interFace = &g_ndImplOps;
    HDF_LOGI("register full netdevice impl success.");
    return HDF_SUCCESS;
}

int32_t UnRegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl)
{
    if (ndImpl == NULL) {
        HDF_LOGI("%s already unregister!", __func__);
        return HDF_SUCCESS;
    }
    ndImpl->interFace = NULL;
    HDF_LOGI("%s success.", __func__);
    return HDF_SUCCESS;
}