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

📄 af_decnet.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	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_fast_timer(sk);			dn_stop_slow_timer(sk);			dn_unhash_sock_bh(sk);			sock_put(sk);			break;	}}char *dn_addr2asc(dn_address 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 socket *sock, int protocol){	struct sock *sk;	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(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;	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 1	if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum ||	    (saddr->sdn_flags & SDF_WILD)))		return -EACCES;#else	/*	 * Maybe put the default actions in the default security ops for	 * dn_prot_sock ? Would be nice if the capable call would go there	 * too.	 */	if (security_dn_prot_sock(saddr) &&	    !capable(CAP_NET_BIND_SERVICE) || 	    saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))		return -EACCES;#endif	if (!(saddr->sdn_flags & SDF_WILD)) {		if (dn_ntohs(saddr->sdn_nodeaddrl)) {			read_lock(&dev_base_lock);			for(dev = dev_base; dev; dev = dev->next) {				if (!dev->dn_ptr)					continue;				if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))					break;			}			read_unlock(&dev_base_lock);			if (dev == NULL)				return -EADDRNOTAVAIL;		}	}	rv = -EINVAL;	lock_sock(sk);	if (sk->sk_zapped) {		memcpy(&scp->addr, saddr, addr_len);		sk->sk_zapped = 0;		rv = dn_hash_sock(sk);		if (rv) {			sk->sk_zapped = 1;		}	}	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;	sk->sk_zapped = 0;	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((dn_address *)scp->addr.sdn_add.a_addr);	if (rv == 0) {		rv = dn_hash_sock(sk);		if (rv) {			sk->sk_zapped = 1;		}	}	return rv;}static int dn_confirm_accept(struct sock *sk, long *timeo, int 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_path_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 (sk->sk_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_path_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;                opt->opt_optl   = *ptr++;        opt->opt_status = 0;        memcpy(opt->opt_data, ptr, opt->opt_optl);        skb_pull(skb, opt->opt_optl + 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(sk);		}	}	cb = DN_SKB_CB(skb);	sk->sk_ack_backlog--;	newsk = dn_alloc_sock(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));	*(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;	*(dn_address *)(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) {		newsk->sk_zapped = 0;		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)			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_len(&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;

⌨️ 快捷键说明

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