IPROUTE2 FOR CAN 一个简化的can专用设置的程序

IPROUTE2 功能太大,太全不方便使用

由于FLASH空间有限只设置CAN 需要一个小的程序只控制CAN 的状态。

相关改动主要代码已上传

PC 上测试

加载vcan内核模块: sudo modprobe vcan
创建虚拟CAN接口: sudo ip link add dev vcan0 type vcan
将虚拟CAN接口处于在线状态: sudo ip link set up vcan0

然后,通过命令ip addr | grep “can” 来验证是否可用并处于在线状态
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/xiandang8023/article/details/127990159

初步分析

设置CAN ip link set can0 type can bitrate 125000时
iplink.c -> do_iplink-> iplink_modify(RTM_NEWLINK, 0, argc-1, argv+1);

iplink_modify->rtnl_talk->__rtnl_talk(libnetlink.c)
最终是调用sendmsg 和recvmsg和底层通信。

static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
{
	char *type = NULL;
	struct iplink_req req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
		.n.nlmsg_flags = NLM_F_REQUEST | flags,
		.n.nlmsg_type = cmd,
		.i.ifi_family = preferred_family,
	};
	int ret;

	ret = iplink_parse(argc, argv, &req, &type);//获取argc 参数个数 argv指针 获取信息看下面分析 针对can 命令获取了 link 参数和 set 参数 初步判断返回&req 是设备名称
	if (ret < 0)
		return ret;

	if (type) {
		struct link_util *lu;
		struct rtattr *linkinfo;
		char *ulinep = strchr(type, '_');
		int iflatype;

		linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
			 strlen(type));

		lu = get_link_kind(type);//根据type类型调用函数或库 can 应该是关联 iplink_can.c 的内容
		/*如果只使用CAN 可以直接如下处理
		#if 0
		lu = get_link_kind(type);
		#else
		lu=&can_link_util;
		#endif
        */
		if (ulinep && !strcmp(ulinep, "_slave"))
			iflatype = IFLA_INFO_SLAVE_DATA;
		else
			iflatype = IFLA_INFO_DATA;

		argc -= ret;
		argv += ret;

		if (lu && lu->parse_opt && argc) {
			struct rtattr *data;

			data = addattr_nest(&req.n, sizeof(req), iflatype);//nlmsghdr 信息报添加信息

			if (lu->parse_opt(lu, argc, argv, &req.n))//实际调用can_parse_opt 信息添加CAN设置信息 下面分析设置内容 
				return -1;

			addattr_nest_end(&req.n, data);//完成nlmsghdr  相关设置
		} else if (argc) {
			if (matches(*argv, "help") == 0)
				usage();
			fprintf(stderr,
				"Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
				*argv);
			return -1;
		}
		addattr_nest_end(&req.n, linkinfo);
	} else if (flags & NLM_F_CREATE) {
		fprintf(stderr,
			"Not enough information: \"type\" argument is required\n");
		return -1;
	}
    //下面的rth 是从ip.c 中rtnl_open 中打开
	if (echo_request)
		ret = rtnl_echo_talk(&rth, &req.n, json, print_linkinfo);//调用设置并返回echo
	else
		ret = rtnl_talk(&rth, &req.n, NULL);//调用设置,不返回

	if (ret)
		return -2;

	/* remove device from cache; next use can refresh with new data */
	ll_drop_by_index(req.i.ifi_index);

	return 0;
}

iplink_parse 中对应调用有

		 if (matches(*argv, "link") == 0) {
					NEXT_ARG();
					link = *argv;
。。。。

		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} 
	if (bt.bitrate || bt.tq)
		addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
	if (dbt.bitrate || dbt.tq)
		addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt));
	if (cm.mask)
		addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));

	if (tdcv != -1 || tdco != -1 || tdcf != -1) {
		tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
		if (tdcv != -1)
			addattr32(n, 1024, IFLA_CAN_TDC_TDCV, tdcv);
		if (tdco != -1)
			addattr32(n, 1024, IFLA_CAN_TDC_TDCO, tdco);
		if (tdcf != -1)
			addattr32(n, 1024, IFLA_CAN_TDC_TDCF, tdcf);
		addattr_nest_end(n, tdc);
	}
static int can_parse_opt(struct link_util *lu, int argc, char **argv,
			 struct nlmsghdr *n){
			 。。。。。。
if (bt.bitrate || bt.tq)
	addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
if (dbt.bitrate || dbt.tq)
	addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt));
if (cm.mask)
	addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));

if (tdcv != -1 || tdco != -1 || tdcf != -1) {
	tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
	if (tdcv != -1)
		addattr32(n, 1024, IFLA_CAN_TDC_TDCV, tdcv);
	if (tdco != -1)
		addattr32(n, 1024, IFLA_CAN_TDC_TDCO, tdco);
	if (tdcf != -1)
		addattr32(n, 1024, IFLA_CAN_TDC_TDCF, tdcf);
	addattr_nest_end(n, tdc);
}
。。。。。。

获取类型的动态库

dlsym函数的功能就是可以从共享库(动态库)中获取符号(全局变量与函数符号)地址,通常用于获取函数符号地址,这样可用于对共享库中函数的包装;下面是函数原型及需要包含的头文件。
动态库
void *dlopen(const char *filename, int flag);

其中flag有:RTLD_LAZY RTLD_NOW RTLD_GLOBAL,其含义分别为:

RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。

RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL,错误为:
undefined symbol: xxxx…

RTLD_GLOBAL: 它的含义是使得库中的解析的定义变量在随后的其它的链接库中变得可以使用。

下面程序输出

/usr/lib/ip/link_can.so1
dlh == NULL
dlh  0x58b62e0
can_link_util
return 1 


struct link_util *get_link_kind(const char *id)
{
	void *dlh;
	char buf[256];
	struct link_util *l;
	printf("%s\n",__FUNCTION__);
	for (l = linkutil_list; l; l = l->next)//如果包里已经使用过了就不进行查找,没有进入后面进行相关的库查找。
		if (strcmp(l->id, id) == 0)
			return l;

	snprintf(buf, sizeof(buf), "%s/link_%s.so", get_ip_lib_dir(), id);
	printf( "%s/link_%s.so", get_ip_lib_dir(), id);
	dlh = dlopen(buf, RTLD_LAZY);
	if (dlh == NULL) {
		printf( "1\n");
		/* look in current binary, only open once */
		dlh = BODY;
		if (dlh == NULL) {
			printf( "2\n");
			dlh = BODY = dlopen(NULL, RTLD_LAZY);
			if (dlh == NULL){
				return NULL;
			}
			printf( "dlh  0x%x\n",(unsigned int )dlh);
		}
	}
	printf( "%s_link_util\n", id);

	snprintf(buf, sizeof(buf), "%s_link_util", id);
	l = dlsym(dlh, buf);
	if (l == NULL){
		printf("dlsym =NULL \n");
		return NULL;
		}
	printf("return 1 \n");
	l->next = linkutil_list;
	linkutil_list = l;
	return l;
}

1直接在编译output 下修改可以不用改makefile

在这里插入图片描述

2IP 文件夹下MAKE FILE 修改

在这里插入图片描述

IPLINK 最主要修改

原文件是从 link*.so 对应设备的库中找到link_util结构体,只支持CAN那么直接返回对应结构体指针就好。

struct link_util *get_link_kind(const char *id)
{
	if(strcmp(id,id)==0)
		return &can_link_util;
	else
		printf( "Special versions olny support CAN \n");
}

去除了IPLINK_IOCTL_COMPAT 的支持

去除了 show、lst、list等不用上的内容。

缩小大小,程序从原有的680K 减少到了115.

在这里插入图片描述

  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值