NetDev

NetDev组件

Net 组件的主要内容有 4 个方面,分别是 sal ,AT,lwip 与 netdev。

使用 RT-Thread上网的联网设备,品类繁多,方式各异,但其实追踪到依赖的基础 net 能力其实也没有多复杂。实际上大部分的功能依赖的基础能力,只有两组而已,即 AT ,Lwip;而到用户,大部分就只用到 Sal 这一个概念。

请添加图片描述


netdev介绍

netdev(network interface device),即网络接口设备,又称网卡。每一个用于网络连接的设备都可以注册成网卡,为了适配更多的种类的网卡,避免系统中对单一网卡的依赖,RT-Thread 系统提供了 netdev 组件用于网卡管理和控制。

功能
  1. 抽象网卡概念,每个网络连接设备可注册唯一网卡;
  2. 提供多种网络连接信息查询,方便用户实时获取当前网卡网络状态;
  3. 建立网卡列表和默认网卡,可用于网络连接的切换;
  4. 提供多种网卡操作接口(设置 IP、DNS 服务器地址,设置网卡状态等);
  5. 统一管理网卡调试命令(ping、ifconfig、netstat、dns 等命令);
结构体
struct netdev
{
    rt_slist_t list;

    char name[RT_NAME_MAX];                            /* network interface device name */
    ip_addr_t ip_addr;                                 /* IP address */
    ip_addr_t netmask;                                 /* subnet mask */
    ip_addr_t gw;                                      /* gateway */
#if NETDEV_IPV6
    ip_addr_t ip6_addr[NETDEV_IPV6_NUM_ADDRESSES];     /* array of IPv6 addresses */
#endif /* NETDEV_IPV6 */
    ip_addr_t dns_servers[NETDEV_DNS_SERVERS_NUM];     /* DNS server */
    uint8_t hwaddr_len;                                /* hardware address length */
    uint8_t hwaddr[NETDEV_HWADDR_MAX_LEN];             /* hardware address */

    uint16_t flags;                                    /* network interface device status flag */
    uint16_t mtu;                                      /* maximum transfer unit (in bytes) */
    const struct netdev_ops *ops;                      /* network interface device operations */

    netdev_callback_fn status_callback;                /* network interface device flags change callback */
    netdev_callback_fn addr_callback;                  /* network interface device address information change callback */

#ifdef RT_USING_SAL
    void *sal_user_data;                               /* user-specific data for SAL */ // to sal pfs and ops
#endif /* RT_USING_SAL */
    void *user_data;                                   /* user-specific data */         // to netif(在netdev_register(...)当中赋值的)
};

网卡OPS

struct netdev_ops
{
    /* set network interface device hardware status operations */
    int (*set_up)(struct netdev *netdev);
    int (*set_down)(struct netdev *netdev);

    /* set network interface device address information operations */
    int (*set_addr_info)(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw);
    int (*set_dns_server)(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server);
    int (*set_dhcp)(struct netdev *netdev, rt_bool_t is_enabled);

#ifdef RT_USING_FINSH
    /* set network interface device common network interface device operations */
    int (*ping)(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp);
    void (*netstat)(struct netdev *netdev);
#endif

    /* set default network interface device in current network stack*/
    int (*set_default)(struct netdev *netdev);
};

