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

📄 sock.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;		/*		 * We double it on the way in to account for		 * "struct sk_buff" etc. overhead.   Applications		 * assume that the SO_RCVBUF setting they make will		 * allow that much actual data to be received on that		 * socket.		 *		 * Applications are unaware that "struct sk_buff" and		 * other overheads allocate from the receive buffer		 * during socket buffer allocation.		 *		 * And after considering the possible alternatives,		 * returning the value we actually used in getsockopt		 * is the most desirable behavior.		 */		if ((val * 2) < SOCK_MIN_RCVBUF)			sk->sk_rcvbuf = SOCK_MIN_RCVBUF;		else			sk->sk_rcvbuf = val * 2;		break;	case SO_RCVBUFFORCE:		if (!capable(CAP_NET_ADMIN)) {			ret = -EPERM;			break;		}		goto set_rcvbuf;	case SO_KEEPALIVE:#ifdef CONFIG_INET		if (sk->sk_protocol == IPPROTO_TCP)			tcp_set_keepalive(sk, valbool);#endif		sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);		break;	case SO_OOBINLINE:		sock_valbool_flag(sk, SOCK_URGINLINE, valbool);		break;	case SO_NO_CHECK:		sk->sk_no_check = valbool;		break;	case SO_PRIORITY:		if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN))			sk->sk_priority = val;		else			ret = -EPERM;		break;	case SO_LINGER:		if (optlen < sizeof(ling)) {			ret = -EINVAL;	/* 1003.1g */			break;		}		if (copy_from_user(&ling,optval,sizeof(ling))) {			ret = -EFAULT;			break;		}		if (!ling.l_onoff)			sock_reset_flag(sk, SOCK_LINGER);		else {#if (BITS_PER_LONG == 32)			if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)				sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;			else#endif				sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;			sock_set_flag(sk, SOCK_LINGER);		}		break;	case SO_BSDCOMPAT:		sock_warn_obsolete_bsdism("setsockopt");		break;	case SO_PASSCRED:		if (valbool)			set_bit(SOCK_PASSCRED, &sock->flags);		else			clear_bit(SOCK_PASSCRED, &sock->flags);		break;	case SO_TIMESTAMP:	case SO_TIMESTAMPNS:		if (valbool)  {			if (optname == SO_TIMESTAMP)				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);			else				sock_set_flag(sk, SOCK_RCVTSTAMPNS);			sock_set_flag(sk, SOCK_RCVTSTAMP);			sock_enable_timestamp(sk);		} else {			sock_reset_flag(sk, SOCK_RCVTSTAMP);			sock_reset_flag(sk, SOCK_RCVTSTAMPNS);		}		break;	case SO_RCVLOWAT:		if (val < 0)			val = INT_MAX;		sk->sk_rcvlowat = val ? : 1;		break;	case SO_RCVTIMEO:		ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen);		break;	case SO_SNDTIMEO:		ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen);		break;	case SO_ATTACH_FILTER:		ret = -EINVAL;		if (optlen == sizeof(struct sock_fprog)) {			struct sock_fprog fprog;			ret = -EFAULT;			if (copy_from_user(&fprog, optval, sizeof(fprog)))				break;			ret = sk_attach_filter(&fprog, sk);		}		break;	case SO_DETACH_FILTER:		ret = sk_detach_filter(sk);		break;	case SO_PASSSEC:		if (valbool)			set_bit(SOCK_PASSSEC, &sock->flags);		else			clear_bit(SOCK_PASSSEC, &sock->flags);		break;		/* We implement the SO_SNDLOWAT etc to		   not be settable (1003.1g 5.3) */	default:		ret = -ENOPROTOOPT;		break;	}	release_sock(sk);	return ret;}int sock_getsockopt(struct socket *sock, int level, int optname,		    char __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	union {		int val;		struct linger ling;		struct timeval tm;	} v;	unsigned int lv = sizeof(int);	int len;	if (get_user(len, optlen))		return -EFAULT;	if (len < 0)		return -EINVAL;	switch(optname) {	case SO_DEBUG:		v.val = sock_flag(sk, SOCK_DBG);		break;	case SO_DONTROUTE:		v.val = sock_flag(sk, SOCK_LOCALROUTE);		break;	case SO_BROADCAST:		v.val = !!sock_flag(sk, SOCK_BROADCAST);		break;	case SO_SNDBUF:		v.val = sk->sk_sndbuf;		break;	case SO_RCVBUF:		v.val = sk->sk_rcvbuf;		break;	case SO_REUSEADDR:		v.val = sk->sk_reuse;		break;	case SO_KEEPALIVE:		v.val = !!sock_flag(sk, SOCK_KEEPOPEN);		break;	case SO_TYPE:		v.val = sk->sk_type;		break;	case SO_ERROR:		v.val = -sock_error(sk);		if (v.val==0)			v.val = xchg(&sk->sk_err_soft, 0);		break;	case SO_OOBINLINE:		v.val = !!sock_flag(sk, SOCK_URGINLINE);		break;	case SO_NO_CHECK:		v.val = sk->sk_no_check;		break;	case SO_PRIORITY:		v.val = sk->sk_priority;		break;	case SO_LINGER:		lv		= sizeof(v.ling);		v.ling.l_onoff	= !!sock_flag(sk, SOCK_LINGER);		v.ling.l_linger	= sk->sk_lingertime / HZ;		break;	case SO_BSDCOMPAT:		sock_warn_obsolete_bsdism("getsockopt");		break;	case SO_TIMESTAMP:		v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&				!sock_flag(sk, SOCK_RCVTSTAMPNS);		break;	case SO_TIMESTAMPNS:		v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);		break;	case SO_RCVTIMEO:		lv=sizeof(struct timeval);		if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {			v.tm.tv_sec = 0;			v.tm.tv_usec = 0;		} else {			v.tm.tv_sec = sk->sk_rcvtimeo / HZ;			v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000000) / HZ;		}		break;	case SO_SNDTIMEO:		lv=sizeof(struct timeval);		if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {			v.tm.tv_sec = 0;			v.tm.tv_usec = 0;		} else {			v.tm.tv_sec = sk->sk_sndtimeo / HZ;			v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000000) / HZ;		}		break;	case SO_RCVLOWAT:		v.val = sk->sk_rcvlowat;		break;	case SO_SNDLOWAT:		v.val=1;		break;	case SO_PASSCRED:		v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;		break;	case SO_PEERCRED:		if (len > sizeof(sk->sk_peercred))			len = sizeof(sk->sk_peercred);		if (copy_to_user(optval, &sk->sk_peercred, len))			return -EFAULT;		goto lenout;	case SO_PEERNAME:	{		char address[128];		if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2))			return -ENOTCONN;		if (lv < len)			return -EINVAL;		if (copy_to_user(optval, address, len))			return -EFAULT;		goto lenout;	}	/* Dubious BSD thing... Probably nobody even uses it, but	 * the UNIX standard wants it for whatever reason... -DaveM	 */	case SO_ACCEPTCONN:		v.val = sk->sk_state == TCP_LISTEN;		break;	case SO_PASSSEC:		v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;		break;	case SO_PEERSEC:		return security_socket_getpeersec_stream(sock, optval, optlen, len);	default:		return -ENOPROTOOPT;	}	if (len > lv)		len = lv;	if (copy_to_user(optval, &v, len))		return -EFAULT;lenout:	if (put_user(len, optlen))		return -EFAULT;	return 0;}/* * Initialize an sk_lock. * * (We also register the sk_lock with the lock validator.) */static inline void sock_lock_init(struct sock *sk){	sock_lock_init_class_and_name(sk,			af_family_slock_key_strings[sk->sk_family],			af_family_slock_keys + sk->sk_family,			af_family_key_strings[sk->sk_family],			af_family_keys + sk->sk_family);}static void sock_copy(struct sock *nsk, const struct sock *osk){#ifdef CONFIG_SECURITY_NETWORK	void *sptr = nsk->sk_security;#endif	memcpy(nsk, osk, osk->sk_prot->obj_size);#ifdef CONFIG_SECURITY_NETWORK	nsk->sk_security = sptr;	security_sk_clone(osk, nsk);#endif}static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,		int family){	struct sock *sk;	struct kmem_cache *slab;	slab = prot->slab;	if (slab != NULL)		sk = kmem_cache_alloc(slab, priority);	else		sk = kmalloc(prot->obj_size, priority);	if (sk != NULL) {		if (security_sk_alloc(sk, family, priority))			goto out_free;		if (!try_module_get(prot->owner))			goto out_free_sec;	}	return sk;out_free_sec:	security_sk_free(sk);out_free:	if (slab != NULL)		kmem_cache_free(slab, sk);	else		kfree(sk);	return NULL;}static void sk_prot_free(struct proto *prot, struct sock *sk){	struct kmem_cache *slab;	struct module *owner;	owner = prot->owner;	slab = prot->slab;	security_sk_free(sk);	if (slab != NULL)		kmem_cache_free(slab, sk);	else		kfree(sk);	module_put(owner);}/** *	sk_alloc - All socket objects are allocated here *	@net: the applicable net namespace *	@family: protocol family *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) *	@prot: struct proto associated with this new sock instance *	@zero_it: if we should zero the newly allocated sock */struct sock *sk_alloc(struct net *net, int family, gfp_t priority,		      struct proto *prot){	struct sock *sk;	sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);	if (sk) {		sk->sk_family = family;		/*		 * See comment in struct sock definition to understand		 * why we need sk_prot_creator -acme		 */		sk->sk_prot = sk->sk_prot_creator = prot;		sock_lock_init(sk);		sk->sk_net = get_net(net);	}	return sk;}void sk_free(struct sock *sk){	struct sk_filter *filter;	if (sk->sk_destruct)		sk->sk_destruct(sk);	filter = rcu_dereference(sk->sk_filter);	if (filter) {		sk_filter_uncharge(sk, filter);		rcu_assign_pointer(sk->sk_filter, NULL);	}	sock_disable_timestamp(sk);	if (atomic_read(&sk->sk_omem_alloc))		printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",		       __FUNCTION__, atomic_read(&sk->sk_omem_alloc));	put_net(sk->sk_net);	sk_prot_free(sk->sk_prot_creator, sk);}struct sock *sk_clone(const struct sock *sk, const gfp_t priority){	struct sock *newsk;	newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family);	if (newsk != NULL) {		struct sk_filter *filter;		sock_copy(newsk, sk);		/* SANITY */		get_net(newsk->sk_net);		sk_node_init(&newsk->sk_node);		sock_lock_init(newsk);		bh_lock_sock(newsk);		newsk->sk_backlog.head	= newsk->sk_backlog.tail = NULL;		atomic_set(&newsk->sk_rmem_alloc, 0);		atomic_set(&newsk->sk_wmem_alloc, 0);		atomic_set(&newsk->sk_omem_alloc, 0);		skb_queue_head_init(&newsk->sk_receive_queue);		skb_queue_head_init(&newsk->sk_write_queue);#ifdef CONFIG_NET_DMA		skb_queue_head_init(&newsk->sk_async_wait_queue);#endif		rwlock_init(&newsk->sk_dst_lock);		rwlock_init(&newsk->sk_callback_lock);		lockdep_set_class_and_name(&newsk->sk_callback_lock,				af_callback_keys + newsk->sk_family,				af_family_clock_key_strings[newsk->sk_family]);		newsk->sk_dst_cache	= NULL;		newsk->sk_wmem_queued	= 0;		newsk->sk_forward_alloc = 0;		newsk->sk_send_head	= NULL;		newsk->sk_userlocks	= sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;		sock_reset_flag(newsk, SOCK_DONE);		skb_queue_head_init(&newsk->sk_error_queue);		filter = newsk->sk_filter;		if (filter != NULL)			sk_filter_charge(newsk, filter);		if (unlikely(xfrm_sk_clone_policy(newsk))) {			/* It is still raw copy of parent, so invalidate			 * destructor and make plain sk_free() */			newsk->sk_destruct = NULL;			sk_free(newsk);			newsk = NULL;			goto out;		}		newsk->sk_err	   = 0;		newsk->sk_priority = 0;		atomic_set(&newsk->sk_refcnt, 2);		/*		 * Increment the counter in the same struct proto as the master		 * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that		 * is the same as sk->sk_prot->socks, as this field was copied		 * with memcpy).		 *		 * This _changes_ the previous behaviour, where		 * tcp_create_openreq_child always was incrementing the		 * equivalent to tcp_prot->socks (inet_sock_nr), so this have		 * to be taken into account in all callers. -acme		 */		sk_refcnt_debug_inc(newsk);		newsk->sk_socket = NULL;		newsk->sk_sleep	 = NULL;		if (newsk->sk_prot->sockets_allocated)			atomic_inc(newsk->sk_prot->sockets_allocated);	}out:	return newsk;}

⌨️ 快捷键说明

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