全志D1开发(十一)网络驱动之网络设备初始化

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2022年5月3日19:34:13 评论 862

1. 网络驱动操作集

类似于SD适配器有操作集,SylixOS的网络驱动也有自己的操作集,是通过 struct netdev_funcs 数据结构来表示:

/*
 * network driver functions.
 */
struct netdev_funcs {
  /* initialize function */
  int  (*init)(struct netdev *netdev);

  /* basice functions can initialize with NULL */
  int  (*up)(struct netdev *netdev);
  int  (*down)(struct netdev *netdev);
  int  (*remove)(struct netdev *netdev);
  
  /* netdev ioctl (If 'net_type' is ethernet, only 2 commands should do)
   * cmd: SIOCSIFMTU:    arg is struct ifreq *pifreq, set MTU    (pifreq->ifr_mtu)
   *      SIOCSIFHWADDR: arg is struct ifreq *pifreq, set hwaddr (pifreq->ifr_hwaddr[]) */
  int  (*ioctl)(struct netdev *netdev, int cmd, void *arg);

  /* netdev rx mode updated: 
   * if 'net_type' is ethernet, driver must be in strict accordance with the following order of judgment)
   * if flags & IFF_PROMISC, driver must allow all packet input.
   * if flags & IFF_ALLMULTI, driver must allow all multicast packet input.
   * other, driver must allow all multicast address in mac list (can use NETDEV_MACFILTER_FOREACH() traverse) */
  int  (*rxmode)(struct netdev *netdev, int flags);
  
  /* netdev transmit a packet, and if success return 0 or return -1. */
  int  (*transmit)(struct netdev *netdev, struct pbuf *p);
  
  /* netdev receive a packet, system will call this function receive a packet. */
#ifdef NETDEV_RECEIVE_ARG_3
  void (*receive)(struct netdev *netdev, int (*input)(struct netdev *, struct pbuf *), void *notify_arg);
#else
  void (*receive)(struct netdev *netdev, int (*input)(struct netdev *, struct pbuf *));
#endif /* NETDEV_RECEIVE_ARG_3 */
  
  /* If netdev support poll mode you must set the following functions 
   * Poll mode is often used for High-Speed, Real-Time network applications */
  /* pollrecv() will be called by real-time applications. 
   * if a packet arrived, pollrecv() must invoke netdev_notify(netdev, LINK_INPUT, 0); to receive packet */
  void (*pollrecv)(struct netdev *netdev);
  
  /* intctl() can enable or disable netdev interrupt, in poll mode, SylixOS will disable netdev interrupt */
  int (*intctl)(struct netdev *netdev, int en);
  
  /* reserve for futrue */
  void (*reserved[6])();
};

这里介绍其中最简单的网络驱动必须的成员:

  • init:初始化接口,可以将网络硬件的一些初始化操作放在这个回调函数中。
  • transmit:数据包发送接口,通过pbuf发送协议栈的数据。
  • receive:数据包接收接口,将收到的数据包通过pbuf送到协议栈处理。
  • 其他的一些回调接口在使用网络的一些高级功能时也要实现,比如如果想设置驱动MTU就需要实现intctl接口等等,这里我们为了学习最简单的网络驱动编写,只需要实现上述三个接口就行。

定义一个全局变量表示网络驱动操作集,并将三个接口先使用空函数实现:

static int netifInit(struct netdev *pnetdev)
{
    return 0;
}
static int netifTransmit(struct netdev *pnetdev, struct pbuf *pbuf)
{
    return 0;
}
static void netifReceive(struct netdev *pnetdev, int (*input)(struct netdev *, struct pbuf *))
{
    return;
}
static struct netdev_funcs netif_funcs = {
    .init      = netifInit,
    .transmit  = netifTransmit,
    .receive   = netifReceive,
};

2. 添加SylixOS网络设备

在SylixOS中,通过 netdev_t 表示一个具体的网络设备:

/*
 * network device struct.
 */
