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

📄 af_inet.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		PF_INET protocol family socket handler. * * Version:	$Id: af_inet.c,v 1.87.2.5 1999/08/08 08:43:10 davem Exp $ * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Florian La Roche, <flla@stud.uni-sb.de> *		Alan Cox, <A.Cox@swansea.ac.uk> * * Changes (see also sock.c) * *		A.N.Kuznetsov	:	Socket death error in accept(). *		John Richardson :	Fix non blocking error in connect() *					so sockets that fail to connect *					don't return -EINPROGRESS. *		Alan Cox	:	Asynchronous I/O support *		Alan Cox	:	Keep correct socket pointer on sock structures *					when accept() ed *		Alan Cox	:	Semantics of SO_LINGER aren't state moved *					to close when you look carefully. With *					this fixed and the accept bug fixed *					some RPC stuff seems happier. *		Niibe Yutaka	:	4.4BSD style write async I/O *		Alan Cox, *		Tony Gale 	:	Fixed reuse semantics. *		Alan Cox	:	bind() shouldn't abort existing but dead *					sockets. Stops FTP netin:.. I hope. *		Alan Cox	:	bind() works correctly for RAW sockets. Note *					that FreeBSD at least was broken in this respect *					so be careful with compatibility tests... *		Alan Cox	:	routing cache support *		Alan Cox	:	memzero the socket structure for compactness. *		Matt Day	:	nonblock connect error handler *		Alan Cox	:	Allow large numbers of pending sockets *					(eg for big web sites), but only if *					specifically application requested. *		Alan Cox	:	New buffering throughout IP. Used dumbly. *		Alan Cox	:	New buffering now used smartly. *		Alan Cox	:	BSD rather than common sense interpretation of *					listen. *		Germano Caronni	:	Assorted small races. *		Alan Cox	:	sendmsg/recvmsg basic support. *		Alan Cox	:	Only sendmsg/recvmsg now supported. *		Alan Cox	:	Locked down bind (see security list). *		Alan Cox	:	Loosened bind a little. *		Mike McLagan	:	ADD/DEL DLCI Ioctls *	Willy Konynenberg	:	Transparent proxying support. *		David S. Miller	:	New socket lookup architecture. *					Some other random speedups. *		Cyrus Durgin	:	Cleaned up file for kmod hacks. *		Andi Kleen	:	Fix inet_stream_connect TCP race. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/poll.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <net/ip.h>#include <net/protocol.h>#include <net/arp.h>#include <net/rarp.h>#include <net/route.h>#include <net/tcp.h>#include <net/udp.h>#include <linux/skbuff.h>#include <net/sock.h>#include <net/raw.h>#include <net/icmp.h>#include <net/ipip.h>#include <net/inet_common.h>#include <linux/ip_fw.h>#ifdef CONFIG_IP_MROUTE#include <linux/mroute.h>#endif#ifdef CONFIG_IP_MASQUERADE#include <net/ip_masq.h>#endif#ifdef CONFIG_BRIDGE#include <net/br.h>#endif#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#ifdef CONFIG_NET_RADIO#include <linux/wireless.h>#endif	/* CONFIG_NET_RADIO */#define min(a,b)	((a)<(b)?(a):(b))struct linux_mib net_statistics;extern int raw_get_info(char *, char **, off_t, int, int);extern int snmp_get_info(char *, char **, off_t, int, int);extern int netstat_get_info(char *, char **, off_t, int, int);extern int afinet_get_info(char *, char **, off_t, int, int);extern int tcp_get_info(char *, char **, off_t, int, int);extern int udp_get_info(char *, char **, off_t, int, int);extern void ip_mc_drop_socket(struct sock *sk);#ifdef CONFIG_DLCIextern int dlci_ioctl(unsigned int, void*);#endif#ifdef CONFIG_DLCI_MODULEint (*dlci_ioctl_hook)(unsigned int, void *) = NULL;#endifint (*rarp_ioctl_hook)(unsigned int,void*) = NULL;/* *	Destroy an AF_INET socket */static __inline__ void kill_sk_queues(struct sock *sk){	struct sk_buff *skb;	/* First the read buffer. */	while((skb = skb_dequeue(&sk->receive_queue)) != NULL)		kfree_skb(skb);	/* Next, the error queue. */	while((skb = skb_dequeue(&sk->error_queue)) != NULL)		kfree_skb(skb);  	/* Now the backlog. */  	while((skb=skb_dequeue(&sk->back_log)) != NULL)		kfree_skb(skb);}static __inline__ void kill_sk_now(struct sock *sk){	/* No longer exists. */	del_from_prot_sklist(sk);	/* Remove from protocol hash chains. */	sk->prot->unhash(sk);	if(sk->opt)		kfree(sk->opt);	dst_release(sk->dst_cache);	sk_free(sk);}static __inline__ void kill_sk_later(struct sock *sk){	/* this should never happen. */	/* actually it can if an ack has just been sent. */	/*	 * It's more normal than that...	 * It can happen because a skb is still in the device queues	 * [PR]	 */	NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",			atomic_read(&sk->rmem_alloc),			atomic_read(&sk->wmem_alloc)));	sk->ack_backlog = 0;	release_sock(sk);	net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);}void destroy_sock(struct sock *sk){	lock_sock(sk);			/* just to be safe. */  	/* Now we can no longer get new packets or once the  	 * timers are killed, send them.  	 */  	net_delete_timer(sk);	if (sk->prot->destroy && !sk->destroy)		sk->prot->destroy(sk);	sk->destroy = 1;	kill_sk_queues(sk);	/* Now if everything is gone we can free the socket	 * structure, otherwise we need to keep it around until	 * everything is gone.	 */	if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0)		kill_sk_now(sk);	else		kill_sk_later(sk);}/* *	The routines beyond this point handle the behaviour of an AF_INET *	socket object. Mostly it punts to the subprotocols of IP to do *	the work. *//* *	Set socket options on an inet socket. */int inet_setsockopt(struct socket *sock, int level, int optname,		    char *optval, int optlen){	struct sock *sk=sock->sk;	if (sk->prot->setsockopt==NULL)		return(-EOPNOTSUPP);	return sk->prot->setsockopt(sk,level,optname,optval,optlen);}/* *	Get a socket option on an AF_INET socket. * *	FIX: POSIX 1003.1g is very ambiguous here. It states that *	asynchronous errors should be reported by getsockopt. We assume *	this means if you specify SO_ERROR (otherwise whats the point of it). */int inet_getsockopt(struct socket *sock, int level, int optname,		    char *optval, int *optlen){	struct sock *sk=sock->sk;	if (sk->prot->getsockopt==NULL)		return(-EOPNOTSUPP);	return sk->prot->getsockopt(sk,level,optname,optval,optlen);}/* *	Automatically bind an unbound socket. */static int inet_autobind(struct sock *sk){	/* We may need to bind the socket. */	if (sk->num == 0) {		if (sk->prot->get_port(sk, 0) != 0)			return(-EAGAIN);		sk->sport = htons(sk->num);		sk->prot->hash(sk);		add_to_prot_sklist(sk);	}	return 0;}/* *	Move a socket into listening state. */int inet_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	unsigned char old_state;	if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)		return(-EINVAL);	if ((unsigned) backlog == 0)	/* BSDism */		backlog = 1;	if ((unsigned) backlog > SOMAXCONN)		backlog = SOMAXCONN;	sk->max_ack_backlog = backlog;	/* Really, if the socket is already in listen state	 * we can only allow the backlog to be adjusted.	 */	old_state = sk->state;	if (old_state != TCP_LISTEN) {		sk->state = TCP_LISTEN;		sk->ack_backlog = 0;		if (sk->num == 0) {			if (sk->prot->get_port(sk, 0) != 0) {				sk->state = old_state;				return -EAGAIN;			}			sk->sport = htons(sk->num);			add_to_prot_sklist(sk);		} else {			if (sk->prev)				((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;		}		dst_release(xchg(&sk->dst_cache, NULL));		sk->prot->hash(sk);		sk->socket->flags |= SO_ACCEPTCON;	}	return 0;}/* *	Create an inet socket. * *	FIXME: Gcc would generate much better code if we set the parameters *	up in in-memory structure order. Gcc68K even more so */static int inet_create(struct socket *sock, int protocol){	struct sock *sk;	struct proto *prot;	/* Compatibility */	if (sock->type == SOCK_PACKET) {		static int warned;		if (net_families[PF_PACKET]==NULL)		{#if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE)			char module_name[30];			sprintf(module_name,"net-pf-%d", PF_PACKET);			request_module(module_name);			if (net_families[PF_PACKET] == NULL)#endif			return -ESOCKTNOSUPPORT;		}		if (!warned++)			printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);		return net_families[PF_PACKET]->create(sock, protocol);	}	sock->state = SS_UNCONNECTED;	sk = sk_alloc(PF_INET, GFP_KERNEL, 1);	if (sk == NULL)		goto do_oom;	switch (sock->type) {	case SOCK_STREAM:		if (protocol && protocol != IPPROTO_TCP)			goto free_and_noproto;		protocol = IPPROTO_TCP;		if (ipv4_config.no_pmtu_disc)			sk->ip_pmtudisc = IP_PMTUDISC_DONT;		else			sk->ip_pmtudisc = IP_PMTUDISC_WANT;		prot = &tcp_prot;		sock->ops = &inet_stream_ops;		break;	case SOCK_SEQPACKET:		goto free_and_badtype;	case SOCK_DGRAM:		if (protocol && protocol != IPPROTO_UDP)			goto free_and_noproto;		protocol = IPPROTO_UDP;		sk->no_check = UDP_NO_CHECK;		sk->ip_pmtudisc = IP_PMTUDISC_DONT;		prot=&udp_prot;		sock->ops = &inet_dgram_ops;		break;	case SOCK_RAW:		if (!capable(CAP_NET_RAW))			goto free_and_badperm;		if (!protocol)			goto free_and_noproto;		prot = &raw_prot;		sk->reuse = 1;		sk->ip_pmtudisc = IP_PMTUDISC_DONT;		sk->num = protocol;		sock->ops = &inet_dgram_ops;		if (protocol == IPPROTO_RAW)			sk->ip_hdrincl = 1;		break;	default:		goto free_and_badtype;	}	sock_init_data(sock,sk);	sk->destruct = NULL;	sk->zapped=0;#ifdef CONFIG_TCP_NAGLE_OFF	sk->nonagle = 1;#endif	sk->family = PF_INET;	sk->protocol = protocol;	sk->prot = prot;	sk->backlog_rcv = prot->backlog_rcv;	sk->timer.data = (unsigned long)sk;	sk->timer.function = &net_timer;	sk->ip_ttl=ip_statistics.IpDefaultTTL;	sk->ip_mc_loop=1;	sk->ip_mc_ttl=1;	sk->ip_mc_index=0;	sk->ip_mc_list=NULL;	if (sk->num) {		/* It assumes that any protocol which allows		 * the user to assign a number at socket		 * creation time automatically		 * shares.		 */		sk->sport = htons(sk->num);		/* Add to protocol hash chains. */		sk->prot->hash(sk);		add_to_prot_sklist(sk);	}	if (sk->prot->init) {		int err = sk->prot->init(sk);		if (err != 0) {			destroy_sock(sk);			return(err);		}	}	return(0);free_and_badtype:	sk_free(sk);	return -ESOCKTNOSUPPORT;free_and_badperm:	sk_free(sk);	return -EPERM;free_and_noproto:	sk_free(sk);	return -EPROTONOSUPPORT;do_oom:	return -ENOBUFS;}/* *	The peer socket should always be NULL (or else). When we call this *	function we are destroying the object and from then on nobody *	should refer to it. */int inet_release(struct socket *sock, struct socket *peersock){	struct sock *sk = sock->sk;	if (sk) {		long timeout;		/* Begin closedown and wake up sleepers. */		if (sock->state != SS_UNCONNECTED)			sock->state = SS_DISCONNECTING;		sk->state_change(sk);		/* Applications forget to leave groups before exiting */		ip_mc_drop_socket(sk);		/* If linger is set, we don't return until the close		 * is complete.  Otherwise we return immediately. The		 * actually closing is done the same either way.		 *		 * If the close is due to the process exiting, we never		 * linger..		 */		timeout = 0;		if (sk->linger && !(current->flags & PF_EXITING)) {			timeout = HZ * sk->lingertime;			if (!timeout)				timeout = MAX_SCHEDULE_TIMEOUT;		}		sock->sk = NULL;		sk->socket = NULL;		sk->prot->close(sk, timeout);	}	return(0);}static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;	struct sock *sk=sock->sk;	unsigned short snum;	int chk_addr_ret;	/* If the socket has its own bind function then use it. (RAW) */	if(sk->prot->bind)		return sk->prot->bind(sk, uaddr, addr_len);	/* Check these errors (active socket, bad address length, double bind). */	if ((sk->state != TCP_CLOSE)			||	    (addr_len < sizeof(struct sockaddr_in))	||	    (sk->num != 0))		return -EINVAL;	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);	if (addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL &&	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) {#ifdef CONFIG_IP_TRANSPARENT_PROXY		/* Superuser may bind to any address to allow transparent proxying. */		if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN))#endif			return -EADDRNOTAVAIL;	/* Source address MUST be ours! */	}	/*      We keep a pair of addresses. rcv_saddr is the one	 *      used by hash lookups, and saddr is used for transmit.	 *	 *      In the BSD API these are the same except where it	 *      would be illegal to use them (multicast/broadcast) in	 *      which case the sending device address is used.	 */	sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;	if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)		sk->saddr = 0;  /* Use device */	snum = ntohs(addr->sin_port);#ifdef CONFIG_IP_MASQUERADE	/* The kernel masquerader needs some ports. */	if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))		return -EADDRINUSE;#endif	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))		return(-EACCES);	/* Make sure we are allowed to bind here. */	if (sk->prot->get_port(sk, snum) != 0)		return -EADDRINUSE;	sk->sport = htons(sk->num);	sk->daddr = 0;	sk->dport = 0;	sk->prot->hash(sk);	add_to_prot_sklist(sk);	dst_release(sk->dst_cache);	sk->dst_cache=NULL;	return(0);}int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,		       int addr_len, int flags){	struct sock *sk=sock->sk;	int err;	if (inet_autobind(sk) != 0)		return(-EAGAIN);	if (sk->prot->connect == NULL)		return(-EOPNOTSUPP);	err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len);	if (err < 0)		return(err);	return(0);}static void inet_wait_for_connect(struct sock *sk){	struct wait_queue wait = { current, NULL };	add_wait_queue(sk->sleep, &wait);	current->state = TASK_INTERRUPTIBLE;	while (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {		if (signal_pending(current))			break;		if (sk->err)

⌨️ 快捷键说明

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