⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 af_ax25.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
				return -EINVAL;			dtmp.ndigi      = usax->sax25_ndigis;			while (ct < usax->sax25_ndigis) {				dtmp.repeated[ct] = 0;				dtmp.calls[ct]    = fsa->fsa_digipeater[ct];				ct++;			}			dtmp.lastrepeat = 0;		}		sax = *usax;		if (sk->type == SOCK_SEQPACKET && ax25cmp(&sk->protinfo.ax25->dest_addr, &sax.sax25_call) != 0)			return -EISCONN;		if (usax->sax25_ndigis == 0)			dp = NULL;		else			dp = &dtmp;	} else {		/*		 *	FIXME: 1003.1g - if the socket is like this because		 *	it has become closed (not started closed) and is VC		 *	we ought to SIGPIPE, EPIPE		 */		if (sk->state != TCP_ESTABLISHED)			return -ENOTCONN;		sax.sax25_family = AF_AX25;		sax.sax25_call   = sk->protinfo.ax25->dest_addr;		dp = sk->protinfo.ax25->digipeat;	}	SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n");	/* Build a packet */	SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n");	/* Assume the worst case */	size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)		return err;	skb_reserve(skb, size - len);	SOCK_DEBUG(sk, "AX.25: Appending user data\n");	/* User data follows immediately after the AX.25 data */	memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);	skb->nh.raw = skb->data;	/* Add the PID if one is not supplied by the user in the skb */	if (!sk->protinfo.ax25->pidincl) {		asmptr  = skb_push(skb, 1);		*asmptr = sk->protocol;	}	SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n");	if (sk->type == SOCK_SEQPACKET) {		/* Connected mode sockets go via the LAPB machine */		if (sk->state != TCP_ESTABLISHED) {			kfree_skb(skb);			return -ENOTCONN;		}		ax25_output(sk->protinfo.ax25, sk->protinfo.ax25->paclen, skb);	/* Shove it onto the queue and kick */		return len;	} else {		asmptr = skb_push(skb, 1 + ax25_addr_size(dp));		SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);		if (dp != NULL)			SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);		/* Build an AX.25 header */		asmptr += (lv = ax25_addr_build(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS));		SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);		skb->h.raw = asmptr;		SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);		*asmptr = AX25_UI;		/* Datagram frames go straight out of the door as UI */		skb->dev      = sk->protinfo.ax25->ax25_dev->dev;		ax25_queue_xmit(skb);		return len;	}}static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){	struct sock *sk = sock->sk;	int copied;	struct sk_buff *skb;	int er;	/*	 * 	This works for seqpacket too. The receiver has ordered the	 *	queue for us! We do one quick check first though	 */	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED)		return -ENOTCONN;	/* Now we can treat all alike */	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)		return er;	if (!sk->protinfo.ax25->pidincl)		skb_pull(skb, 1);		/* Remove PID */	skb->h.raw = skb->data;	copied     = skb->len;	if (copied > size) {		copied = size;		msg->msg_flags |= MSG_TRUNC;	}			skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (msg->msg_namelen != 0) {		struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;		ax25_digi digi;		ax25_address dest;		ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, NULL, &dest, &digi, NULL, NULL);		sax->sax25_family = AF_AX25;		/* We set this correctly, even though we may not let the		   application know the digi calls further down (because it		   did NOT ask to know them).  This could get political... **/		sax->sax25_ndigis = digi.ndigi;		sax->sax25_call   = dest;		if (sax->sax25_ndigis != 0) {			int ct;			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;			for (ct = 0; ct < digi.ndigi; ct++)				fsa->fsa_digipeater[ct] = digi.calls[ct];		}		msg->msg_namelen = sizeof(struct full_sockaddr_ax25);	}	skb_free_datagram(sk, skb);	return copied;}static int ax25_shutdown(struct socket *sk, int how){	/* FIXME - generate DM and RNR states */	return -EOPNOTSUPP;}static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	switch (cmd) {		case TIOCOUTQ: {			long amount;			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);			if (amount < 0)				amount = 0;			return put_user(amount, (int *)arg);		}		case TIOCINQ: {			struct sk_buff *skb;			long amount = 0L;			/* These two are safe on a single CPU system as only user tasks fiddle here */			if ((skb = skb_peek(&sk->receive_queue)) != NULL)				amount = skb->len;			return put_user(amount, (int *)arg);		}		case SIOCGSTAMP:			if (sk != NULL) {				if (sk->stamp.tv_sec == 0)					return -ENOENT;				return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;	 		}			return -EINVAL;		case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */		case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */		case SIOCAX25GETUID: {			struct sockaddr_ax25 sax25;			if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))				return -EFAULT;			return ax25_uid_ioctl(cmd, &sax25);		}		case SIOCAX25NOUID: {	/* Set the default policy (default/bar) */			long amount;			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (get_user(amount, (long *)arg))				return -EFAULT;			if (amount > AX25_NOUID_BLOCK)				return -EINVAL;			ax25_uid_policy = amount;			return 0;		}		case SIOCADDRT:		case SIOCDELRT:		case SIOCAX25OPTRT:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			return ax25_rt_ioctl(cmd, (void *)arg);		case SIOCAX25CTLCON:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			return ax25_ctl_ioctl(cmd, (void *)arg);		case SIOCAX25GETINFO: 		case SIOCAX25GETINFOOLD: {			struct ax25_info_struct ax25_info;			ax25_info.t1        = sk->protinfo.ax25->t1   / HZ;			ax25_info.t2        = sk->protinfo.ax25->t2   / HZ;			ax25_info.t3        = sk->protinfo.ax25->t3   / HZ;			ax25_info.idle      = sk->protinfo.ax25->idle / (60 * HZ);			ax25_info.n2        = sk->protinfo.ax25->n2;			ax25_info.t1timer   = ax25_display_timer(&sk->protinfo.ax25->t1timer)   / HZ;			ax25_info.t2timer   = ax25_display_timer(&sk->protinfo.ax25->t2timer)   / HZ;			ax25_info.t3timer   = ax25_display_timer(&sk->protinfo.ax25->t3timer)   / HZ;			ax25_info.idletimer = ax25_display_timer(&sk->protinfo.ax25->idletimer) / (60 * HZ);			ax25_info.n2count   = sk->protinfo.ax25->n2count;			ax25_info.state     = sk->protinfo.ax25->state;			ax25_info.rcv_q     = atomic_read(&sk->rmem_alloc);			ax25_info.snd_q     = atomic_read(&sk->wmem_alloc);			ax25_info.vs        = sk->protinfo.ax25->vs;			ax25_info.vr        = sk->protinfo.ax25->vr;			ax25_info.va        = sk->protinfo.ax25->va;			ax25_info.vs_max    = sk->protinfo.ax25->vs; /* reserved */			ax25_info.paclen    = sk->protinfo.ax25->paclen;			ax25_info.window    = sk->protinfo.ax25->window;			/* old structure? */			if (cmd == SIOCAX25GETINFOOLD) {				static int warned = 0;				if (!warned) {					printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",						current->comm);					warned=1;				}				if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated)))					return -EFAULT;			} else {				if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct)))					return -EINVAL;			} 			return 0;		}		case SIOCAX25ADDFWD:		case SIOCAX25DELFWD: {			struct ax25_fwd_struct ax25_fwd;			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))				return -EFAULT;			return ax25_fwd_ioctl(cmd, &ax25_fwd);		}		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFDSTADDR:		case SIOCSIFDSTADDR:		case SIOCGIFBRDADDR:		case SIOCSIFBRDADDR:		case SIOCGIFNETMASK:		case SIOCSIFNETMASK:		case SIOCGIFMETRIC:		case SIOCSIFMETRIC:			return -EINVAL;		default:			return dev_ioctl(cmd, (void *)arg);	}	/*NOTREACHED*/	return 0;}static int ax25_get_info(char *buffer, char **start, off_t offset, int length){	ax25_cb *ax25;	int k;	int len = 0;	off_t pos = 0;	off_t begin = 0;	cli();	/*	 * New format:	 * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode 	 */		for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {		len += sprintf(buffer+len, "%8.8lx %s %s%s ", 				(long) ax25, 				ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,				ax2asc(&ax25->source_addr),				ax25->iamdigi? "*":"");		len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr));						for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {			len += sprintf(buffer+len, ",%s%s",					ax2asc(&ax25->digipeat->calls[k]),					ax25->digipeat->repeated[k]? "*":"");		}				len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d",			ax25->state,			ax25->vs, ax25->vr, ax25->va,			ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ,			ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ,			ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ,			ax25_display_timer(&ax25->idletimer) / (60 * HZ),			ax25->idle / (60 * HZ),			ax25->n2count, ax25->n2,			ax25->rtt / HZ,			ax25->window,			ax25->paclen);		if (ax25->sk != NULL) {			len += sprintf(buffer + len, " %d %d %ld\n",				atomic_read(&ax25->sk->wmem_alloc),				atomic_read(&ax25->sk->rmem_alloc),				ax25->sk->socket != NULL ? ax25->sk->socket->inode->i_ino : 0L);		} else {			len += sprintf(buffer + len, " * * *\n");		}		pos = begin + len;		if (pos < offset) {			len   = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	sti();	*start = buffer + (offset - begin);	len   -= (offset - begin);	if (len > length) len = length;	return(len);}static struct net_proto_family ax25_family_ops = {	family:		PF_AX25,	create:		ax25_create,};static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {	family:		PF_AX25,	release:	ax25_release,	bind:		ax25_bind,	connect:	ax25_connect,	socketpair:	sock_no_socketpair,	accept:		ax25_accept,	getname:	ax25_getname,	poll:		datagram_poll,	ioctl:		ax25_ioctl,	listen:		ax25_listen,	shutdown:	ax25_shutdown,	setsockopt:	ax25_setsockopt,	getsockopt:	ax25_getsockopt,	sendmsg:	ax25_sendmsg,	recvmsg:	ax25_recvmsg,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(ax25_proto, PF_AX25);/* *	Called by socket.c on kernel start up */static struct packet_type ax25_packet_type = {	type:		__constant_htons(ETH_P_AX25),	func:		ax25_kiss_rcv,};static struct notifier_block ax25_dev_notifier = {	notifier_call:	ax25_device_event,};EXPORT_SYMBOL(ax25_encapsulate);EXPORT_SYMBOL(ax25_rebuild_header);EXPORT_SYMBOL(ax25_findbyuid);EXPORT_SYMBOL(ax25_find_cb);EXPORT_SYMBOL(ax25_linkfail_register);EXPORT_SYMBOL(ax25_linkfail_release);EXPORT_SYMBOL(ax25_listen_register);EXPORT_SYMBOL(ax25_listen_release);EXPORT_SYMBOL(ax25_protocol_register);EXPORT_SYMBOL(ax25_protocol_release);EXPORT_SYMBOL(ax25_send_frame);EXPORT_SYMBOL(ax25_uid_policy);EXPORT_SYMBOL(ax25cmp);EXPORT_SYMBOL(ax2asc);EXPORT_SYMBOL(asc2ax);EXPORT_SYMBOL(null_ax25_address);EXPORT_SYMBOL(ax25_display_timer);static char banner[] __initdata = KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n";static int __init ax25_init(void){	sock_register(&ax25_family_ops);	dev_add_pack(&ax25_packet_type);	register_netdevice_notifier(&ax25_dev_notifier);	ax25_register_sysctl();	proc_net_create("ax25_route", 0, ax25_rt_get_info);	proc_net_create("ax25", 0, ax25_get_info);	proc_net_create("ax25_calls", 0, ax25_uid_get_info);	printk(banner);	return 0;}module_init(ax25_init);MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");static void __exit ax25_exit(void){	proc_net_remove("ax25_route");	proc_net_remove("ax25");	proc_net_remove("ax25_calls");	ax25_rt_free();	ax25_uid_free();	ax25_dev_free();	ax25_unregister_sysctl();	unregister_netdevice_notifier(&ax25_dev_notifier);	dev_remove_pack(&ax25_packet_type);	sock_unregister(PF_AX25);}module_exit(ax25_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -