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

📄 af_decnet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct sk_buff *skb;	int val;	switch(cmd)	{	case SIOCGIFADDR:	case SIOCSIFADDR:		return dn_dev_ioctl(cmd, (void __user *)arg);	case SIOCATMARK:		lock_sock(sk);		val = !skb_queue_empty(&scp->other_receive_queue);		if (scp->state != DN_RUN)			val = -ENOTCONN;		release_sock(sk);		return val;	case TIOCOUTQ:		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);		if (amount < 0)			amount = 0;		err = put_user(amount, (int __user *)arg);		break;	case TIOCINQ:		lock_sock(sk);		if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {			amount = skb->len;		} else {			struct sk_buff *skb = sk->sk_receive_queue.next;			for(;;) {				if (skb ==				    (struct sk_buff *)&sk->sk_receive_queue)					break;				amount += skb->len;				skb = skb->next;			}		}		release_sock(sk);		err = put_user(amount, (int __user *)arg);		break;	default:		err = -ENOIOCTLCMD;		break;	}	return err;}static int dn_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	int err = -EINVAL;	lock_sock(sk);	if (sock_flag(sk, SOCK_ZAPPED))		goto out;	if ((DN_SK(sk)->state != DN_O) || (sk->sk_state == TCP_LISTEN))		goto out;	sk->sk_max_ack_backlog = backlog;	sk->sk_ack_backlog     = 0;	sk->sk_state           = TCP_LISTEN;	err                 = 0;	dn_rehash_sock(sk);out:	release_sock(sk);	return err;}static int dn_shutdown(struct socket *sock, int how){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	int err = -ENOTCONN;	lock_sock(sk);	if (sock->state == SS_UNCONNECTED)		goto out;	err = 0;	if (sock->state == SS_DISCONNECTING)		goto out;	err = -EINVAL;	if (scp->state == DN_O)		goto out;	if (how != SHUTDOWN_MASK)		goto out;	sk->sk_shutdown = how;	dn_destroy_sock(sk);	err = 0;out:	release_sock(sk);	return err;}static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen){	struct sock *sk = sock->sk;	int err;	lock_sock(sk);	err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);	release_sock(sk);	return err;}static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags){	struct	sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	long timeo;	union {		struct optdata_dn opt;		struct accessdata_dn acc;		int mode;		unsigned long win;		int val;		unsigned char services;		unsigned char info;	} u;	int err;	if (optlen && !optval)		return -EINVAL;	if (optlen > sizeof(u))		return -EINVAL;	if (copy_from_user(&u, optval, optlen))		return -EFAULT;	switch(optname) {		case DSO_CONDATA:			if (sock->state == SS_CONNECTED)				return -EISCONN;			if ((scp->state != DN_O) && (scp->state != DN_CR))				return -EINVAL;			if (optlen != sizeof(struct optdata_dn))				return -EINVAL;			if (dn_ntohs(u.opt.opt_optl) > 16)				return -EINVAL;			memcpy(&scp->conndata_out, &u.opt, optlen);			break;		case DSO_DISDATA:			if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)				return -ENOTCONN;			if (optlen != sizeof(struct optdata_dn))				return -EINVAL;			if (dn_ntohs(u.opt.opt_optl) > 16)				return -EINVAL;			memcpy(&scp->discdata_out, &u.opt, optlen);			break;		case DSO_CONACCESS:			if (sock->state == SS_CONNECTED)				return -EISCONN;			if (scp->state != DN_O)				return -EINVAL;			if (optlen != sizeof(struct accessdata_dn))				return -EINVAL;			if ((u.acc.acc_accl > DN_MAXACCL) ||					(u.acc.acc_passl > DN_MAXACCL) ||					(u.acc.acc_userl > DN_MAXACCL))				return -EINVAL;			memcpy(&scp->accessdata, &u.acc, optlen);			break;		case DSO_ACCEPTMODE:			if (sock->state == SS_CONNECTED)				return -EISCONN;			if (scp->state != DN_O)				return -EINVAL;			if (optlen != sizeof(int))				return -EINVAL;			if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))				return -EINVAL;			scp->accept_mode = (unsigned char)u.mode;			break;		case DSO_CONACCEPT:			if (scp->state != DN_CR)				return -EINVAL;			timeo = sock_rcvtimeo(sk, 0);			err = dn_confirm_accept(sk, &timeo, sk->sk_allocation);			return err;		case DSO_CONREJECT:			if (scp->state != DN_CR)				return -EINVAL;			scp->state = DN_DR;			sk->sk_shutdown = SHUTDOWN_MASK;			dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);			break;		default:#ifdef CONFIG_NETFILTER		return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);#endif		case DSO_LINKINFO:		case DSO_STREAM:		case DSO_SEQPACKET:			return -ENOPROTOOPT;		case DSO_MAXWINDOW:			if (optlen != sizeof(unsigned long))				return -EINVAL;			if (u.win > NSP_MAX_WINDOW)				u.win = NSP_MAX_WINDOW;			if (u.win == 0)				return -EINVAL;			scp->max_window = u.win;			if (scp->snd_window > u.win)				scp->snd_window = u.win;			break;		case DSO_NODELAY:			if (optlen != sizeof(int))				return -EINVAL;			if (scp->nonagle == 2)				return -EINVAL;			scp->nonagle = (u.val == 0) ? 0 : 1;			/* if (scp->nonagle == 1) { Push pending frames } */			break;		case DSO_CORK:			if (optlen != sizeof(int))				return -EINVAL;			if (scp->nonagle == 1)				return -EINVAL;			scp->nonagle = (u.val == 0) ? 0 : 2;			/* if (scp->nonagle == 0) { Push pending frames } */			break;		case DSO_SERVICES:			if (optlen != sizeof(unsigned char))				return -EINVAL;			if ((u.services & ~NSP_FC_MASK) != 0x01)				return -EINVAL;			if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)				return -EINVAL;			scp->services_loc = u.services;			break;		case DSO_INFO:			if (optlen != sizeof(unsigned char))				return -EINVAL;			if (u.info & 0xfc)				return -EINVAL;			scp->info_loc = u.info;			break;	}	return 0;}static int dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	int err;	lock_sock(sk);	err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);	release_sock(sk);	return err;}static int __dn_getsockopt(struct socket *sock, int level,int optname, char __user *optval,int __user *optlen, int flags){	struct	sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	struct linkinfo_dn link;	unsigned int r_len;	void *r_data = NULL;	unsigned int val;	if(get_user(r_len , optlen))		return -EFAULT;	switch(optname) {		case DSO_CONDATA:			if (r_len > sizeof(struct optdata_dn))				r_len = sizeof(struct optdata_dn);			r_data = &scp->conndata_in;			break;		case DSO_DISDATA:			if (r_len > sizeof(struct optdata_dn))				r_len = sizeof(struct optdata_dn);			r_data = &scp->discdata_in;			break;		case DSO_CONACCESS:			if (r_len > sizeof(struct accessdata_dn))				r_len = sizeof(struct accessdata_dn);			r_data = &scp->accessdata;			break;		case DSO_ACCEPTMODE:			if (r_len > sizeof(unsigned char))				r_len = sizeof(unsigned char);			r_data = &scp->accept_mode;			break;		case DSO_LINKINFO:			if (r_len > sizeof(struct linkinfo_dn))				r_len = sizeof(struct linkinfo_dn);			switch(sock->state) {				case SS_CONNECTING:					link.idn_linkstate = LL_CONNECTING;					break;				case SS_DISCONNECTING:					link.idn_linkstate = LL_DISCONNECTING;					break;				case SS_CONNECTED:					link.idn_linkstate = LL_RUNNING;					break;				default:					link.idn_linkstate = LL_INACTIVE;			}			link.idn_segsize = scp->segsize_rem;			r_data = &link;			break;		default:#ifdef CONFIG_NETFILTER		{			int val, len;			if(get_user(len, optlen))				return -EFAULT;			val = nf_getsockopt(sk, PF_DECnet, optname,							optval, &len);			if (val >= 0)				val = put_user(len, optlen);			return val;		}#endif		case DSO_STREAM:		case DSO_SEQPACKET:		case DSO_CONACCEPT:		case DSO_CONREJECT:			return -ENOPROTOOPT;		case DSO_MAXWINDOW:			if (r_len > sizeof(unsigned long))				r_len = sizeof(unsigned long);			r_data = &scp->max_window;			break;		case DSO_NODELAY:			if (r_len > sizeof(int))				r_len = sizeof(int);			val = (scp->nonagle == 1);			r_data = &val;			break;		case DSO_CORK:			if (r_len > sizeof(int))				r_len = sizeof(int);			val = (scp->nonagle == 2);			r_data = &val;			break;		case DSO_SERVICES:			if (r_len > sizeof(unsigned char))				r_len = sizeof(unsigned char);			r_data = &scp->services_rem;			break;		case DSO_INFO:			if (r_len > sizeof(unsigned char))				r_len = sizeof(unsigned char);			r_data = &scp->info_rem;			break;	}	if (r_data) {		if (copy_to_user(optval, r_data, r_len))			return -EFAULT;		if (put_user(r_len, optlen))			return -EFAULT;	}	return 0;}static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target){	struct sk_buff *skb = q->next;	int len = 0;	if (flags & MSG_OOB)		return !skb_queue_empty(q) ? 1 : 0;	while(skb != (struct sk_buff *)q) {		struct dn_skb_cb *cb = DN_SKB_CB(skb);		len += skb->len;		if (cb->nsp_flags & 0x40) {			/* SOCK_SEQPACKET reads to EOM */			if (sk->sk_type == SOCK_SEQPACKET)				return 1;			/* so does SOCK_STREAM unless WAITALL is specified */			if (!(flags & MSG_WAITALL))				return 1;		}		/* minimum data length for read exceeded */		if (len >= target)			return 1;		skb = skb->next;	}	return 0;}static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,	struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct dn_scp *scp = DN_SK(sk);	struct sk_buff_head *queue = &sk->sk_receive_queue;	size_t target = size > 1 ? 1 : 0;	size_t copied = 0;	int rv = 0;	struct sk_buff *skb, *nskb;	struct dn_skb_cb *cb = NULL;	unsigned char eor = 0;	long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);	lock_sock(sk);	if (sock_flag(sk, SOCK_ZAPPED)) {		rv = -EADDRNOTAVAIL;		goto out;	}	if (sk->sk_shutdown & RCV_SHUTDOWN) {		rv = 0;		goto out;	}	rv = dn_check_state(sk, NULL, 0, &timeo, flags);	if (rv)		goto out;	if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {		rv = -EOPNOTSUPP;		goto out;	}	if (flags & MSG_OOB)		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->sk_err)			goto out;		if (!skb_queue_empty(&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 = sock_intr_errno(timeo);			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) {		unsigned 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, queue);			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->sk_type == SOCK_SEQPACKET)				break;			if (!(flags & MSG_WAITALL))				break;		}		if (flags & MSG_OOB)			break;		if (copied >= target)			break;	}	rv = copied;	if (eor && (sk->sk_type == SOCK_SEQPACKET))		msg->msg_flags |= MSG_EOR;out:	if (rv == 0)		rv = (flags & MSG_PEEK) ? -sk->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) {

⌨️ 快捷键说明

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