概述
与字符和块设备不同,网络设备没有设备文件。
但与块设备在读写上有类似之处,
对用户层来讲,用户的IO请求只是入队,内核对入队的IO请求用调度算法进行均匀
化,瓜分成很多个小的任务块放入到一个请求队列中;对于驱动来讲,驱动只要从请求队列中出队一个小的任务块(称作“请求”)进行处理。
网卡操作:
1、网卡信息:
<include/uapi/linux/if.h>
struct ifreq {
#define IFHWADDRLEN 6
union
{
char ifrn_name[IFNAMSIZ]; //物理接口名(网卡名)
} ifr_ifrn;
union {
struct sockaddr ifru_addr; //ip地址
struct sockaddr ifru_dstaddr; //目标地址
struct sockaddr ifru_broadaddr;//广播地址
struct sockaddr ifru_netmask; //子网掩码
struct sockaddr ifru_hwaddr; //MAC
short ifru_flags; //标志
int ifru_ivalue;
int ifru_mtu; //最大包长
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ];
char ifru_newname[IFNAMSIZ];
void __user * ifru_data;
struct if_settings ifru_settings;
} ifr_ifru;
};
2.读取或设置网卡参数:
对以上结构体中成员进行赋值或读取其状态的函数是ioctl(),如:
if (ioctl(sock, SIOCGIFADDR, &device) < 0)
对应的命令码已经被内核封装成宏,在<include/uapi/linux/sockios.h>,例如:
#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */
#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */
#define SIOCGIFNETMASK 0x891b /* get network PA mask */
3.使能和关闭网卡:
/*使能网卡的shell命令*/
strace ifconfig eth0 up
/*关闭网卡的shell命令*/
strace ifconfig eth0 down
net_device 结构体:
<include/linux/netdevice.h>
struct net_device {
char name[IFNAMSIZ]; //物理接口名(网卡名)
struct hlist_node name_hlist;
char *ifalias;
/*物理信息:IO地址、中断号*/
unsigned long mem_end; //缓存结束
unsigned long mem_start; //缓存起始
unsigned long base_addr; //基地址
int irq; //中断
netdev_features_t features; //可变特性,DMA,校验等一系列附加特性
netdev_features_t hw_features; //用户不能改变的私有特性
unsigned int flags; //可变标准
unsigned int priv_flags; //用户不能改变的标准
const struct net_device_ops *netdev_ops; //操作方法集
const struct ethtool_ops *ethtool_ops; //eth工具集操作方法集
const struct header_ops *header_ops; //协议头操作方法集
unsigned char if_port; //接口类型
unsigned int mtu; //最大包长
unsigned short type; //网络包类型
unsigned short hard_header_len; //硬件协议头长度
unsigned char perm_addr[MAX_ADDR_LEN]; //MAC地址
unsigned char addr_len; //MAC地址长度
unsigned short dev_id; //指向mac地址
struct in_device __rcu *ip_ptr; //ip地址
...
};
操作方法集:
<include/linux/netdevcice.h>
struct net_device_ops {
int (*ndo_init)(struct net_device *dev); //构造初始化对象
void (*ndo_uninit)(struct net_device *dev);//析构函数,回收清理
int (*ndo_open)(struct net_device *dev); //打开设备
int (*ndo_stop)(struct net_device *dev); //停止
netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
struct net_device *dev);//发送
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr); //设置mac地址
int (*ndo_validate_addr)(struct net_device *dev);//检查MAC是否有效
int (*ndo_do_ioctl)(struct net_device *dev,
struct ifreq *ifr, int cmd);//ioctl
int (*ndo_set_config)(struct net_device *dev,
struct ifmap *map);//修改网卡io地址、中断等网卡物理信息
int (*ndo_change_mtu)(struct net_device *dev,
int new_mtu); //设置最大包长
void (*ndo_tx_timeout) (struct net_device *dev); //超时重发
...
重要的回调函数接口:
1.发送回调函数
当用户用send函数往网卡发数据时,系统经过VFS文件系统找到相应的struct net_device网络设备句柄,
然后找到这个句柄中的操作方法集,再进一步找到相应的回调函数指针ndo_start_xmit,最终回调了驱动层的函数。
/*
* 功能:把套接字缓冲区中的数据写网卡
* 输入参数:struct sk_buff *skb:网卡的缓存
* struct net_device *dev:设备句柄
* 返回值:
*/
netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
struct net_device *dev);
2.接收数据:
操作方法集中没有,因为接收是靠中断来实现的。