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

📄 udp.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
		/*		 * There are pending frames.	 	 * The socket lock must be held while it's corked.		 */		lock_sock(sk);		if (likely(up->pending)) {			if (unlikely(up->pending != AF_INET)) {				release_sock(sk);				return -EINVAL;			} 			goto do_append_data;		}		release_sock(sk);	}	ulen += sizeof(struct udphdr);	/*	 *	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) {			if (usin->sin_family != AF_UNSPEC)				return -EINVAL;		}		daddr = usin->sin_addr.s_addr;		dport = usin->sin_port;		if (dport == 0)			return -EINVAL;	} else {		if (sk->sk_state != TCP_ESTABLISHED)			return -EDESTADDRREQ;		daddr = inet->daddr;		dport = inet->dport;		/* Open fast path for connected socket.		   Route will not be used, if at least one option is set.		 */		connected = 1;  	}	ipc.addr = inet->saddr;	ipc.oif = sk->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 = inet->opt;	saddr = ipc.addr;	ipc.addr = faddr = daddr;	if (ipc.opt && ipc.opt->srr) {		if (!daddr)			return -EINVAL;		faddr = ipc.opt->faddr;		connected = 0;	}	tos = RT_TOS(inet->tos);	if (sk->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 = inet->mc_index;		if (!saddr)			saddr = inet->mc_addr;		connected = 0;	}	if (connected)		rt = (struct rtable*)sk_dst_check(sk, 0);	if (rt == NULL) {		struct flowi fl = { .oif = ipc.oif,				    .nl_u = { .ip4_u =					      { .daddr = faddr,						.saddr = saddr,						.tos = tos } },				    .proto = IPPROTO_UDP,				    .uli_u = { .ports =					       { .sport = inet->sport,						 .dport = dport } } };		err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));		if (err)			goto out;		err = -EACCES;		if ((rt->rt_flags & RTCF_BROADCAST) &&		    !sock_flag(sk, SOCK_BROADCAST))			goto out;		if (connected)			sk_dst_set(sk, dst_clone(&rt->u.dst));	}	if (msg->msg_flags&MSG_CONFIRM)		goto do_confirm;back_from_confirm:	saddr = rt->rt_src;	if (!ipc.addr)		daddr = ipc.addr = rt->rt_dst;	lock_sock(sk);	if (unlikely(up->pending)) {		/* The socket is already corked while preparing it. */		/* ... which is an evident application bug. --ANK */		release_sock(sk);		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 2\n"));		err = -EINVAL;		goto out;	}	/*	 *	Now cork the socket to pend data.	 */	inet->cork.fl.fl4_dst = daddr;	inet->cork.fl.fl_ip_dport = dport;	inet->cork.fl.fl4_src = saddr;	inet->cork.fl.fl_ip_sport = inet->sport;	up->pending = AF_INET;do_append_data:	up->len += ulen;	err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, 			sizeof(struct udphdr), &ipc, rt, 			corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);	if (err)		udp_flush_pending_frames(sk);	else if (!corkreq)		err = udp_push_pending_frames(sk, up);	release_sock(sk);out:	ip_rt_put(rt);	if (free)		kfree(ipc.opt);	if (!err) {		UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);		return len;	}	return err;do_confirm:	dst_confirm(&rt->u.dst);	if (!(msg->msg_flags&MSG_PROBE) || len)		goto back_from_confirm;	err = 0;	goto out;}int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags){	struct udp_opt *up = udp_sk(sk);	int ret;	if (!up->pending) {		struct msghdr msg = {	.msg_flags = flags|MSG_MORE };		/* Call udp_sendmsg to specify destination address which		 * sendpage interface can't pass.		 * This will succeed only when the socket is connected.		 */		ret = udp_sendmsg(NULL, sk, &msg, 0);		if (ret < 0)			return ret;	}	lock_sock(sk);	if (unlikely(!up->pending)) {		release_sock(sk);		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 3\n"));		return -EINVAL;	}	ret = ip_append_page(sk, page, offset, size, flags);	if (ret == -EOPNOTSUPP) {		release_sock(sk);		return sock_no_sendpage(sk->sk_socket, page, offset,					size, flags);	}	if (ret < 0) {		udp_flush_pending_frames(sk);		goto out;	}	up->len += size;	if (!(up->corkflag || (flags&MSG_MORE)))		ret = udp_push_pending_frames(sk, up);	if (!ret)		ret = size;out:	release_sock(sk);	return ret;}/* *	IOCTL requests applicable to the UDP protocol */ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg){	switch(cmd) 	{		case SIOCOUTQ:		{			int amount = atomic_read(&sk->sk_wmem_alloc);			return put_user(amount, (int __user *)arg);		}		case SIOCINQ:		{			struct sk_buff *skb;			unsigned long amount;			amount = 0;			spin_lock_irq(&sk->sk_receive_queue.lock);			skb = skb_peek(&sk->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);			}			spin_unlock_irq(&sk->sk_receive_queue.lock);			return put_user(amount, (int __user *)arg);		}		default:			return -ENOIOCTLCMD;	}	return(0);}static __inline__ int __udp_checksum_complete(struct sk_buff *skb){	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));}static __inline__ int udp_checksum_complete(struct sk_buff *skb){	return skb->ip_summed != CHECKSUM_UNNECESSARY &&		__udp_checksum_complete(skb);}/* * 	This should be easy, if there is something there we * 	return it, otherwise we block. */int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,		size_t len, int noblock, int flags, int *addr_len){	struct inet_opt *inet = inet_sk(sk);  	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;  	struct sk_buff *skb;  	int copied, err;	/*	 *	Check any passed addresses	 */	if (addr_len)		*addr_len=sizeof(*sin);	if (flags & MSG_ERRQUEUE)		return ip_recv_error(sk, msg, len);try_again:	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;	}	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else if (msg->msg_flags&MSG_TRUNC) {		if (__udp_checksum_complete(skb))			goto csum_copy_err;		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else {		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);		if (err == -EINVAL)			goto csum_copy_err;	}	if (err)		goto out_free;	sock_recv_timestamp(msg, sk, skb);	/* Copy the address. */	if (sin)	{		sin->sin_family = AF_INET;		sin->sin_port = skb->h.uh->source;		sin->sin_addr.s_addr = skb->nh.iph->saddr;		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));  	}	if (inet->cmsg_flags)		ip_cmsg_recv(msg, skb);	err = copied;	if (flags & MSG_TRUNC)		err = skb->len - sizeof(struct udphdr);  out_free:  	skb_free_datagram(sk, skb);out:  	return err;csum_copy_err:	UDP_INC_STATS_BH(UDP_MIB_INERRORS);	/* Clear queue. */	if (flags&MSG_PEEK) {		int clear = 0;		spin_lock_irq(&sk->sk_receive_queue.lock);		if (skb == skb_peek(&sk->sk_receive_queue)) {			__skb_unlink(skb, &sk->sk_receive_queue);			clear = 1;		}		spin_unlock_irq(&sk->sk_receive_queue.lock);		if (clear)			kfree_skb(skb);	}	skb_free_datagram(sk, skb);	if (noblock)		return -EAGAIN;		goto try_again;}int udp_disconnect(struct sock *sk, int flags){	struct inet_opt *inet = inet_sk(sk);	/*	 *	1003.1g - break association.	 */	 	sk->sk_state = TCP_CLOSE;	inet->daddr = 0;	inet->dport = 0;	sk->sk_bound_dev_if = 0;	if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))		inet_reset_saddr(sk);	if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) {		sk->sk_prot->unhash(sk);		inet->sport = 0;	}	sk_dst_reset(sk);	return 0;}static void udp_close(struct sock *sk, long timeout){	sk_common_release(sk);}/* return: * 	1  if the the UDP system should process it *	0  if we should drop this packet * 	-1 if it should get processed by xfrm4_rcv_encap */static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb){#ifndef CONFIG_XFRM	return 1; #else	struct udp_opt *up = udp_sk(sk);  	struct udphdr *uh = skb->h.uh;	struct iphdr *iph;	int iphlen, len;  	__u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);	__u32 *udpdata32 = (__u32 *)udpdata;	__u16 encap_type = up->encap_type;	/* if we're overly short, let UDP handle it */	if (udpdata > skb->tail)		return 1;	/* if this is not encapsulated socket, then just return now */	if (!encap_type)		return 1;	len = skb->tail - udpdata;	switch (encap_type) {	default:	case UDP_ENCAP_ESPINUDP:		/* Check if this is a keepalive packet.  If so, eat it. */		if (len == 1 && udpdata[0] == 0xff) {			return 0;		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0 ) {			/* ESP Packet without Non-ESP header */			len = sizeof(struct udphdr);		} else			/* Must be an IKE packet.. pass it through */			return 1;		break;	case UDP_ENCAP_ESPINUDP_NON_IKE:		/* Check if this is a keepalive packet.  If so, eat it. */		if (len == 1 && udpdata[0] == 0xff) {			return 0;		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&			   udpdata32[0] == 0 && udpdata32[1] == 0) {						/* ESP Packet with Non-IKE marker */			len = sizeof(struct udphdr) + 2 * sizeof(u32);		} else			/* Must be an IKE packet.. pass it through */			return 1;		break;	}	/* At this point we are sure that this is an ESPinUDP packet,	 * so we need to remove 'len' bytes from the packet (the UDP	 * header and optional ESP marker bytes) and then modify the	 * protocol to ESP, and then call into the transform receiver.	 */	/* Now we can update and verify the packet length... */	iph = skb->nh.iph;	iphlen = iph->ihl << 2;	iph->tot_len = htons(ntohs(iph->tot_len) - len);	if (skb->len < iphlen + len) {		/* packet is too small!?! */		return 0;	}	/* pull the data buffer up to the ESP header and set the	 * transport header to point to ESP.  Keep UDP on the stack	 * for later.	 */	skb->h.raw = skb_pull(skb, len);	/* modify the protocol (it's ESP!) */	iph->protocol = IPPROTO_ESP;	/* and let the caller know to send this into the ESP processor... */	return -1;#endif}/* returns: *  -1: error *   0: success *  >0: "udp encap" protocol resubmission * * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb){	struct udp_opt *up = udp_sk(sk);	/*	 *	Charge it to the socket, dropping if the queue is full.	 */	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {		kfree_skb(skb);		return -1;	}	if (up->encap_type) {		/*		 * This is an encapsulation socket, so let's see if this is		 * an encapsulated packet.		 * If it's a keepalive packet, then just eat it.		 * If it's an encapsulateed packet, then pass it to the		 * IPsec xfrm input and return the response		 * appropriately.  Otherwise, just fall through and		 * pass this up the UDP socket.		 */		int ret;		ret = udp_encap_rcv(sk, skb);		if (ret == 0) {			/* Eat the packet .. */			kfree_skb(skb);			return 0;		}		if (ret < 0) {

⌨️ 快捷键说明

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