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

📄 af_decnet.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 = DN_SKB_CB(skb);		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_pull(skb, 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_link(sk, DN_SEND, 0);			}		}		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 inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *queue, int flags){	unsigned char fctype = scp->services_rem & NSP_FC_MASK;	if (skb_queue_len(queue) >= scp->snd_window)		return 1;	if (fctype != NSP_FC_NONE) {		if (flags & MSG_OOB) {			if (scp->flowrem_oth == 0)				return 1;		} else {			if (scp->flowrem_dat == 0)				return 1;		}	}	return 0;}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 = DN_SK(sk);	int mss;	struct sk_buff_head *queue = &scp->data_xmit_queue;	int flags = msg->msg_flags;	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;	unsigned char fctype;	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);	mss = scp->segsize_rem;	fctype = scp->services_rem & NSP_FC_MASK;	if (sk->dst_cache && sk->dst_cache->neighbour) {		struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour;		if (dn->blksize < (mss + 11))			mss = dn->blksize - 11;	}	/*	 * The only difference between SEQPACKET & STREAM sockets under DECnet	 * 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;		}	}	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 > mss)			len = mss;		/*		 * Wait for queue size to go down below the window		 * size.		 */		if (dn_queue_too_long(scp, queue, flags)) {			if (flags & MSG_DONTWAIT) {				err = -EWOULDBLOCK;				goto out;			}			SOCK_SLEEP_PRE(sk)			if (dn_queue_too_long(scp, queue, flags))				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 = DN_SKB_CB(skb);		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;			seq_add(&scp->numoth, 1);			msgflg = 0x30;			ack = (scp->numoth_rcv & 0x0FFF) | 0x8000;			scp->ackxmt_oth = scp->numoth_rcv;			if (fctype != NSP_FC_NONE)				scp->flowrem_oth--;		} else {			cb->segnum = scp->numdat;			seq_add(&scp->numdat, 1);			msgflg = 0x00;			if (sock->type == SOCK_STREAM)				msgflg = 0x60;			if (scp->seg_total == 0)				msgflg |= 0x20;			scp->seg_total += len;					if (((sent + len) == size) && (flags & MSG_EOR)) {				msgflg |= 0x40;				scp->seg_total = 0;				if (fctype == NSP_FC_SCMC)					scp->flowrem_dat--;			}			ack = (scp->numdat_rcv & 0x0FFF) | 0x8000;			scp->ackxmt_dat = scp->numdat_rcv;			if (fctype == NSP_FC_SRC)				scp->flowrem_dat--;		}		*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, sk->allocation, flags & MSG_OOB);		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 = {	notifier_call:	dn_device_event,};extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);static struct packet_type dn_dix_packet_type = {	type:		__constant_htons(ETH_P_DNA_RT),	dev:		NULL,		/* All devices */	func:		dn_route_rcv,	data:		(void*)1,};#define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf){	int i;    	switch (dn_ntohs(dn->sdn_objnamel)) {		case 0:			sprintf(buf, "%d", dn->sdn_objnum);			break;		default:			for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) {				buf[i] = dn->sdn_objname[i];				if (IS_NOT_PRINTABLE(buf[i]))					buf[i] = '.';			}			buf[i] = 0;    	}}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];	char local_object[DN_MAXOBJL+3];	char remote_object[DN_MAXOBJL+3];	int i;	len += sprintf(buffer + len, "Local                                              Remote\n");	read_lock(&dn_hash_lock);	for(i = 0; i < DN_SK_HASH_SIZE; i++) {		for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {			scp = DN_SK(sk);			dn_printable_object(&scp->addr, local_object);			dn_printable_object(&scp->peer, remote_object);			len += sprintf(buffer + len,					"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %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,					local_object,					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,					remote_object,					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 = {	family:		AF_DECnet,	create:		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,	sendpage:	sock_no_sendpage,};#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");MODULE_LICENSE("GPL");static int addr[2] = {0, 0};MODULE_PARM(addr, "2i");MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");#endifstatic char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";static 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(banner);	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 + -