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

📄 af_decnet.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * DECnet       An implementation of the DECnet protocol suite for the LINUX *              operating system.  DECnet is implemented using the  BSD Socket *              interface as the means of communication with the user level. * *              DECnet Socket Layer Interface * * Authors:     Eduardo Marcelo Serrat <emserrat@geocities.com> *              Patrick Caulfield <patrick@pandh.demon.co.uk> * * Changes: *        Steve Whitehouse: Copied from Eduardo Serrat and Patrick Caulfield's *                          version of the code. Original copyright preserved *                          below. *        Steve Whitehouse: Some bug fixes, cleaning up some code to make it *                          compatible with my routing layer. *        Steve Whitehouse: Merging changes from Eduardo Serrat and Patrick *                          Caulfield. *        Steve Whitehouse: Further bug fixes, checking module code still works *                          with new routing layer. *        Steve Whitehouse: Additional set/get_sockopt() calls. *        Steve Whitehouse: Fixed TIOCINQ ioctl to be same as Eduardo's new *                          code. *        Steve Whitehouse: recvmsg() changed to try and behave in a POSIX like *                          way. Didn't manage it entirely, but its better. *        Steve Whitehouse: ditto for sendmsg(). *        Steve Whitehouse: A selection of bug fixes to various things. *        Steve Whitehouse: Added TIOCOUTQ ioctl. *        Steve Whitehouse: Fixes to username2sockaddr & sockaddr2username. *        Steve Whitehouse: Fixes to connect() error returns. *       Patrick Caulfield: Fixes to delayed acceptance logic. *         David S. Miller: New socket locking *        Steve Whitehouse: Socket list hashing/locking *         Arnaldo C. Melo: use capable, not suser *        Steve Whitehouse: Removed unused code. Fix to use sk->allocation *                          when required. *//******************************************************************************    (c) 1995-1998 E.M. Serrat		emserrat@geocities.com        This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.HISTORY:Version           Kernel     Date       Author/Comments-------           ------     ----       ---------------Version 0.0.1     2.0.30    01-dic-97	Eduardo Marcelo Serrat					(emserrat@geocities.com)                                        First Development of DECnet Socket La-					yer for Linux. Only supports outgoing					connections.Version 0.0.2	  2.1.105   20-jun-98   Patrick J. Caulfield					(patrick@pandh.demon.co.uk)					Port to new kernel development version.Version 0.0.3     2.1.106   25-jun-98   Eduardo Marcelo Serrat					(emserrat@geocities.com)					_                                        Added support for incoming connections                                        so we can start developing server apps                                        on Linux.					-					Module SupportVersion 0.0.4     2.1.109   21-jul-98   Eduardo Marcelo Serrat                                       (emserrat@geocities.com)                                       _                                        Added support for X11R6.4. Now we can                                         use DECnet transport for X on Linux!!!                                       -Version 0.0.5    2.1.110   01-aug-98   Eduardo Marcelo Serrat                                       (emserrat@geocities.com)                                       Removed bugs on flow control                                       Removed bugs on incoming accessdata                                       order                                       -Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat                                       dn_recvmsg fixes                                        Patrick J. Caulfield                                       dn_bind fixes*******************************************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/netdevice.h>#include <linux/inet.h>#include <linux/route.h>#include <linux/netfilter.h>#include <net/sock.h>#include <asm/segment.h>#include <asm/system.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/poll.h>#include <net/neighbour.h>#include <net/dst.h>#include <net/dn.h>#include <net/dn_nsp.h>#include <net/dn_dev.h>#include <net/dn_route.h>#include <net/dn_fib.h>#include <net/dn_neigh.h>#define MAX(a,b) ((a)>(b)?(a):(b))static void dn_keepalive(struct sock *sk);/* * decnet_address is kept in network order, decnet_ether_address is kept * as a string of bytes. */dn_address decnet_address = 0;unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };static struct proto_ops dn_proto_ops;rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;static struct sock *dn_sklist = NULL;static struct sock *dn_wild_sk = NULL;static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);static int __dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen, int flags);static struct sock **dn_find_list(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	if (scp->addr.sdn_flags & SDF_WILD)		return dn_wild_sk ? NULL : &dn_wild_sk;	return &dn_sklist;}static unsigned short port_alloc(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;static unsigned short port = 0x2000;	if (port == 0)		port++;	scp->addrloc = port++;	return 1;}/* * Since this is only ever called from user * level, we don't need a write_lock() version * of this. */static int dn_hash_sock(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	struct sock **skp;	int rv = -EUSERS;	write_lock_bh(&dn_hash_lock);	if (!scp->addrloc && !port_alloc(sk))		goto out;	rv = -EADDRINUSE;	if ((skp = dn_find_list(sk)) == NULL)		goto out;	sk->next = *skp;	sk->pprev = skp;	*skp = sk;	rv = 0;out:	write_unlock_bh(&dn_hash_lock);	return rv;}static void dn_unhash_sock(struct sock *sk){	struct sock **skp = sk->pprev;	if (skp == NULL)		return;	write_lock(&dn_hash_lock);	while(*skp != sk)		skp = &((*skp)->next);	*skp = sk->next;	write_unlock(&dn_hash_lock);	sk->next = NULL;	sk->pprev = NULL;}static void dn_unhash_sock_bh(struct sock *sk){	struct sock **skp = sk->pprev;	if (skp == NULL)		return;	write_lock_bh(&dn_hash_lock);	while(*skp != sk)		skp = &((*skp)->next);	*skp = sk->next;	write_unlock_bh(&dn_hash_lock);	sk->next = NULL;	sk->pprev = NULL;}int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type){	int len = 2;	*buf++ = type;	switch(type) {		case 0:			*buf++ = sdn->sdn_objnum;			break;		case 1:			*buf++ = 0;			*buf++ = dn_ntohs(sdn->sdn_objnamel);			memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));			len = 3 + dn_ntohs(sdn->sdn_objnamel);			break;		case 2:			memset(buf, 0, 5);			buf += 5;			*buf++ = dn_ntohs(sdn->sdn_objnamel);			memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));			len = 7 + dn_ntohs(sdn->sdn_objnamel);			break;	}	return len;}/* * On reception of usernames, we handle types 1 and 0 for destination * addresses only. Types 2 and 4 are used for source addresses, but the * UIC, GIC are ignored and they are both treated the same way. Type 3 * is never used as I've no idea what its purpose might be or what its * format is. */int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn, unsigned char *fmt){	unsigned char type;	int size = len;	int namel = 12;	sdn->sdn_objnum = 0;	sdn->sdn_objnamel = dn_htons(0);	memset(sdn->sdn_objname, 0, DN_MAXOBJL);	if (len < 2)		return -1;	len -= 2;	*fmt = *data++;	type = *data++;	switch(*fmt) {		case 0:			sdn->sdn_objnum = type;			return 2;		case 1:			namel = 16;			break;		case 2:			len  -= 4;			data += 4;			break;		case 4:			len  -= 8;			data += 8;			break;		default:			return -1;	}	len -= 1;	if (len < 0)		return -1;	sdn->sdn_objnamel = dn_htons(*data++);	len -= dn_ntohs(sdn->sdn_objnamel);	if ((len < 0) || (dn_ntohs(sdn->sdn_objnamel) > namel))		return -1;	memcpy(sdn->sdn_objname, data, dn_ntohs(sdn->sdn_objnamel));	return size - len;}struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr){	struct sock *sk;	read_lock(&dn_hash_lock);	for(sk = dn_sklist; sk != NULL; sk = sk->next) {		struct dn_scp *scp = &sk->protinfo.dn;		if (sk->state != TCP_LISTEN)			continue;		if (scp->addr.sdn_objnum) {			if (scp->addr.sdn_objnum != addr->sdn_objnum)				continue;		} else {			if (addr->sdn_objnum)				continue;			if (scp->addr.sdn_objnamel != addr->sdn_objnamel)				continue;			if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, dn_ntohs(addr->sdn_objnamel)) != 0)				continue;		}		sock_hold(sk);		read_unlock(&dn_hash_lock);		return sk;	}	if (dn_wild_sk && (dn_wild_sk->state == TCP_LISTEN))		sock_hold((sk = dn_wild_sk));	read_unlock(&dn_hash_lock);	return sk;}struct sock *dn_find_by_skb(struct sk_buff *skb){	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	struct sock *sk;	struct dn_scp *scp;	read_lock(&dn_hash_lock);	for(sk = dn_sklist; sk != NULL; sk = sk->next) {		scp = &sk->protinfo.dn;		if (cb->src != dn_saddr2dn(&scp->peer))			continue;		if (cb->dst_port != scp->addrloc)			continue;		if (scp->addrrem && (cb->src_port != scp->addrrem))			continue;		break;	}	if (sk)		sock_hold(sk);	read_unlock(&dn_hash_lock);	return sk;}static void dn_destruct(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	skb_queue_purge(&scp->data_xmit_queue);	skb_queue_purge(&scp->other_xmit_queue);	skb_queue_purge(&scp->other_receive_queue);	dst_release(xchg(&sk->dst_cache, NULL));	MOD_DEC_USE_COUNT;}struct sock *dn_alloc_sock(struct socket *sock, int flags){	struct sock *sk;	struct dn_scp *scp;	if  ((sk = sk_alloc(PF_DECnet, flags, 1)) == NULL) 		goto no_sock;	if (sock) {			sock->ops = &dn_proto_ops;	}	sock_init_data(sock,sk);	scp = &sk->protinfo.dn;	sk->backlog_rcv = dn_nsp_backlog_rcv;	sk->destruct    = dn_destruct;	sk->no_check    = 1;	sk->family      = PF_DECnet;	sk->protocol    = 0;	/* Initialization of DECnet Session Control Port		*/	scp->state	= DN_O;		/* Open			*/	scp->numdat	= 1;		/* Next data seg to tx	*/	scp->numoth	= 1;		/* Next oth data to tx  */	scp->ackxmt_dat = 0;		/* Last data seg ack'ed */	scp->ackxmt_oth = 0;		/* Last oth data ack'ed */	scp->ackrcv_dat = 0;		/* Highest data ack recv*/	scp->ackrcv_oth = 0;		/* Last oth data ack rec*/        scp->flowrem_sw = DN_SEND;	scp->flowloc_sw = DN_SEND;	scp->accept_mode = ACC_IMMED;	scp->addr.sdn_family    = AF_DECnet;	scp->peer.sdn_family    = AF_DECnet;	scp->accessdata.acc_accl = 5;	memcpy(scp->accessdata.acc_acc, "LINUX", 5);	scp->mss = 1460;	scp->snd_window   = NSP_MIN_WINDOW;	scp->nsp_srtt     = NSP_INITIAL_SRTT;	scp->nsp_rttvar   = NSP_INITIAL_RTTVAR;	scp->nsp_rxtshift = 0;	skb_queue_head_init(&scp->data_xmit_queue);	skb_queue_head_init(&scp->other_xmit_queue);	skb_queue_head_init(&scp->other_receive_queue);	scp->persist = 0;	scp->persist_fxn = NULL;	scp->keepalive = 10 * HZ;	scp->keepalive_fxn = dn_keepalive;	init_timer(&scp->delack_timer);	scp->delack_pending = 0;	scp->delack_fxn = dn_nsp_delayed_ack;	dn_start_slow_timer(sk);	MOD_INC_USE_COUNT;	return sk;no_sock:	return NULL;}/* * Keepalive timer. * FIXME: Should respond to SO_KEEPALIVE etc. */static void dn_keepalive(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	/*	 * By checking the other_data transmit queue is empty	 * we are double checking that we are not sending too	 * many of these keepalive frames.	 */	if (skb_queue_len(&scp->other_xmit_queue) == 0)		dn_nsp_send_lnk(sk, DN_NOCHANGE);}/* * Timer for shutdown/destroyed sockets. * When socket is dead & no packets have been sent for a * certain amount of time, they are removed by this * routine. Also takes care of sending out DI & DC * frames at correct times. */int dn_destroy_timer(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	scp->persist = dn_nsp_persist(sk);	switch(scp->state) {		case DN_DI:			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);			if (scp->nsp_rxtshift >= decnet_di_count)				scp->state = DN_CN;			return 0;		case DN_DR:			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);			if (scp->nsp_rxtshift >= decnet_dr_count)				scp->state = DN_DRC;			return 0;		case DN_DN:			if (scp->nsp_rxtshift < decnet_dn_count) {				/* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */				dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);				return 0;			}	}	scp->persist = (HZ * decnet_time_wait);	if (sk->socket)		return 0;	dn_stop_fast_timer(sk); /* unlikely, but possible that this is runninng */	if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) {		dn_unhash_sock(sk);		sock_put(sk);		return 1;	}	return 0;}static void dn_destroy_sock(struct sock *sk){	struct dn_scp *scp = &sk->protinfo.dn;	scp->nsp_rxtshift = 0; /* reset back off */	if (sk->socket) {		if (sk->socket->state != SS_UNCONNECTED)			sk->socket->state = SS_DISCONNECTING;	}	sk->state = TCP_CLOSE;

⌨️ 快捷键说明

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