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

📄 af_x25.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (!x25->neighbour)		goto out;	if (usx25) {		rc = -EINVAL;		if (msg->msg_namelen < sizeof(sx25))			goto out;		memcpy(&sx25, usx25, sizeof(sx25));		rc = -EISCONN;		if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr))			goto out;		rc = -EINVAL;		if (sx25.sx25_family != AF_X25)			goto out;	} else {		/*		 *	FIXME 1003.1g - if the socket is like this because		 *	it has become closed (not started closed) we ought		 *	to SIGPIPE, EPIPE;		 */		rc = -ENOTCONN;		if (sk->sk_state != TCP_ESTABLISHED)			goto out;		sx25.sx25_family = AF_X25;		sx25.sx25_addr   = x25->dest_addr;	}	SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n");	/* Build a packet */	SOCK_DEBUG(sk, "x25_sendmsg: sendto: building packet.\n");	if ((msg->msg_flags & MSG_OOB) && len > 32)		len = 32;	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;	skb = sock_alloc_send_skb(sk, size, noblock, &rc);	if (!skb)		goto out;	X25_SKB_CB(skb)->flags = msg->msg_flags;	skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);	/*	 *	Put the data on the end	 */	SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n");	asmptr = skb->h.raw = skb_put(skb, len);	rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);	if (rc)		goto out_kfree_skb;	/*	 *	If the Q BIT Include socket option is in force, the first	 *	byte of the user data is the logical value of the Q Bit.	 */	if (x25->qbitincl) {		qbit = skb->data[0];		skb_pull(skb, 1);	}	/*	 *	Push down the X.25 header	 */	SOCK_DEBUG(sk, "x25_sendmsg: Building X.25 Header.\n");	if (msg->msg_flags & MSG_OOB) {		if (x25->neighbour->extended) {			asmptr    = skb_push(skb, X25_STD_MIN_LEN);			*asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;			*asmptr++ = (x25->lci >> 0) & 0xFF;			*asmptr++ = X25_INTERRUPT;		} else {			asmptr    = skb_push(skb, X25_STD_MIN_LEN);			*asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;			*asmptr++ = (x25->lci >> 0) & 0xFF;			*asmptr++ = X25_INTERRUPT;		}	} else {		if (x25->neighbour->extended) {			/* Build an Extended X.25 header */			asmptr    = skb_push(skb, X25_EXT_MIN_LEN);			*asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;			*asmptr++ = (x25->lci >> 0) & 0xFF;			*asmptr++ = X25_DATA;			*asmptr++ = X25_DATA;		} else {			/* Build an Standard X.25 header */			asmptr    = skb_push(skb, X25_STD_MIN_LEN);			*asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;			*asmptr++ = (x25->lci >> 0) & 0xFF;			*asmptr++ = X25_DATA;		}		if (qbit)			skb->data[0] |= X25_Q_BIT;	}	SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n");	SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n");	rc = -ENOTCONN;	if (sk->sk_state != TCP_ESTABLISHED)		goto out_kfree_skb;	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_opt *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_opt *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 != 1)				break;			x25->facilities = facilities;			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;		} 		default:			rc = dev_ioctl(cmd, argp);			break;	}	return rc;}struct net_proto_family x25_family_ops = {	.family =	AF_X25,	.create =	x25_create,	.owner	=	THIS_MODULE,};static 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,	.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,};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){	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();	return 0;}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);}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 + -