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

📄 af_decnet.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (sk->shutdown & RCV_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		rv = -EPIPE;		goto out;	}	if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT)) {		rv = -EOPNOTSUPP;		goto out;	}	if (flags & MSG_OOB)		queue = &scp->other_receive_queue;	if (flags & MSG_WAITALL)		target = size;	/*	 * See if there is data ready to read, sleep if there isn't	 */	for(;;) {		if (sk->err)			goto out;		if (skb_queue_len(&scp->other_receive_queue)) {			if (!(flags & MSG_OOB)) {				msg->msg_flags |= MSG_OOB;				if (!scp->other_report) {					scp->other_report = 1;					goto out;				}			}		}				if (scp->state != DN_RUN)			goto out;		if (signal_pending(current)) {			rv = -ERESTARTSYS;			goto out;		}		if (dn_data_ready(sk, queue, flags, target))			break;		if (flags & MSG_DONTWAIT) {			rv = -EWOULDBLOCK;			goto out;		}		set_bit(SOCK_ASYNC_WAITDATA, &sock->flags);		SOCK_SLEEP_PRE(sk)		if (!dn_data_ready(sk, queue, flags, target))			schedule();		SOCK_SLEEP_POST(sk)		clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags);	}	for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {		int chunk = skb->len;		cb = (struct dn_skb_cb *)skb->cb;		if ((chunk + copied) > size)			chunk = size - copied;		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {			rv = -EFAULT;			break;		}		copied += chunk;		if (!(flags & MSG_PEEK))			skb->len -= chunk;		eor = cb->nsp_flags & 0x40;		nskb = skb->next;		if (skb->len == 0) {			skb_unlink(skb);			kfree_skb(skb);			/* 			 * N.B. Don't refer to skb or cb after this point			 * in loop.			 */			if ((scp->flowloc_sw == DN_DONTSEND) && !dn_congested(sk)) {				scp->flowloc_sw = DN_SEND;				dn_nsp_send_lnk(sk, DN_SEND);			}		}		if (eor) { 			if (sk->type == SOCK_SEQPACKET)				break;			if (!(flags & MSG_WAITALL))				break;		}		if (flags & MSG_OOB)			break;		if (copied >= target)			break;	}	rv = copied;	if (eor && (sk->type == SOCK_SEQPACKET))		msg->msg_flags |= MSG_EOR;out:	if (rv == 0)		rv = (flags & MSG_PEEK) ? -sk->err : sock_error(sk);	if ((rv >= 0) && msg->msg_name) {		memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn));		msg->msg_namelen = sizeof(struct sockaddr_dn);	}	release_sock(sk);	return rv;}static int dn_sendmsg(struct socket *sock, struct msghdr *msg, int size, 	   struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct dn_scp *scp = &sk->protinfo.dn;	int mss = scp->mss;	int mtu = 230 - 11; /* maximum value thats always safe */	struct sk_buff_head *queue = &scp->data_xmit_queue;	int flags = msg->msg_flags;	unsigned short numseg = 0;	int err = 0;	int sent = 0;	int addr_len = msg->msg_namelen;	struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name;	struct sk_buff *skb = NULL;	struct dn_skb_cb *cb;	unsigned char msgflg;	unsigned char *ptr;	unsigned short ack;	int len;	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR))		return -EOPNOTSUPP;	if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))		return -EINVAL;	if (sk->zapped && dn_auto_bind(sock))  {		err = -EADDRNOTAVAIL;		goto out;	}	if (scp->state == DN_O) {		if (!addr_len || !addr) {			err = -ENOTCONN;			goto out;		}		if ((err = dn_connect(sock, (struct sockaddr *)addr, addr_len, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0)) < 0)			goto out;	}	lock_sock(sk);	if ((err = dn_wait_run(sk, flags)) < 0)		goto out;	if (sk->shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		err = -EPIPE;		goto out;	}	if ((flags & MSG_TRYHARD) && sk->dst_cache)		dst_negative_advice(&sk->dst_cache);	if (sk->dst_cache && sk->dst_cache->neighbour) {		struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour;		if (dn->blksize > 230)			mtu = dn->blksize - 11;	}	/*	 * The only difference between SEQPACKET & STREAM sockets under DECnet	 * AFAIK is that SEQPACKET sockets set the MSG_EOR flag for the last	 * session control message segment.	 */	if (flags & MSG_OOB) {		mss = 16;		queue = &scp->other_xmit_queue;		if (size > mss) {			err = -EMSGSIZE;			goto out;		}	}	if (mss < mtu)		mtu = mss;	scp->persist_fxn = dn_nsp_xmit_timeout;	while(sent < size) {		err = sock_error(sk);		if (err)			goto out;		if (signal_pending(current)) {			err = -ERESTARTSYS;			goto out;		}		/*		 * Calculate size that we wish to send.		 */		len = size - sent;		if (len > mtu)			len = mtu;		/*		 * Wait for queue size to go down below the window		 * size.		 */		if (skb_queue_len(queue) >= scp->snd_window) {			if (flags & MSG_DONTWAIT) {				err = -EWOULDBLOCK;				goto out;			}			SOCK_SLEEP_PRE(sk)			if (skb_queue_len(queue) >= scp->snd_window)				schedule();			SOCK_SLEEP_POST(sk)			continue;		}		/*		 * Get a suitably sized skb.		 */		skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, &err);		if (err)			break;		if (!skb)			continue;		cb = (struct dn_skb_cb *)skb->cb;		ptr = skb_put(skb, 9);		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {			err = -EFAULT;			goto out;		}		if (flags & MSG_OOB) {			cb->segnum = scp->numoth++;			scp->numoth &= 0x0fff;			msgflg = 0x30;			ack = scp->ackxmt_oth | 0x8000;		} else {			cb->segnum = scp->numdat++;			scp->numdat &= 0x0fff;			msgflg = 0x00;			if (sock->type == SOCK_STREAM)				msgflg = 0x60;			if (scp->seg_size == 0)				msgflg |= 0x20;			scp->seg_size += len;					if (((sent + len) == size) && (flags & MSG_EOR)) {				msgflg |= 0x40;				scp->seg_size = 0;			}			ack = scp->ackxmt_dat | 0x8000;		}		*ptr++ = msgflg;		*(__u16 *)ptr = scp->addrrem;		ptr += 2;		*(__u16 *)ptr = scp->addrloc;		ptr += 2;		*(__u16 *)ptr = dn_htons(ack);		ptr += 2;		*(__u16 *)ptr = dn_htons(cb->segnum);		sent += len;		dn_nsp_queue_xmit(sk, skb, flags & MSG_OOB);		numseg++;		skb = NULL;		scp->persist = dn_nsp_persist(sk);	}out:	if (skb)		kfree_skb(skb);	release_sock(sk);	return sent ? sent : err;}static int dn_device_event(struct notifier_block *this, unsigned long event,			void *ptr){	struct net_device *dev = (struct net_device *)ptr;	switch(event) {		case NETDEV_UP:			dn_dev_up(dev);			break;		case NETDEV_DOWN:			dn_dev_down(dev);			break;		default:			break;	}	return NOTIFY_DONE;}static struct notifier_block dn_dev_notifier = {	dn_device_event,	0};extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);static struct packet_type dn_dix_packet_type = {	__constant_htons(ETH_P_DNA_RT),	NULL,		/* All devices */	dn_route_rcv,	(void*)1,	NULL,};static int dn_get_info(char *buffer, char **start, off_t offset, int length){	struct sock *sk;	struct dn_scp *scp;	int len = 0;	off_t pos = 0;	off_t begin = 0;	char buf1[DN_ASCBUF_LEN];	char buf2[DN_ASCBUF_LEN];	len += sprintf(buffer + len, "Local                             Remote\n");	read_lock(&dn_hash_lock);	for(sk = dn_sklist; sk != NULL; sk = sk->next) {		scp = &sk->protinfo.dn;		len += sprintf(buffer + len,				"%6s/%04X %04d:%04d %04d:%04d %01d %6s/%04X %04d:%04d %04d:%04d %01d %4s %s\n",				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),				scp->addrloc,				scp->numdat,				scp->numoth,				scp->ackxmt_dat,				scp->ackxmt_oth,				scp->flowloc_sw,				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),				scp->addrrem,				scp->numdat_rcv,				scp->numoth_rcv,				scp->ackrcv_dat,				scp->ackrcv_oth,				scp->flowrem_sw,				dn_state2asc(scp->state),				((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > (offset + length))			break;	}	read_unlock(&dn_hash_lock);	*start = buffer + (offset - begin);	len -= (offset - begin);	if (len > length)		len = length;	return len;}static struct net_proto_family	dn_family_ops = {	AF_DECnet,	dn_create};static struct proto_ops dn_proto_ops = {	family:		AF_DECnet,	release:	dn_release,	bind:		dn_bind,	connect:	dn_connect,	socketpair:	sock_no_socketpair,	accept:		dn_accept,	getname:	dn_getname,	poll:		dn_poll,	ioctl:		dn_ioctl,	listen:		dn_listen,	shutdown:	dn_shutdown,	setsockopt:	dn_setsockopt,	getsockopt:	dn_getsockopt,	sendmsg:	dn_sendmsg,	recvmsg:	dn_recvmsg,	mmap:		sock_no_mmap,};#ifdef CONFIG_SYSCTLvoid dn_register_sysctl(void);void dn_unregister_sysctl(void);#endif#ifdef MODULEEXPORT_NO_SYMBOLS;MODULE_DESCRIPTION("The Linux DECnet Network Protocol");MODULE_AUTHOR("Linux DECnet Project Team");static int addr[2] = {0, 0};MODULE_PARM(addr, "2i");MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");#endifstatic int __init decnet_init(void){#ifdef MODULE	if (addr[0] > 63 || addr[0] < 0) {		printk(KERN_ERR "DECnet: Area must be between 0 and 63");		return 1;	}	if (addr[1] > 1023 || addr[1] < 0) {		printk(KERN_ERR "DECnet: Node must be between 0 and 1023");		return 1;	}	decnet_address = dn_htons((addr[0] << 10) | addr[1]);	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));#endif        printk(KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test10s (C) 1995-2000 Linux DECnet Project Team\n");	sock_register(&dn_family_ops);	dev_add_pack(&dn_dix_packet_type);	register_netdevice_notifier(&dn_dev_notifier);	proc_net_create("decnet", 0, dn_get_info);	dn_neigh_init();	dn_dev_init();	dn_route_init();#ifdef CONFIG_DECNET_ROUTER	dn_fib_init();#endif /* CONFIG_DECNET_ROUTER */#ifdef CONFIG_SYSCTL	dn_register_sysctl();#endif /* CONFIG_SYSCTL */	/*	 * Prevent DECnet module unloading until its fixed properly.	 * Requires an audit of the code to check for memory leaks and	 * initialisation problems etc.	 */	MOD_INC_USE_COUNT;	return 0;}#ifndef MODULEstatic int __init decnet_setup(char *str){	unsigned short area = simple_strtoul(str, &str, 0);	unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);	decnet_address = dn_htons(area << 10 | node);	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));	return 1;}__setup("decnet=", decnet_setup);#endifstatic void __exit decnet_exit(void){	sock_unregister(AF_DECnet);	dev_remove_pack(&dn_dix_packet_type);#ifdef CONFIG_SYSCTL	dn_unregister_sysctl();#endif /* CONFIG_SYSCTL */	unregister_netdevice_notifier(&dn_dev_notifier);	dn_route_cleanup();	dn_dev_cleanup();	dn_neigh_cleanup();#ifdef CONFIG_DECNET_ROUTER	dn_fib_cleanup();#endif /* CONFIG_DECNET_ROUTER */	proc_net_remove("decnet");}module_init(decnet_init);module_exit(decnet_exit);

⌨️ 快捷键说明

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