Linux 网络设备驱动

news2024/11/24 20:31:21

一.网络设备驱动框架 

接收

将报文从设备驱动接受并送入协议栈

老API netif_if

编写网络设备驱动

步骤

1.注册一个网络设备

2.填充net_device_ops结构体

3.编写接收发送函数

// SPDX-License-Identifier: GPL-2.0-only
/*
 * This module emits "Hello, world" on printk when loaded.
 *
 * It is designed to be used for basic evaluation of the module loading
 * subsystem (for example when validating module signing/verification). It
 * lacks any extra dependencies, and will not normally be loaded by the
 * system unless explicitly requested by name.
 */


#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>

#include <linux/uaccess.h>
#include <linux/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>	/* For the statistics structure. */
#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <linux/net_tstamp.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
#include <linux/printk.h>
#include <linux/icmp.h>

#define DEBUG_TEST_NETDEV

#define TEST_NETDEV_NAME "test%d"
#define MAX_JUMBO_FRAME_SIZE         0x3F00

static struct net_device *test_netdev;
#ifdef DEBUG_TEST_NETDEV
static void dump_skb (struct sk_buff * skb) 
{
  print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
			 16, 1, skb->data, skb->len, true);
  return;
}
#endif
static int test_open(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return 0;
}
static int test_close(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return 0;
}
netdev_tx_t	test_xmit_frame(struct sk_buff *skb, struct net_device *dev)
{
	int len;
	struct ethhdr *ethh = eth_hdr(skb);
	struct iphdr *iph = ip_hdr(skb);
	struct icmphdr *icmph = icmp_hdr(skb);
	char mac_tmp[6];
	__be32 addr_tmp;
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	
#ifdef DEBUG_TEST_NETDEV
	dump_skb(skb);
#endif
	memcpy(mac_tmp, ethh->h_source, 6);
	memcpy(ethh->h_source, ethh->h_dest, 6);
	memcpy(ethh->h_dest, mac_tmp, 6);
	addr_tmp = iph->saddr;
	iph->saddr = iph->daddr;
	iph->daddr = addr_tmp;
	icmph->type = 0;
	icmph->checksum = 0;
	icmph->checksum = ip_compute_csum(icmph, iph->tot_len - iph->ihl);
	iph->check = 0;
	iph->check = ip_compute_csum(iph, iph->tot_len);
	
#ifdef DEBUG_TEST_NETDEV
	dump_skb(skb);
#endif
	skb_tx_timestamp(skb);

	/* do not fool net_timestamp_check() with various clock bases */
	skb->tstamp = 0;

	skb_orphan(skb);

	/* Before queueing this packet to netif_rx(),
	 * make sure dst is refcounted.
	 */
	skb_dst_force(skb);
	
	skb->protocol = eth_type_trans(skb, dev);



	len = skb->len;
	
	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
		test_netdev->stats.rx_bytes += len;
		test_netdev->stats.tx_bytes += len;
		test_netdev->stats.rx_packets++;
		test_netdev->stats.tx_packets++;
	}
	
	return NETDEV_TX_OK;
}

static void	test_set_rx_mode(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}

static int test_set_mac(struct net_device *dev, void *addr)
{
	struct sockaddr *saddr = addr;
	printk("<%s:%d> mac: %02x:%02x:%02x:%02x:%02x:%02x\n",__FUNCTION__,__LINE__, 
		saddr->sa_data[0],saddr->sa_data[1],saddr->sa_data[2],saddr->sa_data[3],saddr->sa_data[4],saddr->sa_data[5]);
	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
	return 0;
}

static void test_tx_timeout (struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}
static int test_change_mtu(struct net_device *dev, int new_mtu)
{
	printk("<%s:%d>: mtu: %d\n", __FUNCTION__,__LINE__, new_mtu);
	return 0;
}
static int test_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{

	printk("<%s:%d> cmd %d\n", __FUNCTION__,__LINE__, cmd);
	return 0;

}
static void test_netpoll(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}
static netdev_features_t test_fix_features(struct net_device *dev, netdev_features_t features)
{
	
	printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, dev->features);
	return features;
}
static int test_set_features(struct net_device *dev, netdev_features_t features)
{
	printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, features);
	dev->features = features;
	return 1;
}
static void test_change_rx_flags(struct net_device *dev, int flags)
{
	printk("<%s:%d> flags %d\n", __FUNCTION__,__LINE__, flags);
}

static const struct net_device_ops test_netdev_ops = {
	.ndo_open			= test_open,
	.ndo_stop			= test_close,
	.ndo_start_xmit		= test_xmit_frame,
	.ndo_set_rx_mode	= test_set_rx_mode,
	.ndo_set_mac_address	= test_set_mac,
	.ndo_tx_timeout		= test_tx_timeout,
	.ndo_change_mtu		= test_change_mtu,
	.ndo_do_ioctl		= test_ioctl,
	.ndo_validate_addr	= eth_validate_addr,

#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= test_netpoll,
#endif
	.ndo_fix_features		= test_fix_features,
	.ndo_set_features		= test_set_features,
   	.ndo_change_rx_flags 	= test_change_rx_flags,


};


static int __init test_netdev_init(void)
{

	
	int ret = 0;
	pr_warn("init test netdev\n");
	test_netdev = alloc_etherdev(sizeof(struct net_device));
	if (!test_netdev)
		goto out;
	test_netdev->netdev_ops = &test_netdev_ops;
	strcpy(test_netdev->name, TEST_NETDEV_NAME);
	ret = register_netdev(test_netdev);
	if(ret)
		goto failed;
	test_netdev->min_mtu = ETH_ZLEN - ETH_HLEN;
	test_netdev->max_mtu = MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN);
	memset(test_netdev->dev_addr, 0x60, test_netdev->addr_len);
	return 0;
failed:
	free_netdev(test_netdev);
out:
	return 0;
}

module_init(test_netdev_init);

static void __exit test_netdev_exit(void)
{
	pr_warn("exit test netdev\n");
	unregister_netdev(test_netdev);
	free_netdev(test_netdev);

}

module_exit(test_netdev_exit);

MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
MODULE_LICENSE("GPL");

 test0就是我们的驱动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2033373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IOS 02 SnapKit 纯代码开发

SnapKit是一个Swift语言写的自动布局框架&#xff0c;可以运行到iOS&#xff0c;Mac系统上&#xff1b;OC版本的框架是Masonry&#xff0c;都是出自同一个团队。 用这个框架的目的是&#xff0c;用起来比系统自带的API方便&#xff0c;他内部也是对系统API进行了封装。 为什么…

房产中介小程序

本文来自&#xff1a;ThinkPHPFastAdmin房产中介小程序 - 源码1688 应用介绍 产中介小程序是一款基于ThinkPHPFastAdmin开发的原生微信小程序&#xff0c;为房地产中介提供房源管理、发布、报备客户、跟踪客户以及营销推广获客等服务的系统。 前端演示&#xff1a; 后台演示&am…

HarmonyOS应用开发者基础认证(三)

1、针对包含文本元素的组件&#xff0c;例如Text、Button、TextInput等&#xff0c;可以使用下列哪些属性&#xff1a;&#xff08;全选&#xff09; 答案&#xff1a; fontColor fontFamily fontSize fontWeight fontStyle 分析&#xff1a; 2、关于Tabs组件和TabContent组件&…

【高效笔记与整理的艺术】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

通过jmeter对websocket后台做压测

后台使用java程序&#xff0c;通过springboot集成的stomp协议暴露websocket接口&#xff0c;所以下文测试过程会有特定的stomp报文&#xff0c;无需在意&#xff0c;关注流程即可 本次测试使用jmeter模拟大量用户接收群消息的场景&#xff0c;可覆盖连接数以及消息并发的压测 一…

CentOS7.6 RabbitMQ消息队列集群部署——实施方案

1、前期环境准备&#xff08;每个主机都配置&#xff09; 1.准备三台主机 IP地址主机名内存大小192.168.200.10 rabbitmq1 2G192.168.200.11rabbitmq22G192.168.200.55rabbitmq32G 2. 设置主机名 hostnamectl set-hostname 主机名suexit Ctrlr 3. 设置IP地址然后重启网卡 …

深度学习与图像修复:ADetailer插件在Stable Diffusion中的应用

文章目录 引言ADetailer插件介绍插件安装常用模型控制提示词参数配置参数详解 实践建议 示例插件的对比&#xff1a;1. ADetailer插件2. Photoshop插件&#xff08;如Nik Collection&#xff09;3. GIMP插件&#xff08;如GMIC&#xff09;4. Affinity Photo插件 结语 引言 无…

【物联网】(蓝牙篇)微信小程序ios如何自动打开蓝牙

微信小程序打开蓝牙的便捷之道——微信小程序ios如何自动打开蓝牙 随着智能手机蓝牙技术和物联网产品的普及&#xff0c;很多人在使用微信小程序时&#xff0c;都希望能够更便捷地打开蓝牙功能。 在iOS系统上&#xff0c;由于其封闭性和权限控制严格&#xff0c;使得自动打开蓝…

OpenGL ES->GLSurfaceView进行点、线段、三角形等基本图元的绘制

GLSurfaceView代码见OpenGL ES-&#xff1e;顶点着色器和片段着色器代码&#xff0c;只修改顶点数组&#xff0c;片段着色器的颜色&#xff0c;和绘制方式进行不同图元绘制 绘制点 GL_POINTS方式 // 顶点数据 val vertices floatArrayOf(0.8f, -0.8f, 0.0f,-0.8f, -0.8f, 0…

Python大数据分析——SVM模型(支持向量机)

Python大数据分析——SVM模型&#xff08;支持向量机&#xff09; 认知模型介绍距离计算模型思想目标函数函数与几何间隔 线性可分SVM模型目标函数函数代码 非线性可分SVM模型目标函数函数代码 示例手写体字母识别森林火灾面积预测 认知模型 介绍 超平面的理解&#xff1a;在…

Stable Diffusion绘画 | 进阶语法

控制提示词生效时间 使用格式1&#xff1a;[提示词:0-1数值] 举例&#xff1a;forest,lots of trees and stones,[flowers:0.7] 其中 [flowers:0.7] 表示整体画面采样值达到70%的进程以后&#xff0c;才开始计算花的采样。 因此&#xff0c;花的数量仅仅只跑了末段的30%&am…

LeetCode之回溯

1.全排列 1.1 题目 1.2 题解 LeetCode 力扣官方题解 1.3 代码 class Solution {public List<List<Integer>> permute(int[] nums) {// 创建一个空的列表 res&#xff0c;用于存储所有的排列结果List<List<Integer>> res new ArrayList<>();/…

C++入门基础:数据类型与条件判断语句

数据类型 基础数据类型 整型&#xff08;Integral Types&#xff09; int&#xff1a;基本的整型&#xff0c;大小依赖于编译器和平台&#xff0c;通常是32位或64位。 short&#xff1a;短整型&#xff0c;通常是16位。 long&#xff1a;长整型&#xff0c;大小依赖于编译…

本地部署Code Llama大模型结合Text generation Web UI远程运行LLM

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

pdf拆分成一页一页,怎么操作?pdf拆分的好用方法

pdf拆分成一页一页&#xff0c;怎么操作&#xff1f;PDF文件的拆分通常涉及到以下几个常见场景和需求&#xff1a;首先&#xff0c;PDF文件可能包含大量的页面&#xff0c;例如数百页的电子书或详尽的技术手册。在某些情况下&#xff0c;用户可能只需要处理其中的几页或者想要单…

揭秘!亚马逊与速卖通自养号测评:必备资源与技术要点

面对测评服务商的种种承诺&#xff0c;其真实性往往难以验证&#xff0c;而在像Facebook这样的社交平台上自行寻找测评资源&#xff0c;也显得相当困难和不切实际。随着产品即将上架&#xff0c;寻找一个可靠的测评服务似乎并不那么容易。因此&#xff0c;对于亚马逊等跨境平台…

运动耳机哪个品牌好用?五款质量一流品牌推荐!

运动耳机无疑是运动爱好者的绝佳伴侣&#xff0c;让每一次挥汗如雨的瞬间都伴随着无与伦比的音乐盛宴与舒适的佩戴感受。特别是对于跑步爱好者而言&#xff0c;一款优秀的运动耳机更是不可或缺的装备。然而&#xff0c;市场上的运动耳机种类繁多&#xff0c;质量也千差万别&…

Mirror学习笔记(五)概念指南

文章目录 一、Authority(权限)二、IDs(身份编号)三、Attributes(属性)四、Time Synchronization(同步时间)五、Data types(数据类型)六、Serialization(序列化)七、Synchronization(同步)八、Communications(通讯)九、GameObject(游戏对象) 顶层脚本API: Mirror是一个高级网络库…

Qt信号与槽-思维导图-学习笔记

Qt 信号与槽 Qt 信号与槽机制 基本概念 信号与槽机制&#xff1a;Qt 编程的基础与创新&#xff0c;使得处理界面组件交互操作更加直观和简单 信号&#xff08;Signal&#xff09;&#xff1a;在特定情况下被发射的事件&#xff0c;如按钮点击的 clicked() 信号、组合框项变化…

服务器数据恢复—服务器raid常见故障产生原因数据恢复方案

磁盘阵列&#xff08;raid&#xff09;是一种将多块物理硬盘整合成一个虚拟存储的技术。raid模块相当于一个存储管理中间层&#xff0c;上层接收并执行操作系统及文件系统的数据读写指令&#xff0c;下层管理数据在各个物理硬盘上的存储及读写。相对于单独的物理硬盘&#xff0…