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

📄 af_inet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	struct sock *sk = sock->sk;	if (uaddr->sa_family == AF_UNSPEC)		return sk->sk_prot->disconnect(sk, flags);	if (!inet_sk(sk)->num && inet_autobind(sk))		return -EAGAIN;	return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len);}static long inet_wait_for_connect(struct sock *sk, long timeo){	DEFINE_WAIT(wait);	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	/* Basic assumption: if someone sets sk->sk_err, he _must_	 * change state of the socket from TCP_SYN_*.	 * Connect() does not allow to get error notifications	 * without closing the socket.	 */	while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {		release_sock(sk);		timeo = schedule_timeout(timeo);		lock_sock(sk);		if (signal_pending(current) || !timeo)			break;		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);	return timeo;}/* *	Connect to a remote host. There is regrettably still a little *	TCP 'magic' in here. */int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,			int addr_len, int flags){	struct sock *sk = sock->sk;	int err;	long timeo;	lock_sock(sk);	if (uaddr->sa_family == AF_UNSPEC) {		err = sk->sk_prot->disconnect(sk, flags);		sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;		goto out;	}	switch (sock->state) {	default:		err = -EINVAL;		goto out;	case SS_CONNECTED:		err = -EISCONN;		goto out;	case SS_CONNECTING:		err = -EALREADY;		/* Fall out of switch with err, set for this state */		break;	case SS_UNCONNECTED:		err = -EISCONN;		if (sk->sk_state != TCP_CLOSE)			goto out;		err = sk->sk_prot->connect(sk, uaddr, addr_len);		if (err < 0)			goto out;		sock->state = SS_CONNECTING;		/* Just entered SS_CONNECTING state; the only		 * difference is that return value in non-blocking		 * case is EINPROGRESS, rather than EALREADY.		 */		err = -EINPROGRESS;		break;	}	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {		/* Error code is set above */		if (!timeo || !inet_wait_for_connect(sk, timeo))			goto out;		err = sock_intr_errno(timeo);		if (signal_pending(current))			goto out;	}	/* Connection was closed by RST, timeout, ICMP error	 * or another process disconnected us.	 */	if (sk->sk_state == TCP_CLOSE)		goto sock_error;	/* sk->sk_err may be not zero now, if RECVERR was ordered by user	 * and error was received after socket entered established state.	 * Hence, it is handled normally after connect() return successfully.	 */	sock->state = SS_CONNECTED;	err = 0;out:	release_sock(sk);	return err;sock_error:	err = sock_error(sk) ? : -ECONNABORTED;	sock->state = SS_UNCONNECTED;	if (sk->sk_prot->disconnect(sk, flags))		sock->state = SS_DISCONNECTING;	goto out;}/* *	Accept a pending connection. The TCP layer now gives BSD semantics. */int inet_accept(struct socket *sock, struct socket *newsock, int flags){	struct sock *sk1 = sock->sk;	int err = -EINVAL;	struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err);	if (!sk2)		goto do_err;	lock_sock(sk2);	BUG_TRAP((1 << sk2->sk_state) &		 (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE));	sock_graft(sk2, newsock);	newsock->state = SS_CONNECTED;	err = 0;	release_sock(sk2);do_err:	return err;}/* *	This does both peername and sockname. */int inet_getname(struct socket *sock, struct sockaddr *uaddr,			int *uaddr_len, int peer){	struct sock *sk		= sock->sk;	struct inet_sock *inet	= inet_sk(sk);	struct sockaddr_in *sin	= (struct sockaddr_in *)uaddr;	sin->sin_family = AF_INET;	if (peer) {		if (!inet->dport ||		    (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&		     peer == 1))			return -ENOTCONN;		sin->sin_port = inet->dport;		sin->sin_addr.s_addr = inet->daddr;	} else {		__be32 addr = inet->rcv_saddr;		if (!addr)			addr = inet->saddr;		sin->sin_port = inet->sport;		sin->sin_addr.s_addr = addr;	}	memset(sin->sin_zero, 0, sizeof(sin->sin_zero));	*uaddr_len = sizeof(*sin);	return 0;}int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,		 size_t size){	struct sock *sk = sock->sk;	/* We may need to bind the socket. */	if (!inet_sk(sk)->num && inet_autobind(sk))		return -EAGAIN;	return sk->sk_prot->sendmsg(iocb, sk, msg, size);}static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags){	struct sock *sk = sock->sk;	/* We may need to bind the socket. */	if (!inet_sk(sk)->num && inet_autobind(sk))		return -EAGAIN;	if (sk->sk_prot->sendpage)		return sk->sk_prot->sendpage(sk, page, offset, size, flags);	return sock_no_sendpage(sock, page, offset, size, flags);}int inet_shutdown(struct socket *sock, int how){	struct sock *sk = sock->sk;	int err = 0;	/* This should really check to make sure	 * the socket is a TCP socket. (WHY AC...)	 */	how++; /* maps 0->1 has the advantage of making bit 1 rcvs and		       1->2 bit 2 snds.		       2->3 */	if ((how & ~SHUTDOWN_MASK) || !how)	/* MAXINT->0 */		return -EINVAL;	lock_sock(sk);	if (sock->state == SS_CONNECTING) {		if ((1 << sk->sk_state) &		    (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE))			sock->state = SS_DISCONNECTING;		else			sock->state = SS_CONNECTED;	}	switch (sk->sk_state) {	case TCP_CLOSE:		err = -ENOTCONN;		/* Hack to wake up other listeners, who can poll for		   POLLHUP, even on eg. unconnected UDP sockets -- RR */	default:		sk->sk_shutdown |= how;		if (sk->sk_prot->shutdown)			sk->sk_prot->shutdown(sk, how);		break;	/* Remaining two branches are temporary solution for missing	 * close() in multithreaded environment. It is _not_ a good idea,	 * but we have no choice until close() is repaired at VFS level.	 */	case TCP_LISTEN:		if (!(how & RCV_SHUTDOWN))			break;		/* Fall through */	case TCP_SYN_SENT:		err = sk->sk_prot->disconnect(sk, O_NONBLOCK);		sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;		break;	}	/* Wake up anyone sleeping in poll. */	sk->sk_state_change(sk);	release_sock(sk);	return err;}/* *	ioctl() calls you can issue on an INET socket. Most of these are *	device configuration and stuff and very rarely used. Some ioctls *	pass on to the socket itself. * *	NOTE: I like the idea of a module for the config stuff. ie ifconfig *	loads the devconfigure module does its configuring and unloads it. *	There's a good 20K of config code hanging around the kernel. */int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	int err = 0;	switch (cmd) {		case SIOCGSTAMP:			err = sock_get_timestamp(sk, (struct timeval __user *)arg);			break;		case SIOCGSTAMPNS:			err = sock_get_timestampns(sk, (struct timespec __user *)arg);			break;		case SIOCADDRT:		case SIOCDELRT:		case SIOCRTMSG:			err = ip_rt_ioctl(cmd, (void __user *)arg);			break;		case SIOCDARP:		case SIOCGARP:		case SIOCSARP:			err = arp_ioctl(cmd, (void __user *)arg);			break;		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFBRDADDR:		case SIOCSIFBRDADDR:		case SIOCGIFNETMASK:		case SIOCSIFNETMASK:		case SIOCGIFDSTADDR:		case SIOCSIFDSTADDR:		case SIOCSIFPFLAGS:		case SIOCGIFPFLAGS:		case SIOCSIFFLAGS:			err = devinet_ioctl(cmd, (void __user *)arg);			break;		default:			if (sk->sk_prot->ioctl)				err = sk->sk_prot->ioctl(sk, cmd, arg);			else				err = -ENOIOCTLCMD;			break;	}	return err;}const struct proto_ops inet_stream_ops = {	.family		   = PF_INET,	.owner		   = THIS_MODULE,	.release	   = inet_release,	.bind		   = inet_bind,	.connect	   = inet_stream_connect,	.socketpair	   = sock_no_socketpair,	.accept		   = inet_accept,	.getname	   = inet_getname,	.poll		   = tcp_poll,	.ioctl		   = inet_ioctl,	.listen		   = inet_listen,	.shutdown	   = inet_shutdown,	.setsockopt	   = sock_common_setsockopt,	.getsockopt	   = sock_common_getsockopt,	.sendmsg	   = tcp_sendmsg,	.recvmsg	   = sock_common_recvmsg,	.mmap		   = sock_no_mmap,	.sendpage	   = tcp_sendpage,#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_sock_common_setsockopt,	.compat_getsockopt = compat_sock_common_getsockopt,#endif};const struct proto_ops inet_dgram_ops = {	.family		   = PF_INET,	.owner		   = THIS_MODULE,	.release	   = inet_release,	.bind		   = inet_bind,	.connect	   = inet_dgram_connect,	.socketpair	   = sock_no_socketpair,	.accept		   = sock_no_accept,	.getname	   = inet_getname,	.poll		   = udp_poll,	.ioctl		   = inet_ioctl,	.listen		   = sock_no_listen,	.shutdown	   = inet_shutdown,	.setsockopt	   = sock_common_setsockopt,	.getsockopt	   = sock_common_getsockopt,	.sendmsg	   = inet_sendmsg,	.recvmsg	   = sock_common_recvmsg,	.mmap		   = sock_no_mmap,	.sendpage	   = inet_sendpage,#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_sock_common_setsockopt,	.compat_getsockopt = compat_sock_common_getsockopt,#endif};/* * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without * udp_poll */static const struct proto_ops inet_sockraw_ops = {	.family		   = PF_INET,	.owner		   = THIS_MODULE,	.release	   = inet_release,	.bind		   = inet_bind,	.connect	   = inet_dgram_connect,	.socketpair	   = sock_no_socketpair,	.accept		   = sock_no_accept,	.getname	   = inet_getname,	.poll		   = datagram_poll,	.ioctl		   = inet_ioctl,	.listen		   = sock_no_listen,	.shutdown	   = inet_shutdown,	.setsockopt	   = sock_common_setsockopt,	.getsockopt	   = sock_common_getsockopt,	.sendmsg	   = inet_sendmsg,	.recvmsg	   = sock_common_recvmsg,	.mmap		   = sock_no_mmap,	.sendpage	   = inet_sendpage,#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_sock_common_setsockopt,	.compat_getsockopt = compat_sock_common_getsockopt,#endif};static struct net_proto_family inet_family_ops = {	.family = PF_INET,	.create = inet_create,	.owner	= THIS_MODULE,};/* Upon startup we insert all the elements in inetsw_array[] into * the linked list inetsw. */static struct inet_protosw inetsw_array[] ={	{		.type =       SOCK_STREAM,		.protocol =   IPPROTO_TCP,		.prot =       &tcp_prot,		.ops =        &inet_stream_ops,		.capability = -1,		.no_check =   0,		.flags =      INET_PROTOSW_PERMANENT |			      INET_PROTOSW_ICSK,	},	{		.type =       SOCK_DGRAM,		.protocol =   IPPROTO_UDP,		.prot =       &udp_prot,		.ops =        &inet_dgram_ops,		.capability = -1,		.no_check =   UDP_CSUM_DEFAULT,		.flags =      INET_PROTOSW_PERMANENT,       },       {	       .type =       SOCK_RAW,	       .protocol =   IPPROTO_IP,	/* wild card */	       .prot =       &raw_prot,	       .ops =        &inet_sockraw_ops,	       .capability = CAP_NET_RAW,	       .no_check =   UDP_CSUM_DEFAULT,	       .flags =      INET_PROTOSW_REUSE,       }};#define INETSW_ARRAY_LEN ARRAY_SIZE(inetsw_array)void inet_register_protosw(struct inet_protosw *p){	struct list_head *lh;	struct inet_protosw *answer;	int protocol = p->protocol;	struct list_head *last_perm;	spin_lock_bh(&inetsw_lock);	if (p->type >= SOCK_MAX)		goto out_illegal;	/* If we are trying to override a permanent protocol, bail. */	answer = NULL;	last_perm = &inetsw[p->type];	list_for_each(lh, &inetsw[p->type]) {		answer = list_entry(lh, struct inet_protosw, list);		/* Check only the non-wild match. */		if (INET_PROTOSW_PERMANENT & answer->flags) {			if (protocol == answer->protocol)				break;			last_perm = lh;		}		answer = NULL;	}	if (answer)		goto out_permanent;	/* Add the new entry after the last permanent entry if any, so that	 * the new entry does not override a permanent entry when matched with	 * a wild-card protocol. But it is allowed to override any existing	 * non-permanent entry.  This means that when we remove this entry, the	 * system automatically returns to the old behavior.	 */	list_add_rcu(&p->list, last_perm);out:	spin_unlock_bh(&inetsw_lock);	synchronize_net();	return;out_permanent:	printk(KERN_ERR "Attempt to override permanent protocol %d.\n",	       protocol);	goto out;out_illegal:	printk(KERN_ERR	       "Ignoring attempt to register invalid socket type %d.\n",	       p->type);	goto out;}void inet_unregister_protosw(struct inet_protosw *p){	if (INET_PROTOSW_PERMANENT & p->flags) {		printk(KERN_ERR		       "Attempt to unregister permanent protocol %d.\n",		       p->protocol);	} else {		spin_lock_bh(&inetsw_lock);		list_del_rcu(&p->list);		spin_unlock_bh(&inetsw_lock);		synchronize_net();

⌨️ 快捷键说明

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