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

📄 af_decnet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (flags & MSG_OOB) {			if (scp->flowrem_oth == 0)				return 1;		} else {			if (scp->flowrem_dat == 0)				return 1;		}	}	return 0;}/* * The DECnet spec requires that the "routing layer" accepts packets which * are at least 230 bytes in size. This excludes any headers which the NSP * layer might add, so we always assume that we'll be using the maximal * length header on data packets. The variation in length is due to the * inclusion (or not) of the two 16 bit acknowledgement fields so it doesn't * make much practical difference. */unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu){	unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;	if (dev) {		struct dn_dev *dn_db = dev->dn_ptr;		mtu -= LL_RESERVED_SPACE(dev);		if (dn_db->use_long)			mtu -= 21;		else			mtu -= 6;		mtu -= DN_MAX_NSP_DATA_HEADER;	} else {		/*		 * 21 = long header, 16 = guess at MAC header length		 */		mtu -= (21 + DN_MAX_NSP_DATA_HEADER + 16);	}	if (mtu > mss)		mss = mtu;	return mss;}static inline unsigned int dn_current_mss(struct sock *sk, int flags){	struct dst_entry *dst = __sk_dst_get(sk);	struct dn_scp *scp = DN_SK(sk);	int mss_now = min_t(int, scp->segsize_loc, scp->segsize_rem);	/* Other data messages are limited to 16 bytes per packet */	if (flags & MSG_OOB)		return 16;	/* This works out the maximum size of segment we can send out */	if (dst) {		u32 mtu = dst_mtu(dst);		mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now);	}	return mss_now;}/* * N.B. We get the timeout wrong here, but then we always did get it * wrong before and this is another step along the road to correcting * it. It ought to get updated each time we pass through the routine, * but in practise it probably doesn't matter too much for now. */static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk,			      unsigned long datalen, int noblock,			      int *errcode){	struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,						   noblock, errcode);	if (skb) {		skb->protocol = __constant_htons(ETH_P_DNA_RT);		skb->pkt_type = PACKET_OUTGOING;	}	return skb;}static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,		      struct msghdr *msg, size_t size){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	size_t mss;	struct sk_buff_head *queue = &scp->data_xmit_queue;	int flags = msg->msg_flags;	int err = 0;	size_t 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;	size_t len;	unsigned char fctype;	long timeo;	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT))		return -EOPNOTSUPP;	if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))		return -EINVAL;	lock_sock(sk);	timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);	/*	 * The only difference between stream sockets and sequenced packet	 * sockets is that the stream sockets always behave as if MSG_EOR	 * has been set.	 */	if (sock->type == SOCK_STREAM) {		if (flags & MSG_EOR) {			err = -EINVAL;			goto out;		}		flags |= MSG_EOR;	}	err = dn_check_state(sk, addr, addr_len, &timeo, flags);	if (err)		goto out_err;	if (sk->sk_shutdown & SEND_SHUTDOWN) {		err = -EPIPE;		if (!(flags & MSG_NOSIGNAL))			send_sig(SIGPIPE, current, 0);		goto out_err;	}	if ((flags & MSG_TRYHARD) && sk->sk_dst_cache)		dst_negative_advice(&sk->sk_dst_cache);	mss = scp->segsize_rem;	fctype = scp->services_rem & NSP_FC_MASK;	mss = dn_current_mss(sk, flags);	if (flags & MSG_OOB) {		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 = sock_intr_errno(timeo);			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.		 * 64 is a bit of a hack really, but its larger than any		 * link-layer headers and has served us well as a good		 * guess as to their real length.		 */		skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER,					 flags & MSG_DONTWAIT, &err);		if (err)			break;		if (!skb)			continue;		cb = DN_SKB_CB(skb);		skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER);		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {			err = -EFAULT;			goto out;		}		if (flags & MSG_OOB) {			cb->nsp_flags = 0x30;			if (fctype != NSP_FC_NONE)				scp->flowrem_oth--;		} else {			cb->nsp_flags = 0x00;			if (scp->seg_total == 0)				cb->nsp_flags |= 0x20;			scp->seg_total += len;			if (((sent + len) == size) && (flags & MSG_EOR)) {				cb->nsp_flags |= 0x40;				scp->seg_total = 0;				if (fctype == NSP_FC_SCMC)					scp->flowrem_dat--;			}			if (fctype == NSP_FC_SRC)				scp->flowrem_dat--;		}		sent += len;		dn_nsp_queue_xmit(sk, skb, sk->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;out_err:	err = sk_stream_error(sk, flags, err);	release_sock(sk);	return err;}static int dn_device_event(struct notifier_block *this, unsigned long event,			void *ptr){	struct net_device *dev = (struct net_device *)ptr;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	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 *, struct net_device *);static struct packet_type dn_dix_packet_type = {	.type =		__constant_htons(ETH_P_DNA_RT),	.dev =		NULL,		/* All devices */	.func =		dn_route_rcv,};#ifdef CONFIG_PROC_FSstruct dn_iter_state {	int bucket;};static struct sock *dn_socket_get_first(struct seq_file *seq){	struct dn_iter_state *state = seq->private;	struct sock *n = NULL;	for(state->bucket = 0;	    state->bucket < DN_SK_HASH_SIZE;	    ++state->bucket) {		n = sk_head(&dn_sk_hash[state->bucket]);		if (n)			break;	}	return n;}static struct sock *dn_socket_get_next(struct seq_file *seq,				       struct sock *n){	struct dn_iter_state *state = seq->private;	n = sk_next(n);try_again:	if (n)		goto out;	if (++state->bucket >= DN_SK_HASH_SIZE)		goto out;	n = sk_head(&dn_sk_hash[state->bucket]);	goto try_again;out:	return n;}static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos){	struct sock *sk = dn_socket_get_first(seq);	if (sk) {		while(*pos && (sk = dn_socket_get_next(seq, sk)))			--*pos;	}	return *pos ? NULL : sk;}static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos){	void *rc;	read_lock_bh(&dn_hash_lock);	rc = socket_get_idx(seq, &pos);	if (!rc) {		read_unlock_bh(&dn_hash_lock);	}	return rc;}static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos){	return *pos ? dn_socket_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos){	void *rc;	if (v == SEQ_START_TOKEN) {		rc = dn_socket_get_idx(seq, 0);		goto out;	}	rc = dn_socket_get_next(seq, v);	if (rc)		goto out;	read_unlock_bh(&dn_hash_lock);out:	++*pos;	return rc;}static void dn_socket_seq_stop(struct seq_file *seq, void *v){	if (v && v != SEQ_START_TOKEN)		read_unlock_bh(&dn_hash_lock);}#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 char *dn_state2asc(unsigned char state){	switch(state) {		case DN_O:			return "OPEN";		case DN_CR:			return "  CR";		case DN_DR:			return "  DR";		case DN_DRC:			return " DRC";		case DN_CC:			return "  CC";		case DN_CI:			return "  CI";		case DN_NR:			return "  NR";		case DN_NC:			return "  NC";		case DN_CD:			return "  CD";		case DN_RJ:			return "  RJ";		case DN_RUN:			return " RUN";		case DN_DI:			return "  DI";		case DN_DIC:			return " DIC";		case DN_DN:			return "  DN";		case DN_CL:			return "  CL";		case DN_CN:			return "  CN";	}	return "????";}static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk){	struct dn_scp *scp = DN_SK(sk);	char buf1[DN_ASCBUF_LEN];	char buf2[DN_ASCBUF_LEN];	char local_object[DN_MAXOBJL+3];	char remote_object[DN_MAXOBJL+3];	dn_printable_object(&scp->addr, local_object);	dn_printable_object(&scp->peer, remote_object);	seq_printf(seq,		   "%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"));}static int dn_socket_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN) {		seq_puts(seq, "Local                                              Remote\n");	} else {		dn_socket_format_entry(seq, v);	}	return 0;}static const struct seq_operations dn_socket_seq_ops = {	.start	= dn_socket_seq_start,	.next	= dn_socket_seq_next,	.stop	= dn_socket_seq_stop,	.show	= dn_socket_seq_show,};static int dn_socket_seq_open(struct inode *inode, struct file *file){	struct seq_file *seq;	int rc = -ENOMEM;	struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);	if (!s)		goto out;	rc = seq_open(file, &dn_socket_seq_ops);	if (rc)		goto out_kfree;	seq		= file->private_data;	seq->private	= s;	memset(s, 0, sizeof(*s));out:	return rc;out_kfree:	kfree(s);	goto out;}static const struct file_operations dn_socket_seq_fops = {	.owner		= THIS_MODULE,	.open		= dn_socket_seq_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release_private,};#endifstatic struct net_proto_family	dn_family_ops = {	.family =	AF_DECnet,	.create =	dn_create,	.owner	=	THIS_MODULE,};static const struct proto_ops dn_proto_ops = {	.family =	AF_DECnet,	.owner =	THIS_MODULE,	.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,};void dn_register_sysctl(void);void dn_unregister_sysctl(void);MODULE_DESCRIPTION("The Linux DECnet Network Protocol");MODULE_AUTHOR("Linux DECnet Project Team");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_DECnet);static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";static int __init decnet_init(void){	int rc;	printk(banner);	rc = proto_register(&dn_proto, 1);	if (rc != 0)		goto out;	dn_neigh_init();	dn_dev_init();	dn_route_init();	dn_fib_init();	sock_register(&dn_family_ops);	dev_add_pack(&dn_dix_packet_type);	register_netdevice_notifier(&dn_dev_notifier);	proc_net_fops_create(&init_net, "decnet", S_IRUGO, &dn_socket_seq_fops);	dn_register_sysctl();out:	return rc;}module_init(decnet_init);/* * Prevent DECnet module unloading until its fixed properly. * Requires an audit of the code to check for memory leaks and * initialisation problems etc. */#if 0static void __exit decnet_exit(void){	sock_unregister(AF_DECnet);	rtnl_unregister_all(PF_DECnet);	dev_remove_pack(&dn_dix_packet_type);	dn_unregister_sysctl();	unregister_netdevice_notifier(&dn_dev_notifier);	dn_route_cleanup();	dn_dev_cleanup();	dn_neigh_cleanup();	dn_fib_cleanup();	proc_net_remove(&init_net, "decnet");	proto_unregister(&dn_proto);}module_exit(decnet_exit);#endif

⌨️ 快捷键说明

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