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; }
评论