typedef struct netdev {
#define NETDEV_VERSION  (0x00020003)
#define NETDEV_MAGIC    (0xf7e34a81 + NETDEV_VERSION)
  UINT32 magic_no;  /* MUST be NETDEV_MAGIC */

  char  dev_name[IF_NAMESIZE];  /* user network device name (such as igb* rtl* also call initialize with '\0') */
  char  if_name[IF_NAMESIZE];   /* add to system netif name (such as 'en'), after netdev_add() if_name saved full ifname by system */
  char *if_hostname;
  
#define NETDEV_INIT_LOAD_PARAM     0x01     /* load netif parameter when add to system */
#define NETDEV_INIT_LOAD_DNS       0x02     /* load dns parameter when add to system */
#define NETDEV_INIT_IPV6_AUTOCFG   0x04     /* use IPv6 auto config */
#define NETDEV_INIT_AS_DEFAULT     0x08
#define NETDEV_INIT_USE_DHCP       0x10     /* force use DHCP get address */
#define NETDEV_INIT_USE_DHCP6      0x40     /* force use IPv6 DHCP get address */
#define NETDEV_INIT_USE_AODV       0x80     /* use AODV(Ad-hoc) Only for LOWPAN (ipv4 only) */
#define NETDEV_INIT_DO_NOT         0x20     /* do not call init() function (Only used for net bridge) */
#define NETDEV_INIT_NO_TXQ         0x100    /* do not support txqueue */
#define NETDEV_INIT_TIGHT          0x200    /* add to bridge or bonding do not delete from system */
  UINT32 init_flags;
  
#define NETDEV_CHKSUM_GEN_IP       0x0001   /* tcp/ip stack will generate checksum IP, UDP, TCP, ICMP, ICMP6 */
#define NETDEV_CHKSUM_GEN_UDP      0x0002
#define NETDEV_CHKSUM_GEN_TCP      0x0004
#define NETDEV_CHKSUM_GEN_ICMP     0x0008
#define NETDEV_CHKSUM_GEN_ICMP6    0x0010
#define NETDEV_CHKSUM_CHECK_IP     0x0100   /* tcp/ip stack will check checksum IP, UDP, TCP, ICMP, ICMP6 */
#define NETDEV_CHKSUM_CHECK_UDP    0x0200
#define NETDEV_CHKSUM_CHECK_TCP    0x0400
#define NETDEV_CHKSUM_CHECK_ICMP   0x0800
#define NETDEV_CHKSUM_CHECK_ICMP6  0x1000
#define NETDEV_CHKSUM_ENABLE_ALL   0xffff   /* tcp/ip stack will gen/check all chksum */
#define NETDEV_CHKSUM_DISABLE_ALL  0x0000   /* tcp/ip stack will not gen/check all chksum */
  UINT32 chksum_flags;

#define NETDEV_TYPE_RAW             0
#define NETDEV_TYPE_ETHERNET        1
#define NETDEV_TYPE_LOWPAN          2
#define NETDEV_TYPE_LOWPAN_BLE      3
  UINT32 net_type;
  
  UINT64 speed; /* link layer speed bps */
  UINT32 mtu;   /* link layer max packet length (6LowPAN must be 1280) */
  
  UINT8 hwaddr_len;                     /* link layer address length MUST 6 or 8 */
  UINT8 hwaddr[NETIF_MAX_HWADDR_LEN];   /* link layer address */
  
  struct netdev_funcs *drv; /* netdev driver */
  
  void *priv;   /* user network device private data */
  
  /* the following member is used by system, driver MUST set zero and do not used! */
  int if_flags; /* ONLY IFF_RUNNING and IFF_UP flags will automated update, use netdev_flags() instead */
  
  /* wireless externed */
  void *wireless_handlers; /* iw_handler_def ptr */
  void *wireless_data; /* iw_public_data ptr */
  
  /* hwaddr filter list */
  struct netdev_mac *mac_filter;
  
  /* SylixOS Real-Time externd(poll mode) */
  struct netdev_poll poll;
  
  /* SylixOS Tx-Queue */
  void *kern_txq;
  
  /* SylixOS Reserve */
  void *kern_priv; /* kernel priv */
  void *kern_res[15];
  
  ULONG sys[254];  /* reserve for netif */
} netdev_t;

