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

📄 af_decnet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static void dn_destroy_sock(struct sock *sk){	struct dn_scp *scp = DN_SK(sk);	scp->nsp_rxtshift = 0; /* reset back off */	if (sk->sk_socket) {		if (sk->sk_socket->state != SS_UNCONNECTED)			sk->sk_socket->state = SS_DISCONNECTING;	}	sk->sk_state = TCP_CLOSE;	switch(scp->state) {		case DN_DN:			dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,					 sk->sk_allocation);			scp->persist_fxn = dn_destroy_timer;			scp->persist = dn_nsp_persist(sk);			break;		case DN_CR:			scp->state = DN_DR;			goto disc_reject;		case DN_RUN:			scp->state = DN_DI;		case DN_DI:		case DN_DR:disc_reject:			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);		case DN_NC:		case DN_NR:		case DN_RJ:		case DN_DIC:		case DN_CN:		case DN_DRC:		case DN_CI:		case DN_CD:			scp->persist_fxn = dn_destroy_timer;			scp->persist = dn_nsp_persist(sk);			break;		default:			printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");		case DN_O:			dn_stop_slow_timer(sk);			dn_unhash_sock_bh(sk);			sock_put(sk);			break;	}}char *dn_addr2asc(__u16 addr, char *buf){	unsigned short node, area;	node = addr & 0x03ff;	area = addr >> 10;	sprintf(buf, "%hd.%hd", area, node);	return buf;}static int dn_create(struct net *net, struct socket *sock, int protocol){	struct sock *sk;	if (net != &init_net)		return -EAFNOSUPPORT;	switch(sock->type) {		case SOCK_SEQPACKET:			if (protocol != DNPROTO_NSP)				return -EPROTONOSUPPORT;			break;		case SOCK_STREAM:			break;		default:			return -ESOCKTNOSUPPORT;	}	if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL)		return -ENOBUFS;	sk->sk_protocol = protocol;	return 0;}static intdn_release(struct socket *sock){	struct sock *sk = sock->sk;	if (sk) {		sock_orphan(sk);		sock_hold(sk);		lock_sock(sk);		dn_destroy_sock(sk);		release_sock(sk);		sock_put(sk);	}	return 0;}static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;	struct net_device *dev, *ldev;	int rv;	if (addr_len != sizeof(struct sockaddr_dn))		return -EINVAL;	if (saddr->sdn_family != AF_DECnet)		return -EINVAL;	if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2))		return -EINVAL;	if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL)		return -EINVAL;	if (saddr->sdn_flags & ~SDF_WILD)		return -EINVAL;	if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum ||	    (saddr->sdn_flags & SDF_WILD)))		return -EACCES;	if (!(saddr->sdn_flags & SDF_WILD)) {		if (dn_ntohs(saddr->sdn_nodeaddrl)) {			read_lock(&dev_base_lock);			ldev = NULL;			for_each_netdev(&init_net, dev) {				if (!dev->dn_ptr)					continue;				if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {					ldev = dev;					break;				}			}			read_unlock(&dev_base_lock);			if (ldev == NULL)				return -EADDRNOTAVAIL;		}	}	rv = -EINVAL;	lock_sock(sk);	if (sock_flag(sk, SOCK_ZAPPED)) {		memcpy(&scp->addr, saddr, addr_len);		sock_reset_flag(sk, SOCK_ZAPPED);		rv = dn_hash_sock(sk);		if (rv)			sock_set_flag(sk, SOCK_ZAPPED);	}	release_sock(sk);	return rv;}static int dn_auto_bind(struct socket *sock){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	int rv;	sock_reset_flag(sk, SOCK_ZAPPED);	scp->addr.sdn_flags  = 0;	scp->addr.sdn_objnum = 0;	/*	 * This stuff is to keep compatibility with Eduardo's	 * patch. I hope I can dispense with it shortly...	 */	if ((scp->accessdata.acc_accl != 0) &&		(scp->accessdata.acc_accl <= 12)) {		scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl);		memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel));		scp->accessdata.acc_accl = 0;		memset(scp->accessdata.acc_acc, 0, 40);	}	/* End of compatibility stuff */	scp->addr.sdn_add.a_len = dn_htons(2);	rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr);	if (rv == 0) {		rv = dn_hash_sock(sk);		if (rv)			sock_set_flag(sk, SOCK_ZAPPED);	}	return rv;}static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation){	struct dn_scp *scp = DN_SK(sk);	DEFINE_WAIT(wait);	int err;	if (scp->state != DN_CR)		return -EINVAL;	scp->state = DN_CC;	scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS);	dn_send_conn_conf(sk, allocation);	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	for(;;) {		release_sock(sk);		if (scp->state == DN_CC)			*timeo = schedule_timeout(*timeo);		lock_sock(sk);		err = 0;		if (scp->state == DN_RUN)			break;		err = sock_error(sk);		if (err)			break;		err = sock_intr_errno(*timeo);		if (signal_pending(current))			break;		err = -EAGAIN;		if (!*timeo)			break;		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);	if (err == 0) {		sk->sk_socket->state = SS_CONNECTED;	} else if (scp->state != DN_CC) {		sk->sk_socket->state = SS_UNCONNECTED;	}	return err;}static int dn_wait_run(struct sock *sk, long *timeo){	struct dn_scp *scp = DN_SK(sk);	DEFINE_WAIT(wait);	int err = 0;	if (scp->state == DN_RUN)		goto out;	if (!*timeo)		return -EALREADY;	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	for(;;) {		release_sock(sk);		if (scp->state == DN_CI || scp->state == DN_CC)			*timeo = schedule_timeout(*timeo);		lock_sock(sk);		err = 0;		if (scp->state == DN_RUN)			break;		err = sock_error(sk);		if (err)			break;		err = sock_intr_errno(*timeo);		if (signal_pending(current))			break;		err = -ETIMEDOUT;		if (!*timeo)			break;		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);out:	if (err == 0) {		sk->sk_socket->state = SS_CONNECTED;	} else if (scp->state != DN_CI && scp->state != DN_CC) {		sk->sk_socket->state = SS_UNCONNECTED;	}	return err;}static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, long *timeo, int flags){	struct socket *sock = sk->sk_socket;	struct dn_scp *scp = DN_SK(sk);	int err = -EISCONN;	struct flowi fl;	if (sock->state == SS_CONNECTED)		goto out;	if (sock->state == SS_CONNECTING) {		err = 0;		if (scp->state == DN_RUN) {			sock->state = SS_CONNECTED;			goto out;		}		err = -ECONNREFUSED;		if (scp->state != DN_CI && scp->state != DN_CC) {			sock->state = SS_UNCONNECTED;			goto out;		}		return dn_wait_run(sk, timeo);	}	err = -EINVAL;	if (scp->state != DN_O)		goto out;	if (addr == NULL || addrlen != sizeof(struct sockaddr_dn))		goto out;	if (addr->sdn_family != AF_DECnet)		goto out;	if (addr->sdn_flags & SDF_WILD)		goto out;	if (sock_flag(sk, SOCK_ZAPPED)) {		err = dn_auto_bind(sk->sk_socket);		if (err)			goto out;	}	memcpy(&scp->peer, addr, sizeof(struct sockaddr_dn));	err = -EHOSTUNREACH;	memset(&fl, 0, sizeof(fl));	fl.oif = sk->sk_bound_dev_if;	fl.fld_dst = dn_saddr2dn(&scp->peer);	fl.fld_src = dn_saddr2dn(&scp->addr);	dn_sk_ports_copy(&fl, scp);	fl.proto = DNPROTO_NSP;	if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, flags) < 0)		goto out;	sk->sk_route_caps = sk->sk_dst_cache->dev->features;	sock->state = SS_CONNECTING;	scp->state = DN_CI;	scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS);	dn_nsp_send_conninit(sk, NSP_CI);	err = -EINPROGRESS;	if (*timeo) {		err = dn_wait_run(sk, timeo);	}out:	return err;}static int dn_connect(struct socket *sock, struct sockaddr *uaddr, int addrlen, int flags){	struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr;	struct sock *sk = sock->sk;	int err;	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);	lock_sock(sk);	err = __dn_connect(sk, addr, addrlen, &timeo, 0);	release_sock(sk);	return err;}static inline int dn_check_state(struct sock *sk, struct sockaddr_dn *addr, int addrlen, long *timeo, int flags){	struct dn_scp *scp = DN_SK(sk);	switch(scp->state) {		case DN_RUN:			return 0;		case DN_CR:			return dn_confirm_accept(sk, timeo, sk->sk_allocation);		case DN_CI:		case DN_CC:			return dn_wait_run(sk, timeo);		case DN_O:			return __dn_connect(sk, addr, addrlen, timeo, flags);	}	return -EINVAL;}static void dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc){	unsigned char *ptr = skb->data;	acc->acc_userl = *ptr++;	memcpy(&acc->acc_user, ptr, acc->acc_userl);	ptr += acc->acc_userl;	acc->acc_passl = *ptr++;	memcpy(&acc->acc_pass, ptr, acc->acc_passl);	ptr += acc->acc_passl;	acc->acc_accl = *ptr++;	memcpy(&acc->acc_acc, ptr, acc->acc_accl);	skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);}static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt){	unsigned char *ptr = skb->data;	u16 len = *ptr++; /* yes, it's 8bit on the wire */	BUG_ON(len > 16); /* we've checked the contents earlier */	opt->opt_optl   = dn_htons(len);	opt->opt_status = 0;	memcpy(opt->opt_data, ptr, len);	skb_pull(skb, len + 1);}static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo){	DEFINE_WAIT(wait);	struct sk_buff *skb = NULL;	int err = 0;	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	for(;;) {		release_sock(sk);		skb = skb_dequeue(&sk->sk_receive_queue);		if (skb == NULL) {			*timeo = schedule_timeout(*timeo);			skb = skb_dequeue(&sk->sk_receive_queue);		}		lock_sock(sk);		if (skb != NULL)			break;		err = -EINVAL;		if (sk->sk_state != TCP_LISTEN)			break;		err = sock_intr_errno(*timeo);		if (signal_pending(current))			break;		err = -EAGAIN;		if (!*timeo)			break;		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);	return skb == NULL ? ERR_PTR(err) : skb;}static int dn_accept(struct socket *sock, struct socket *newsock, int flags){	struct sock *sk = sock->sk, *newsk;	struct sk_buff *skb = NULL;	struct dn_skb_cb *cb;	unsigned char menuver;	int err = 0;	unsigned char type;	long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);	lock_sock(sk);	if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) {		release_sock(sk);		return -EINVAL;	}	skb = skb_dequeue(&sk->sk_receive_queue);	if (skb == NULL) {		skb = dn_wait_for_connect(sk, &timeo);		if (IS_ERR(skb)) {			release_sock(sk);			return PTR_ERR(skb);		}	}	cb = DN_SKB_CB(skb);	sk->sk_ack_backlog--;	newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation);	if (newsk == NULL) {		release_sock(sk);		kfree_skb(skb);		return -ENOBUFS;	}	release_sock(sk);	dst_release(xchg(&newsk->sk_dst_cache, skb->dst));	skb->dst = NULL;	DN_SK(newsk)->state        = DN_CR;	DN_SK(newsk)->addrrem      = cb->src_port;	DN_SK(newsk)->services_rem = cb->services;	DN_SK(newsk)->info_rem     = cb->info;	DN_SK(newsk)->segsize_rem  = cb->segsize;	DN_SK(newsk)->accept_mode  = DN_SK(sk)->accept_mode;	if (DN_SK(newsk)->segsize_rem < 230)		DN_SK(newsk)->segsize_rem = 230;	if ((DN_SK(newsk)->services_rem & NSP_FC_MASK) == NSP_FC_NONE)		DN_SK(newsk)->max_window = decnet_no_fc_max_cwnd;	newsk->sk_state  = TCP_LISTEN;	memcpy(&(DN_SK(newsk)->addr), &(DN_SK(sk)->addr), sizeof(struct sockaddr_dn));	/*	 * If we are listening on a wild socket, we don't want	 * the newly created socket on the wrong hash queue.	 */	DN_SK(newsk)->addr.sdn_flags &= ~SDF_WILD;	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type));	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type));	*(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;	*(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;	menuver = *skb->data;	skb_pull(skb, 1);	if (menuver & DN_MENUVER_ACC)		dn_access_copy(skb, &(DN_SK(newsk)->accessdata));	if (menuver & DN_MENUVER_USR)		dn_user_copy(skb, &(DN_SK(newsk)->conndata_in));	if (menuver & DN_MENUVER_PRX)		DN_SK(newsk)->peer.sdn_flags |= SDF_PROXY;	if (menuver & DN_MENUVER_UIC)		DN_SK(newsk)->peer.sdn_flags |= SDF_UICPROXY;	kfree_skb(skb);	memcpy(&(DN_SK(newsk)->conndata_out), &(DN_SK(sk)->conndata_out),		sizeof(struct optdata_dn));	memcpy(&(DN_SK(newsk)->discdata_out), &(DN_SK(sk)->discdata_out),		sizeof(struct optdata_dn));	lock_sock(newsk);	err = dn_hash_sock(newsk);	if (err == 0) {		sock_reset_flag(newsk, SOCK_ZAPPED);		dn_send_conn_ack(newsk);		/*		 * Here we use sk->sk_allocation since although the conn conf is		 * for the newsk, the context is the old socket.		 */		if (DN_SK(newsk)->accept_mode == ACC_IMMED)			err = dn_confirm_accept(newsk, &timeo,						sk->sk_allocation);	}	release_sock(newsk);	return err;}static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len,int peer){	struct sockaddr_dn *sa = (struct sockaddr_dn *)uaddr;	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	*uaddr_len = sizeof(struct sockaddr_dn);	lock_sock(sk);	if (peer) {		if ((sock->state != SS_CONNECTED &&		     sock->state != SS_CONNECTING) &&		    scp->accept_mode == ACC_IMMED) {			release_sock(sk);			return -ENOTCONN;		}		memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn));	} else {		memcpy(sa, &scp->addr, sizeof(struct sockaddr_dn));	}	release_sock(sk);	return 0;}static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table  *wait){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	int mask = datagram_poll(file, sock, wait);	if (!skb_queue_empty(&scp->other_receive_queue))		mask |= POLLRDBAND;	return mask;}static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	int err = -EOPNOTSUPP;	long amount = 0;

⌨️ 快捷键说明

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