/* sal network database name resolving */
struct sal_netdb_ops
{
    struct hostent* (*gethostbyname)  (const char *name);
    int             (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
    int             (*getaddrinfo)    (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
    void            (*freeaddrinfo)   (struct addrinfo *ai);
};

netdev状态


/* whether the network interface device is 'up' (set by the network interface driver or application) */
#define NETDEV_FLAG_UP                 0x01U      //--------->up/down
/* if set, the network interface device has broadcast capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_BROADCAST          0x02U
/* if set, the network interface device has an active link (set by the network interface driver) */
#define NETDEV_FLAG_LINK_UP            0x04U      //--------->link_up/link_down
/* if set, the network interface device is an ethernet device using ARP, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_ETHARP             0x08U
/* if set, the network interface device is an ethernet device, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_ETHERNET           0x10U
/* if set, the network interface device has IGMP capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_IGMP               0x20U
/* if set, the network interface device has MLD6 capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_MLD6               0x40U
/* if set, the network interface device connected to internet successfully (set by the network interface driver) */
#define NETDEV_FLAG_INTERNET_UP        0x80U      //--------->internet_up/internet_down
/* if set, the network interface device has DHCP capability (set by the network interface device driver or application) */
#define NETDEV_FLAG_DHCP               0x100U
API
#include <arpa/inet.h>         /* 包含 ip_addr_t 等地址相关的头文件 */
#include <netdev.h>            /* 包含全部的 netdev 相关操作接口函数 */
int netdev_register(struct netdev *netdev, const char *name, void *user_data);
int netdev_unregister(struct netdev *netdev);
struct netdev *netdev_get_first_by_flags(uint16_t flags);
struct netdev *netdev_get_by_family(int family);
struct netdev *netdev_get_by_ipaddr(ip_addr_t *ip_addr);
struct netdev *netdev_get_by_name(const char *name);    // 网卡名称唯一
void netdev_set_default(struct netdev *netdev);
int netdev_set_up(struct netdev *netdev);
int netdev_set_down(struct netdev *netdev);
int netdev_dhcp_enabled(struct netdev *netdev, rt_bool_t is_enabled);
/* 设置网卡 IP 地址 */
int netdev_set_ipaddr(struct netdev *netdev, const ip_addr_t *ipaddr);      // dhcp关闭状态下使用
/* 设置网卡网关地址 */
int netdev_set_gw(struct netdev *netdev, const ip_addr_t *gw);              // dhcp关闭状态下使用
/* 设置网卡子网掩码地址 */
int netdev_set_netmask(struct netdev *netdev, const ip_addr_t *netmask);    // dhcp关闭状态下使用
int netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, const ip_addr_t *dns_server); // dhcp关闭状态下使用
typedef void (*netdev_callback_fn )(struct netdev *netdev, enum netdev_cb_type type);
void netdev_set_status_callback(struct netdev *netdev, netdev_callback_fn status_callback); // 网卡可以设置回调用函数,状态改变时调用 TODO
void netdev_set_addr_callback(struct netdev *netdev, netdev_callback_fn addr_callback)      // 地址改变时调用
#define netdev_is_up(netdev)
#define netdev_is_link_up(netdev)
#define netdev_is_internet_up(netdev)
#define netdev_is_dhcp_enable(netdev)
状态设置调用路径

up/down 状态以及 dhcp_enable/dhcp_disable 状态可以通过 netdev 组件提供的接口设置,可以在应用层控制。其他状态是由网卡底层驱动或者 netdev 组件根据当前网卡网络连接情况自动设置

状态含义设置
up网卡开启底层: eth_device_init(…)/lwip_netdev_set_up(struct netdev *netif) ->
netif_set_up(struct netif *netif)->
netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up);
上层:netdev->ops->set_up( );
down网卡禁用eth_device_deinit(…)/lwip_netdev_set_down(struct netdev *netif)->
netif_set_down(struct netif *netif)->
netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up)
link_up链路有效eth_device_linkchange(struct eth_device* dev, rt_bool_t up)->
netif_set_link_up(struct netif *netif)->
netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up)
link_down链路无效eth_device_linkchange(struct eth_device* dev, rt_bool_t up)->
netif_set_link_down(struct netif *netif )->
netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up)
internet_up连接到因特网check_netdev_internet_up_work(struct rt_work *work, void *work_data)->
netdev_low_level_set_internet_status(struct netdev *netdev, rt_bool_t is_up);
internet_down未连接到因特网netdev_low_level_set_…(…)->
sal_check_netdev_internet_up(…)->
check_netdev_internet_up_work(struct rt_work *work, void *work_data)->
netdev_low_level_set_internet_status(struct netdev *netdev, rt_bool_t is_up);
dhcp_enable开启 DHCP
dhcp_disable关闭 DHCP

Lwip 设备eth_device及网卡netif 和rt-thread网卡netdev的状态同步,通过上面的函数间的调用关系,如果使用lwip的网卡来是适配我们的协议栈,底层调用关系已经设置好了。

文件结构
├─ netdev                 // netdev 组件
│  ├─ include
│  │  ├─ arpa             // 引用了netdev_ipaddr.h
│  │  │  └─ inet.h
│  │  ├─ netdev.h         // netdev 结构体定义及相关操作声明,netdev状态定义
│  │  └─ netdev_ipaddr.h  // 一些IP 地址相关的操作
│  ├─ Kconfig
│  ├─ SConscript
│  └─ src
│     ├─ netdev.c
│     └─ netdev_ipaddr.c

Lwip 介绍


Lwip网卡注册调用关系
xxx_hw_init();--->
  rt_err_t eth_device_init(struct eth_device * dev, const char *name); --->
    rt_err_t eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flags);--->
      netifapi_netif_add(...);--->
        tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call);--->     // TODO:why call this func?? 猜测是为了线程安全。
          static err_t eth_netif_device_init(struct netif *netif); --->
            static int netdev_add(struct netif *lwip_netif); --->
              int netdev_register(struct netdev *netdev, const char *name, void *user_data); --->   // struct netif 作为user data在netdev中进行链接


网卡设备继承关系

RT-Thread 的设备模型是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理器的范畴。每个设备对象都是由基对象派生而来,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VfzGzvi8-1667636788512)(25a40859735f5684b1fe6a76ebc98593.png)]

struct rt_object --->
  struct rt_device --->
    struct eth_device --->
      struct eth_device_xxx    // device type: RT_Device_Class_NetIf

Lwip 函数调用流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8MRfYM3s-1667636788513)(8e47ad50f996d7368e2788de6d98d5ef.png)]

网络接口层:
lwip 的ETH 层可以单独分两个线程进行数据的发送和接收,连线程和tcpip线程间通过邮箱通信。是否开这两个线程和邮箱通过 LWIP_NO_TX_THREAD/LWIP_NO_RX_THREAD 宏进行控制(开线程和不开的区别在哪?)。

收发线程和邮箱的初始化放在lwip初始化的时候, lwip_system_init()时完成。

rx:硬件收到数据后,产生一个对应的中断,调用eth_device_ready(...)通过邮箱通知eth_rx_thread去读取数据并处理存放进 struct pbuf 中,再调用网卡netif入口函数ethernet_input(...)进行处理。

tx:发送线程,从邮箱中接收到数据后,调用底层提供的接口,把数据写到FIFO中,等待发送完成的反馈。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LuAujJV9-1667636788513)(255d43f7d1e8d0470c90cc427f53f3c2.png)]

网卡信息的配置

目前认为有两种方式获取Ip地址,一种是DHCP分配,一种是调用netdev提供的接口手动设置。

DHCP 动态分配

根据rt-thread的代码,当设置了DHCP自动分配IP地址的时候,无法手动设置IP地址;但是DHCP申请到了IP地址是如何给netdev的呢?

DHCP打开的时候,手动进行IP地址的设置会失败。

dhcp_bind(struct netif *netif)->
  netif_set_addr(...)->

DHCP可以在程序运行中打开/关闭,列一下有哪些时候会进行DHCP的打来关闭

dhcp_start(struct netif *netif);      // DHCP 开  初始化时:eth_netif_device_init(struct netif *netif) ->dhcp_start();
                                                  程序运行中:通过netdev提供的接口lwip_netdev_set_dhcp(...)
                                                            
dhcp_stop(struct netif *netif);       // DHCP 关  删除eth_device时:eth_device_deinit(struct eth_device *dev)
                                                  程序运行时同dhcp_start(...)

dhcp 静态分配

当在配置文件中关闭通过DHCP分配IP地址后,rt_thread会给网卡分配一个静态IP地址,换个说法就是,当打开dhcp 时,rt_thread会把网卡的初始地址设成0,否则初始地址为一个局部IP地址。

手动设置

eth_device&netdev&netif

eth_device 网络接口设备

struct eth_device
{
    /* inherit from rt_device */
    struct rt_device parent;

    /* network interface for lwip */
    struct netif *netif;                // to netif

    rt_uint16_t flags;
    rt_uint8_t  link_changed;
    rt_uint8_t  link_status;
    rt_uint8_t  rx_notice;

    /* eth device interface */
    struct pbuf* (*eth_rx)(rt_device_t dev);                  // send data
    rt_err_t (*eth_tx)(rt_device_t dev, struct pbuf* p);      // recv data
};

netdev 是对 lwip 中 netif 的继承。因为 netdev 从 netif 中取出了一些字节用于关键信息的填充。

请添加图片描述

需求

需要在rt_thread和DR之间搭一个数据传输通道,那么需要在rt_thread中注册一个网卡;----需要写一个虚拟网卡驱动;

需要给rt_thread暴露一个ip地址;—有两种实现方式,一种是通过DHCP和DR的dhcp_service获取一个地址,这种方式需要我们先把想要分配的地址写到DR的dhcp_service中;另外一种方式是,关闭dhcp功能的情况下,通过调用netdev提供的接口把IP地址等设置好。(不使用dhcp似乎是更好的选择)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值