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

📄 af_x25.c

📁 之前积累的一个X25在LINUX下的协议实现代码,现在估计应该比较少见了,应该是收藏的东西
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (msg->msg_flags & MSG_OOB)		skb_queue_tail(&x25->interrupt_out_queue, skb);	else {	        len = x25_output(sk, skb);		if (len < 0)			kfree_skb(skb);		else if (x25->qbitincl)			len++;	}	/*	 * lock_sock() is currently only used to serialize this x25_kick()	 * against input-driven x25_kick() calls. It currently only blocks	 * incoming packets for this socket and does not protect against	 * any other socket state changes and is not called from anywhere	 * else. As x25_kick() cannot block and as long as all socket	 * operations are BKL-wrapped, we don't need take to care about	 * purging the backlog queue in x25_release().	 *	 * Using lock_sock() to protect all socket operations entirely	 * (and making the whole x25 stack SMP aware) unfortunately would	 * require major changes to {send,recv}msg and skb allocation methods.	 * -> 2.5 ;)	 */	lock_sock(sk);	x25_kick(sk);	release_sock(sk);	rc = len;out:	return rc;out_kfree_skb:	kfree_skb(skb);	goto out;}static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,		       struct msghdr *msg, size_t size,		       int flags){	struct sock *sk = sock->sk;	struct x25_sock *x25 = x25_sk(sk);	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;	size_t copied;	int qbit;	struct sk_buff *skb;	unsigned char *asmptr;	int rc = -ENOTCONN;	/*	 * This works for seqpacket too. The receiver has ordered the queue for	 * us! We do one quick check first though	 */	if (sk->sk_state != TCP_ESTABLISHED)		goto out;	if (flags & MSG_OOB) {		rc = -EINVAL;		if (sock_flag(sk, SOCK_URGINLINE) ||		    !skb_peek(&x25->interrupt_in_queue))			goto out;		skb = skb_dequeue(&x25->interrupt_in_queue);		skb_pull(skb, X25_STD_MIN_LEN);		/*		 *	No Q bit information on Interrupt data.		 */		if (x25->qbitincl) {			asmptr  = skb_push(skb, 1);			*asmptr = 0x00;		}		msg->msg_flags |= MSG_OOB;	} else {		/* Now we can treat all alike */		skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,					flags & MSG_DONTWAIT, &rc);		if (!skb)			goto out;		qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;		skb_pull(skb, x25->neighbour->extended ?				X25_EXT_MIN_LEN : X25_STD_MIN_LEN);		if (x25->qbitincl) {			asmptr  = skb_push(skb, 1);			*asmptr = qbit;		}	}	skb->h.raw = skb->data;	copied = skb->len;	if (copied > size) {		copied = size;		msg->msg_flags |= MSG_TRUNC;	}	/* Currently, each datagram always contains a complete record */ 	msg->msg_flags |= MSG_EOR;	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (rc)		goto out_free_dgram;	if (sx25) {		sx25->sx25_family = AF_X25;		sx25->sx25_addr   = x25->dest_addr;	}	msg->msg_namelen = sizeof(struct sockaddr_x25);	lock_sock(sk);	x25_check_rbuf(sk);	release_sock(sk);	rc = copied;out_free_dgram:	skb_free_datagram(sk, skb);out:	return rc;}static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	struct x25_sock *x25 = x25_sk(sk);	void __user *argp = (void __user *)arg;	int rc;	switch (cmd) {		case TIOCOUTQ: {			int amount = sk->sk_sndbuf -				     atomic_read(&sk->sk_wmem_alloc);			if (amount < 0)				amount = 0;			rc = put_user(amount, (unsigned int __user *)argp);			break;		}		case TIOCINQ: {			struct sk_buff *skb;			int amount = 0;			/*			 * These two are safe on a single CPU system as			 * only user tasks fiddle here			 */			if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)				amount = skb->len;			rc = put_user(amount, (unsigned int __user *)argp);			break;		}		case SIOCGSTAMP:			rc = -EINVAL;			if (sk)				rc = sock_get_timestamp(sk, 						(struct timeval __user *)argp); 			break;		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFDSTADDR:		case SIOCSIFDSTADDR:		case SIOCGIFBRDADDR:		case SIOCSIFBRDADDR:		case SIOCGIFNETMASK:		case SIOCSIFNETMASK:		case SIOCGIFMETRIC:		case SIOCSIFMETRIC:			rc = -EINVAL;			break;		case SIOCADDRT:		case SIOCDELRT:			rc = -EPERM;			if (!capable(CAP_NET_ADMIN))				break;			rc = x25_route_ioctl(cmd, argp);			break;		case SIOCX25GSUBSCRIP:			rc = x25_subscr_ioctl(cmd, argp);			break;		case SIOCX25SSUBSCRIP:			rc = -EPERM;			if (!capable(CAP_NET_ADMIN))				break;			rc = x25_subscr_ioctl(cmd, argp);			break;		case SIOCX25GFACILITIES: {			struct x25_facilities fac = x25->facilities;			rc = copy_to_user(argp, &fac,					  sizeof(fac)) ? -EFAULT : 0;			break;		}		case SIOCX25SFACILITIES: {			struct x25_facilities facilities;			rc = -EFAULT;			if (copy_from_user(&facilities, argp,					   sizeof(facilities)))				break;			rc = -EINVAL;			if (sk->sk_state != TCP_LISTEN &&			    sk->sk_state != TCP_CLOSE)				break;			if (facilities.pacsize_in < X25_PS16 ||			    facilities.pacsize_in > X25_PS4096)				break;			if (facilities.pacsize_out < X25_PS16 ||			    facilities.pacsize_out > X25_PS4096)				break;			if (facilities.winsize_in < 1 ||			    facilities.winsize_in > 127)				break;			if (facilities.throughput < 0x03 ||			    facilities.throughput > 0xDD)				break;			if (facilities.reverse &&				(facilities.reverse | 0x81)!= 0x81)				break;			x25->facilities = facilities;			rc = 0;			break;		}		case SIOCX25GDTEFACILITIES: { 			rc = copy_to_user(argp, &x25->dte_facilities,						sizeof(x25->dte_facilities));			if (rc)				rc = -EFAULT; 			break; 		}	 	case SIOCX25SDTEFACILITIES: {	 		struct x25_dte_facilities dtefacs;	 		rc = -EFAULT;		 	if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))				break;			rc = -EINVAL;			if (sk->sk_state != TCP_LISTEN &&					sk->sk_state != TCP_CLOSE)				break;			if (dtefacs.calling_len > X25_MAX_AE_LEN)				break;			if (dtefacs.calling_ae == NULL)				break;			if (dtefacs.called_len > X25_MAX_AE_LEN)				break;			if (dtefacs.called_ae == NULL)				break;			x25->dte_facilities = dtefacs;			rc = 0;			break;		}		case SIOCX25GCALLUSERDATA: {			struct x25_calluserdata cud = x25->calluserdata;			rc = copy_to_user(argp, &cud,					  sizeof(cud)) ? -EFAULT : 0;			break;		}		case SIOCX25SCALLUSERDATA: {			struct x25_calluserdata calluserdata;			rc = -EFAULT;			if (copy_from_user(&calluserdata, argp,					   sizeof(calluserdata)))				break;			rc = -EINVAL;			if (calluserdata.cudlength > X25_MAX_CUD_LEN)				break;			x25->calluserdata = calluserdata;			rc = 0;			break;		}		case SIOCX25GCAUSEDIAG: {			struct x25_causediag causediag;			causediag = x25->causediag;			rc = copy_to_user(argp, &causediag,					  sizeof(causediag)) ? -EFAULT : 0;			break;		}		case SIOCX25SCUDMATCHLEN: {			struct x25_subaddr sub_addr;			rc = -EINVAL;			if(sk->sk_state != TCP_CLOSE)				break;			rc = -EFAULT;			if (copy_from_user(&sub_addr, argp,					sizeof(sub_addr)))				break;		 	rc = -EINVAL;			if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)				break;			x25->cudmatchlength = sub_addr.cudmatchlength;			rc = 0;			break;		}		case SIOCX25CALLACCPTAPPRV: {			rc = -EINVAL;			if (sk->sk_state != TCP_CLOSE)				break;			x25->accptapprv = X25_ALLOW_ACCPT_APPRV;			rc = 0;			break;		}		case SIOCX25SENDCALLACCPT:  {			rc = -EINVAL;			if (sk->sk_state != TCP_ESTABLISHED)				break;			if (x25->accptapprv)	/* must call accptapprv above */				break;			x25_write_internal(sk, X25_CALL_ACCEPTED);			x25->state = X25_STATE_3;			rc = 0;			break;		} 		default:			rc = -ENOIOCTLCMD;			break;	}	return rc;}static struct net_proto_family x25_family_ops = {	.family =	AF_X25,	.create =	x25_create,	.owner	=	THIS_MODULE,};#ifdef CONFIG_COMPATstatic int compat_x25_subscr_ioctl(unsigned int cmd,		struct compat_x25_subscrip_struct __user *x25_subscr32){	struct compat_x25_subscrip_struct x25_subscr;	struct x25_neigh *nb;	struct net_device *dev;	int rc = -EINVAL;	rc = -EFAULT;	if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))		goto out;	rc = -EINVAL;	dev = x25_dev_get(x25_subscr.device);	if (dev == NULL)		goto out;	nb = x25_get_neigh(dev);	if (nb == NULL)		goto out_dev_put;	dev_put(dev);	if (cmd == SIOCX25GSUBSCRIP) {		x25_subscr.extended = nb->extended;		x25_subscr.global_facil_mask = nb->global_facil_mask;		rc = copy_to_user(x25_subscr32, &x25_subscr,				sizeof(*x25_subscr32)) ? -EFAULT : 0;	} else {		rc = -EINVAL;		if (x25_subscr.extended == 0 || x25_subscr.extended == 1) {			rc = 0;			nb->extended = x25_subscr.extended;			nb->global_facil_mask = x25_subscr.global_facil_mask;		}	}	x25_neigh_put(nb);out:	return rc;out_dev_put:	dev_put(dev);	goto out;}static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,				unsigned long arg){	void __user *argp = compat_ptr(arg);	struct sock *sk = sock->sk;	int rc = -ENOIOCTLCMD;	switch(cmd) {	case TIOCOUTQ:	case TIOCINQ:		rc = x25_ioctl(sock, cmd, (unsigned long)argp);		break;	case SIOCGSTAMP:		rc = -EINVAL;		if (sk)			rc = compat_sock_get_timestamp(sk,					(struct timeval __user*)argp);		break;	case SIOCGIFADDR:	case SIOCSIFADDR:	case SIOCGIFDSTADDR:	case SIOCSIFDSTADDR:	case SIOCGIFBRDADDR:	case SIOCSIFBRDADDR:	case SIOCGIFNETMASK:	case SIOCSIFNETMASK:	case SIOCGIFMETRIC:	case SIOCSIFMETRIC:		rc = -EINVAL;		break;	case SIOCADDRT:	case SIOCDELRT:		rc = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		rc = x25_route_ioctl(cmd, argp);		break;	case SIOCX25GSUBSCRIP:		rc = compat_x25_subscr_ioctl(cmd, argp);		break;	case SIOCX25SSUBSCRIP:		rc = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		rc = compat_x25_subscr_ioctl(cmd, argp);		break;	case SIOCX25GFACILITIES:	case SIOCX25SFACILITIES:	case SIOCX25GDTEFACILITIES:	case SIOCX25SDTEFACILITIES:	case SIOCX25GCALLUSERDATA:	case SIOCX25SCALLUSERDATA:	case SIOCX25GCAUSEDIAG:	case SIOCX25SCUDMATCHLEN:	case SIOCX25CALLACCPTAPPRV:	case SIOCX25SENDCALLACCPT:		rc = x25_ioctl(sock, cmd, (unsigned long)argp);		break;	default:		rc = -ENOIOCTLCMD;		break;	}	return rc;}#endifstatic const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {	.family =	AF_X25,	.owner =	THIS_MODULE,	.release =	x25_release,	.bind =		x25_bind,	.connect =	x25_connect,	.socketpair =	sock_no_socketpair,	.accept =	x25_accept,	.getname =	x25_getname,	.poll =		datagram_poll,	.ioctl =	x25_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl = compat_x25_ioctl,#endif	.listen =	x25_listen,	.shutdown =	sock_no_shutdown,	.setsockopt =	x25_setsockopt,	.getsockopt =	x25_getsockopt,	.sendmsg =	x25_sendmsg,	.recvmsg =	x25_recvmsg,	.mmap =		sock_no_mmap,	.sendpage =	sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(x25_proto, AF_X25);static struct packet_type x25_packet_type = {	.type =	__constant_htons(ETH_P_X25),	.func =	x25_lapb_receive_frame,};static struct notifier_block x25_dev_notifier = {	.notifier_call = x25_device_event,};void x25_kill_by_neigh(struct x25_neigh *nb){	struct sock *s;	struct hlist_node *node;	write_lock_bh(&x25_list_lock);	sk_for_each(s, node, &x25_list)		if (x25_sk(s)->neighbour == nb)			x25_disconnect(s, ENETUNREACH, 0, 0);	write_unlock_bh(&x25_list_lock);}static int __init x25_init(void){	int rc = proto_register(&x25_proto, 0);	if (rc != 0)		goto out;	sock_register(&x25_family_ops);	dev_add_pack(&x25_packet_type);	register_netdevice_notifier(&x25_dev_notifier);	printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");#ifdef CONFIG_SYSCTL	x25_register_sysctl();#endif	x25_proc_init();out:	return rc;}module_init(x25_init);static void __exit x25_exit(void){	x25_proc_exit();	x25_link_free();	x25_route_free();#ifdef CONFIG_SYSCTL	x25_unregister_sysctl();#endif	unregister_netdevice_notifier(&x25_dev_notifier);	dev_remove_pack(&x25_packet_type);	sock_unregister(AF_X25);	proto_unregister(&x25_proto);}module_exit(x25_exit);MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_X25);

⌨️ 快捷键说明

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