可以看出来这个数据结构有很多成员,下面介绍本次网络驱动中使用一些重要成员:

  • dev_name:网卡设备名字,这个名字在使用ifconfig命令查看网卡信息时回显示,同时也会在设置ifparam.ini文件时使用到,这个配置文件用于启动时自动设置网络ip地址等一些信息,在后面章节讲解。
  • if_name:网卡接口名字,一般都为"en",同样会在ifconfig命令时查看到网卡对应的接口名字。
  • if_hostname:网络主机名,一般在局域网中使用。
  • magic_no:固定为 NETDEV_MAGIC 。
  • init_flags:网卡初始化的属性,一般设置为NETDEV_INIT_LOAD_PARAM | NETDEV_INIT_LOAD_DNS | NETDEV_INIT_IPV6_AUTOCFG | NETDEV_INIT_AS_DEFAULT。其中NETDEV_INIT_LOAD_PARAM标志表示是否在初始化的时候加载ifparam.ini文件。
  • chksum_flags:校验选项,一般设置为 NETDEV_CHKSUM_ENABLE_ALL。
  • net_type:网络类型,一般都是以太网,设置为 NETDEV_TYPE_ETHERNET。
  • speed:网络工作速度,千兆/百兆/十兆,初始化时设置为0,后续在MAC和PHY自协商完成后会重新通过接口设置。
  • mtu:一般初始化时设置为1500。
  • hwaddr_len:网卡mac地址长度,一般为6字节。
  • hwaddr:网卡mac地址。
  • drv:网卡驱动操作集。
  • priv:网卡驱动私有数据。

 

SylixOS中通过netdev_add 接口来向内核添加一个网络设备,其函数原型如下:

int  netdev_add(netdev_t *netdev, const char *ip, const char *netmask, const char *gw, int if_flags);
  • netdev:网络设备。
  • ip:初始化时用的网卡ip地址。
  • netmask:初始化时用的网络掩码。
  • gw:初始化时用的网关ip地址。
  • if_flags:用于设置网卡的一些属性功能,一般为IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST。

我们定义一个全局变量表示网卡设备,并在 netifProbe 接口中初始化这个网络设备,最后加入到内核中:

struct netdev net_dev;

int netifProbe(void)
{
    struct netdev *pnetdev = &net_dev;

    sprintf(pnetdev->dev_name, "%s", "emac");
    strcpy(pnetdev->if_name, "en");
    pnetdev->if_hostname = "SylixOS D1";

    pnetdev->magic_no     = NETDEV_MAGIC;
    pnetdev->init_flags   = NETDEV_INIT_LOAD_PARAM   |
                            NETDEV_INIT_LOAD_DNS     |
                            NETDEV_INIT_IPV6_AUTOCFG |
                            NETDEV_INIT_AS_DEFAULT;
    pnetdev->chksum_flags = NETDEV_CHKSUM_ENABLE_ALL;
    pnetdev->net_type     = NETDEV_TYPE_ETHERNET;

    pnetdev->speed        = 0;
    pnetdev->mtu          = 1500;

    // TODO:应该从网卡设备中读取硬件MAC地址
    pnetdev->hwaddr_len   = 6;
    pnetdev->hwaddr[0]    = 0x00;
    pnetdev->hwaddr[1]    = 0x11;
    pnetdev->hwaddr[2]    = 0x22;
    pnetdev->hwaddr[3]    = 0x33;
    pnetdev->hwaddr[4]    = 0x44;
    pnetdev->hwaddr[5]    = 0x55;

    pnetdev->drv          = &netif_funcs;
    pnetdev->priv         = (void *)(pnetdev);

    netdev_add(pnetdev, "10.9.0.110", "255.255.0.0", "10.9.0.1",
               IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST);

    return 0;
}
gewenbin
  • 本文由 发表于 2022年5月3日19:34:13
  • 转载请务必保留本文链接:http://www.databusworld.cn/10713.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: