Linux驱动开发(十八)---网络(网卡)驱动学习

前文回顾

《Linux驱动开发(一)—环境搭建与hello world》
《Linux驱动开发(二)—驱动与设备的分离设计》
《Linux驱动开发(三)—设备树》
《Linux驱动开发(四)—树莓派内核编译》
《Linux驱动开发(五)—树莓派设备树配合驱动开发》
《Linux驱动开发(六)—树莓派配合硬件进行字符驱动开发》
《Linux驱动开发(七)—树莓派按键驱动开发》
《Linux驱动开发(八)—树莓派SR04驱动开发》
《Linux驱动开发(九)—树莓派I2C设备驱动开发(BME280)》
《Linux驱动开发(十)—树莓派输入子系统学习(红外接收)》
《Linux驱动开发(十一)—树莓派SPI驱动学习(OLED)》
《Linux驱动开发(十二)—树莓派framebuffer学习(改造OLED)》
《Linux驱动开发(十三)—USB驱动HID开发学习(鼠标)》
《Linux驱动开发(十四)—USB驱动开发学习(键盘+鼠标)》
《Linux驱动开发(十五)—如何使用内核现有驱动(显示屏)》
《Linux驱动开发(十六)—块设备驱动》
《Linux驱动开发(十七)—树莓派PWM驱动》

今天来学一下驱动中的第三类设备,网络设备的驱动。边学边写,慢慢理解。
在这里插入图片描述

网络设备驱动程序结构

Linux网络设备驱动程序的体系结构如图所示,从上到下可以划分为4层,依次为网络协议接口层、网络设备接口层、提供实际功能的设备驱动功能层以及网络设备与媒介层,这4层的作用如下所示:

  1. 网络协议接口层
    向网络层协议提供统一的数据包收发接口,不论上层协议是ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()数接收数据。这一层的存在使得上层协议独立于具体的设备。
  2. 网络设备接口层
    向协议接口层提供统一的用于描述具体网络设备属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器。实际上,网络设备接口层从宏观上规划了具体操作硬件的设备驱动功能层的结构。
  3. 设备驱动功能层
    设备驱动功能层的各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,它通过hard_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作。
  4. 网络设备与媒介层
    网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和具体的传输媒介,网络适配器被设备驱动功能层中的函数在物理上驱动。对于Linux系统而言,网络设备和媒介都可以是虚拟的。
    在这里插入图片描述
    以上内容来自《Linux设备驱动开发详解》,其中下面这句就是关键
    在设计具体的网络设备驱动程序时,我们需要完成的主要工作是
    编写设备驱动功能层的相关函数

    填充net device数据结构
    的内容
    并将net device注册入内核。
    看看,三个核心操作。
    在这里插入图片描述

虚拟网卡

来看一个虚拟网卡的例子,就是直接构造软件网卡,来看一下实现过程

#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netdev_features.h>
 
static struct net_device *virt_net;
   
static void virt_rs_packet(struct sk_buff *skb, struct net_device *dev)
{
   
	unsigned char *type;
	struct iphdr *ih;
	__be32 *saddr, *daddr, tmp;
	unsigned char tmp_dev_addr[ETH_ALEN];
	struct ethhdr *ethhdr;
	struct sk_buff *rx_skb;
	int ret;
 
	//对调ethhdr结构体 "源/目的"MAC地址*/
	ethhdr = (struct ethhdr *)skb->data;
	memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
	memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
	memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

	//对调iphdr结构体"源/目的" IP地址
	ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
	saddr = &ih->saddr;
	daddr = &ih->daddr;
	tmp = *saddr;
	*saddr = *daddr;
	*daddr = tmp;
        
    ih->check=0;
    ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
	
	//之前是发送ping包0x08,需要改为0x00,表示接收ping包
	type = skb
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值