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

📄 udp.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/*	 *	Get and verify the address.	 */	if (msg->msg_name) {		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;		if (msg->msg_namelen < sizeof(*usin))			return(-EINVAL);		if (usin->sin_family != AF_INET) {			static int complained;			if (!complained++)				printk(KERN_WARNING "%s forgot to set AF_INET in udp sendmsg. Fix it!\n", current->comm);			if (usin->sin_family)				return -EINVAL;		}		ufh.daddr = usin->sin_addr.s_addr;		ufh.uh.dest = usin->sin_port;		if (ufh.uh.dest == 0)			return -EINVAL;	} else {		if (sk->state != TCP_ESTABLISHED)			return -ENOTCONN;		ufh.daddr = sk->daddr;		ufh.uh.dest = sk->dport;		/* Open fast path for connected socket.		   Route will not be used, if at least one option is set.		 */		connected = 1;  	}#ifdef CONFIG_IP_TRANSPARENT_PROXY	if (msg->msg_flags&MSG_PROXY) {		/*		 * We map the first 8 bytes of a second sockaddr_in		 * into the last 8 (unused) bytes of a sockaddr_in.		 */		struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name;		from = (struct sockaddr_in *)&from->sin_zero;		if (from->sin_family != AF_INET)			return -EINVAL;		ipc.addr = from->sin_addr.s_addr;		ufh.uh.source = from->sin_port;		if (ipc.addr == 0)			ipc.addr = sk->saddr;		connected = 0;	} else#endif	{		ipc.addr = sk->saddr;		ufh.uh.source = sk->sport;	}	ipc.opt = NULL;	ipc.oif = sk->bound_dev_if;	if (msg->msg_controllen) {		err = ip_cmsg_send(msg, &ipc);		if (err)			return err;		if (ipc.opt)			free = 1;		connected = 0;	}	if (!ipc.opt)		ipc.opt = sk->opt;	ufh.saddr = ipc.addr;	ipc.addr = daddr = ufh.daddr;	if (ipc.opt && ipc.opt->srr) {		if (!daddr)			return -EINVAL;		daddr = ipc.opt->faddr;		connected = 0;	}	tos = RT_TOS(sk->ip_tos);	if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||	    (ipc.opt && ipc.opt->is_strictroute)) {		tos |= RTO_ONLINK;		connected = 0;	}	if (MULTICAST(daddr)) {		if (!ipc.oif)			ipc.oif = sk->ip_mc_index;		if (!ufh.saddr)			ufh.saddr = sk->ip_mc_addr;		connected = 0;	}	if (connected && sk->dst_cache) {		rt = (struct rtable*)sk->dst_cache;		if (rt->u.dst.obsolete) {			sk->dst_cache = NULL;			dst_release(&rt->u.dst);			rt = NULL;		} else			dst_clone(&rt->u.dst);	}	if (rt == NULL) {		err = ip_route_output(&rt, daddr, ufh.saddr,#ifdef CONFIG_IP_TRANSPARENT_PROXY			(msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) |#endif			 tos, ipc.oif);		if (err)			goto out;		err = -EACCES;		if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast)			goto out;		if (connected && sk->dst_cache == NULL)			sk->dst_cache = dst_clone(&rt->u.dst);	}	ufh.saddr = rt->rt_src;	if (!ipc.addr)		ufh.daddr = ipc.addr = rt->rt_dst;	ufh.uh.len = htons(ulen);	ufh.uh.check = 0;	ufh.iov = msg->msg_iov;	ufh.wcheck = 0;	/* RFC1122: OK.  Provides the checksumming facility (MUST) as per */	/* 4.1.3.4. It's configurable by the application via setsockopt() */	/* (MAY) and it defaults to on (MUST). */	err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,			    &ufh, ulen, &ipc, rt, msg->msg_flags);out:	ip_rt_put(rt);	if (free)		kfree(ipc.opt);	if (!err) {		udp_statistics.UdpOutDatagrams++;		return len;	}	return err;}#ifdef _HURD_#define udp_ioctl 0#else/* *	IOCTL requests applicable to the UDP protocol */int udp_ioctl(struct sock *sk, int cmd, unsigned long arg){	switch(cmd)	{		case TIOCOUTQ:		{			unsigned long amount;			amount = sock_wspace(sk);			return put_user(amount, (int *)arg);		}		case TIOCINQ:		{			struct sk_buff *skb;			unsigned long amount;			amount = 0;			/* N.B. Is this interrupt safe??			   -> Yes. Interrupts do not remove skbs. --ANK (980725)			 */			skb = skb_peek(&sk->receive_queue);			if (skb != NULL) {				/*				 * We will only return the amount				 * of this packet since that is all				 * that will be read.				 */				amount = skb->len - sizeof(struct udphdr);			}			return put_user(amount, (int *)arg);		}		default:			return(-ENOIOCTLCMD);	}	return(0);}#endif#ifndef HAVE_CSUM_COPY_USER#undef CONFIG_UDP_DELAY_CSUM#endif/* * 	This should be easy, if there is something there we * 	return it, otherwise we block. */int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,		int noblock, int flags, int *addr_len){  	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;  	struct sk_buff *skb;  	int copied, err;	if (flags & MSG_ERRQUEUE)		return ip_recv_error(sk, msg, len);	/*	 *	From here the generic datagram does a lot of the work. Come	 *	the finished NET3, it will do _ALL_ the work!	 */	skb = skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;  	copied = skb->len - sizeof(struct udphdr);	if (copied > len) {		copied = len;		msg->msg_flags |= MSG_TRUNC;	}#ifndef CONFIG_UDP_DELAY_CSUM	err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					copied);#else	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) {		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)))			goto csum_copy_err;		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else {		unsigned int csum;		err = 0;		csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum);		csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base,					     copied, csum, &err);		if (err)			goto out_free;		if ((unsigned short)csum_fold(csum))			goto csum_copy_err;	}#endif	if (err)		goto out_free;	sk->stamp=skb->stamp;	/* Copy the address. */	if (sin)	{		/*		 *	Check any passed addresses		 */		if (addr_len)			*addr_len=sizeof(*sin);		sin->sin_family = AF_INET;		sin->sin_port = skb->h.uh->source;		sin->sin_addr.s_addr = skb->nh.iph->saddr;#ifdef CONFIG_IP_TRANSPARENT_PROXY		if (flags&MSG_PROXY)		{			/*			 * We map the first 8 bytes of a second sockaddr_in			 * into the last 8 (unused) bytes of a sockaddr_in.			 * This _is_ ugly, but it's the only way to do it			 * easily,  without adding system calls.			 */			struct sockaddr_in *sinto =				(struct sockaddr_in *) sin->sin_zero;			sinto->sin_family = AF_INET;			sinto->sin_port = skb->h.uh->dest;			sinto->sin_addr.s_addr = skb->nh.iph->daddr;		}#endif  	}	if (sk->ip_cmsg_flags)		ip_cmsg_recv(msg, skb);	err = copied;out_free:  	skb_free_datagram(sk, skb);out:  	return err;#ifdef CONFIG_UDP_DELAY_CSUMcsum_copy_err:	udp_statistics.UdpInErrors++;	skb_free_datagram(sk, skb);	/*	 * Error for blocking case is chosen to masquerade   	 * as some normal condition.	 */	return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;#endif}int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len){	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;	struct rtable *rt;	int err;	if (addr_len < sizeof(*usin))	  	return(-EINVAL);	/*	 *	1003.1g - break association.	 */	if (usin->sin_family==AF_UNSPEC)	{		sk->saddr=INADDR_ANY;		sk->rcv_saddr=INADDR_ANY;		sk->daddr=INADDR_ANY;		sk->state = TCP_CLOSE;		if(uh_cache_sk == sk)			uh_cache_sk = NULL;		return 0;	}	if (usin->sin_family && usin->sin_family != AF_INET)	  	return(-EAFNOSUPPORT);	dst_release(xchg(&sk->dst_cache, NULL));	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,			       sk->ip_tos|sk->localroute, sk->bound_dev_if);	if (err)		return err;	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {		ip_rt_put(rt);		return -EACCES;	}  	if(!sk->saddr)	  	sk->saddr = rt->rt_src;		/* Update source address */	if(!sk->rcv_saddr)		sk->rcv_saddr = rt->rt_src;	sk->daddr = rt->rt_dst;	sk->dport = usin->sin_port;	sk->state = TCP_ESTABLISHED;	if(uh_cache_sk == sk)		uh_cache_sk = NULL;	sk->dst_cache = &rt->u.dst;	return(0);}static void udp_close(struct sock *sk, long timeout){	/* See for explanation: raw_close in ipv4/raw.c */	sk->state = TCP_CLOSE;	udp_v4_unhash(sk);	sk->dead = 1;	destroy_sock(sk);}static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb){	/*	 *	Charge it to the socket, dropping if the queue is full.	 */#if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {			udp_statistics.UdpInErrors++;			ip_statistics.IpInDiscards++;			ip_statistics.IpInDelivers--;			kfree_skb(skb);			return -1;		}		skb->ip_summed = CHECKSUM_UNNECESSARY;	}#endif	if (sock_queue_rcv_skb(sk,skb)<0) {		udp_statistics.UdpInErrors++;		ip_statistics.IpInDiscards++;		ip_statistics.IpInDelivers--;		kfree_skb(skb);		return -1;	}	udp_statistics.UdpInDatagrams++;	return 0;}static inline void udp_deliver(struct sock *sk, struct sk_buff *skb){	udp_queue_rcv_skb(sk, skb);}/* *	Multicasts and broadcasts go to each listener. * *	Note: called only from the BH handler context, *	so we don't need to lock the hashes. */static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,				 u32 saddr, u32 daddr){	struct sock *sk;	int dif;	sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];	dif = skb->dev->ifindex;	sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, dif);	if (sk) {		struct sock *sknext = NULL;		do {			struct sk_buff *skb1 = skb;			sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr,						   uh->source, daddr, dif);			if(sknext)				skb1 = skb_clone(skb, GFP_ATOMIC);			if(skb1)				udp_deliver(sk, skb1);			sk = sknext;		} while(sknext);	} else		kfree_skb(skb);	return 0;}#ifdef CONFIG_IP_TRANSPARENT_PROXY/* *	Check whether a received UDP packet might be for one of our *	sockets. */int udp_chkaddr(struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4);	struct sock *sk;	sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev->ifindex);	if (!sk)		return 0;	/* 0 means accept all LOCAL addresses here, not all the world... */	if (sk->rcv_saddr == 0)		return 0;	return 1;}#endif/* *	All we need to do is get the socket, and then do a checksum. */int udp_rcv(struct sk_buff *skb, unsigned short len){  	struct sock *sk;  	struct udphdr *uh;	unsigned short ulen;	struct rtable *rt = (struct rtable*)skb->dst;	u32 saddr = skb->nh.iph->saddr;	u32 daddr = skb->nh.iph->daddr;	/*	 * First time through the loop.. Do all the setup stuff	 * (including finding out the socket we go to etc)	 */	/*	 *	Get the header.	 */  	uh = skb->h.uh;	__skb_pull(skb, skb->h.raw - skb->data);  	ip_statistics.IpInDelivers++;	/*	 *	Validate the packet and the UDP length.	 */	ulen = ntohs(uh->len);	if (ulen > len || ulen < sizeof(*uh)) {		NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));		udp_statistics.UdpInErrors++;		kfree_skb(skb);		return(0);	}	skb_trim(skb, ulen);#ifndef CONFIG_UDP_DELAY_CSUM	if (uh->check &&	    (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,ulen,saddr,daddr,skb->csum)) ||	     ((skb->ip_summed==CHECKSUM_NONE) &&	      (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0))))))		goto csum_error;#else	if (uh->check==0)		skb->ip_summed = CHECKSUM_UNNECESSARY;	else if (skb->ip_summed==CHECKSUM_HW) {		if (udp_check(uh,ulen,saddr,daddr,skb->csum))			goto csum_error;		skb->ip_summed = CHECKSUM_UNNECESSARY;	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);#endif	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))		return udp_v4_mcast_deliver(skb, uh, saddr, daddr);#ifdef CONFIG_IP_TRANSPARENT_PROXY	if (IPCB(skb)->redirport)		sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source,					 daddr, skb->dev, IPCB(skb)->redirport,					 skb->dev->ifindex);	else#endif	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);	if (sk == NULL) {#ifdef CONFIG_UDP_DELAY_CSUM		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&		    (unsigned short)csum_fold(csum_partial((char*)uh, ulen, skb->csum)))			goto csum_error;#endif  		udp_statistics.UdpNoPorts++;		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);		/*		 * Hmm.  We got an UDP broadcast to a port to which we		 * don't wanna listen.  Ignore it.		 */		kfree_skb(skb);		return(0);  	}	udp_deliver(sk, skb);	return 0;csum_error:	/*	 * RFC1122: OK.  Discards the bad packet silently (as far as	 * the network is concerned, anyway) as per 4.1.3.4 (MUST).	 */	NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",			NIPQUAD(saddr),			ntohs(uh->source),			NIPQUAD(daddr),			ntohs(uh->dest),			ulen));	udp_statistics.UdpInErrors++;	kfree_skb(skb);	return(0);}struct proto udp_prot = {	(struct sock *)&udp_prot,	/* sklist_next */	(struct sock *)&udp_prot,	/* sklist_prev */	udp_close,			/* close */	udp_connect,			/* connect */	NULL,				/* accept */	NULL,				/* retransmit */	NULL,				/* write_wakeup */	NULL,				/* read_wakeup */	datagram_poll,			/* poll */	udp_ioctl,			/* ioctl */	NULL,				/* init */	NULL,				/* destroy */	NULL,				/* shutdown */	ip_setsockopt,			/* setsockopt */	ip_getsockopt,			/* getsockopt */	udp_sendmsg,			/* sendmsg */	udp_recvmsg,			/* recvmsg */	NULL,				/* bind */	udp_queue_rcv_skb,		/* backlog_rcv */	udp_v4_hash,			/* hash */	udp_v4_unhash,			/* unhash */	udp_v4_get_port,		/* good_socknum */	128,				/* max_header */	0,				/* retransmits */ 	"UDP",				/* name */	0,				/* inuse */	0				/* highestinuse */};

⌨️ 快捷键说明

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