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

📄 udp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
					       skb->len, proto, 0);	/* Probably, we should checksum udp header (it should be in cache	 * in any case) and data in tiny packets (< rx copybreak).	 */	return 0;}/* *	All we need to do is get the socket, and then do a checksum. */int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],		   int proto){	struct sock *sk;	struct udphdr *uh = udp_hdr(skb);	unsigned short ulen;	struct rtable *rt = (struct rtable*)skb->dst;	__be32 saddr = ip_hdr(skb)->saddr;	__be32 daddr = ip_hdr(skb)->daddr;	/*	 *  Validate the packet.	 */	if (!pskb_may_pull(skb, sizeof(struct udphdr)))		goto drop;		/* No space for header. */	ulen = ntohs(uh->len);	if (ulen > skb->len)		goto short_packet;	if (proto == IPPROTO_UDP) {		/* UDP validates ulen. */		if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))			goto short_packet;		uh = udp_hdr(skb);	}	if (udp4_csum_init(skb, uh, proto))		goto csum_error;	if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))		return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);	sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,			       inet_iif(skb), udptable);	if (sk != NULL) {		int ret = udp_queue_rcv_skb(sk, skb);		sock_put(sk);		/* a return value > 0 means to resubmit the input, but		 * it wants the return to be -protocol, or 0		 */		if (ret > 0)			return -ret;		return 0;	}	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))		goto drop;	nf_reset(skb);	/* No socket. Drop packet silently, if checksum is wrong */	if (udp_lib_checksum_complete(skb))		goto csum_error;	UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);	/*	 * Hmm.  We got an UDP packet to a port to which we	 * don't wanna listen.  Ignore it.	 */	kfree_skb(skb);	return 0;short_packet:	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",		       proto == IPPROTO_UDPLITE ? "-Lite" : "",		       NIPQUAD(saddr),		       ntohs(uh->source),		       ulen,		       skb->len,		       NIPQUAD(daddr),		       ntohs(uh->dest));	goto drop;csum_error:	/*	 * RFC1122: OK.  Discards the bad packet silently (as far as	 * the network is concerned, anyway) as per 4.1.3.4 (MUST).	 */	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",		       proto == IPPROTO_UDPLITE ? "-Lite" : "",		       NIPQUAD(saddr),		       ntohs(uh->source),		       NIPQUAD(daddr),		       ntohs(uh->dest),		       ulen);drop:	UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);	kfree_skb(skb);	return 0;}int udp_rcv(struct sk_buff *skb){	return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);}int udp_destroy_sock(struct sock *sk){	lock_sock(sk);	udp_flush_pending_frames(sk);	release_sock(sk);	return 0;}/* *	Socket option code for UDP */int udp_lib_setsockopt(struct sock *sk, int level, int optname,		       char __user *optval, int optlen,		       int (*push_pending_frames)(struct sock *)){	struct udp_sock *up = udp_sk(sk);	int val;	int err = 0;	if (optlen<sizeof(int))		return -EINVAL;	if (get_user(val, (int __user *)optval))		return -EFAULT;	switch (optname) {	case UDP_CORK:		if (val != 0) {			up->corkflag = 1;		} else {			up->corkflag = 0;			lock_sock(sk);			(*push_pending_frames)(sk);			release_sock(sk);		}		break;	case UDP_ENCAP:		switch (val) {		case 0:		case UDP_ENCAP_ESPINUDP:		case UDP_ENCAP_ESPINUDP_NON_IKE:			up->encap_rcv = xfrm4_udp_encap_rcv;			/* FALLTHROUGH */		case UDP_ENCAP_L2TPINUDP:			up->encap_type = val;			break;		default:			err = -ENOPROTOOPT;			break;		}		break;	/*	 * 	UDP-Lite's partial checksum coverage (RFC 3828).	 */	/* The sender sets actual checksum coverage length via this option.	 * The case coverage > packet length is handled by send module. */	case UDPLITE_SEND_CSCOV:		if (!up->pcflag)         /* Disable the option on UDP sockets */			return -ENOPROTOOPT;		if (val != 0 && val < 8) /* Illegal coverage: use default (8) */			val = 8;		up->pcslen = val;		up->pcflag |= UDPLITE_SEND_CC;		break;	/* The receiver specifies a minimum checksum coverage value. To make	 * sense, this should be set to at least 8 (as done below). If zero is	 * used, this again means full checksum coverage.                     */	case UDPLITE_RECV_CSCOV:		if (!up->pcflag)         /* Disable the option on UDP sockets */			return -ENOPROTOOPT;		if (val != 0 && val < 8) /* Avoid silly minimal values.       */			val = 8;		up->pcrlen = val;		up->pcflag |= UDPLITE_RECV_CC;		break;	default:		err = -ENOPROTOOPT;		break;	}	return err;}int udp_setsockopt(struct sock *sk, int level, int optname,		   char __user *optval, int optlen){	if (level == SOL_UDP  ||  level == SOL_UDPLITE)		return udp_lib_setsockopt(sk, level, optname, optval, optlen,					  udp_push_pending_frames);	return ip_setsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATint compat_udp_setsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int optlen){	if (level == SOL_UDP  ||  level == SOL_UDPLITE)		return udp_lib_setsockopt(sk, level, optname, optval, optlen,					  udp_push_pending_frames);	return compat_ip_setsockopt(sk, level, optname, optval, optlen);}#endifint udp_lib_getsockopt(struct sock *sk, int level, int optname,		       char __user *optval, int __user *optlen){	struct udp_sock *up = udp_sk(sk);	int val, len;	if (get_user(len,optlen))		return -EFAULT;	len = min_t(unsigned int, len, sizeof(int));	if (len < 0)		return -EINVAL;	switch (optname) {	case UDP_CORK:		val = up->corkflag;		break;	case UDP_ENCAP:		val = up->encap_type;		break;	/* The following two cannot be changed on UDP sockets, the return is	 * always 0 (which corresponds to the full checksum coverage of UDP). */	case UDPLITE_SEND_CSCOV:		val = up->pcslen;		break;	case UDPLITE_RECV_CSCOV:		val = up->pcrlen;		break;	default:		return -ENOPROTOOPT;	}	if (put_user(len, optlen))		return -EFAULT;	if (copy_to_user(optval, &val,len))		return -EFAULT;	return 0;}int udp_getsockopt(struct sock *sk, int level, int optname,		   char __user *optval, int __user *optlen){	if (level == SOL_UDP  ||  level == SOL_UDPLITE)		return udp_lib_getsockopt(sk, level, optname, optval, optlen);	return ip_getsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATint compat_udp_getsockopt(struct sock *sk, int level, int optname,				 char __user *optval, int __user *optlen){	if (level == SOL_UDP  ||  level == SOL_UDPLITE)		return udp_lib_getsockopt(sk, level, optname, optval, optlen);	return compat_ip_getsockopt(sk, level, optname, optval, optlen);}#endif/** * 	udp_poll - wait for a UDP event. *	@file - file struct *	@sock - socket *	@wait - poll table * *	This is same as datagram poll, except for the special case of *	blocking sockets. If application is using a blocking fd *	and a packet with checksum error is in the queue; *	then it could get return from select indicating data available *	but then block when reading it. Add special case code *	to work around these arguably broken applications. */unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait){	unsigned int mask = datagram_poll(file, sock, wait);	struct sock *sk = sock->sk;	int 	is_lite = IS_UDPLITE(sk);	/* Check for false positives due to checksum errors */	if ( (mask & POLLRDNORM) &&	     !(file->f_flags & O_NONBLOCK) &&	     !(sk->sk_shutdown & RCV_SHUTDOWN)){		struct sk_buff_head *rcvq = &sk->sk_receive_queue;		struct sk_buff *skb;		spin_lock_bh(&rcvq->lock);		while ((skb = skb_peek(rcvq)) != NULL &&		       udp_lib_checksum_complete(skb)) {			UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite);			__skb_unlink(skb, rcvq);			kfree_skb(skb);		}		spin_unlock_bh(&rcvq->lock);		/* nothing to see, move along */		if (skb == NULL)			mask &= ~(POLLIN | POLLRDNORM);	}	return mask;}DEFINE_PROTO_INUSE(udp)struct proto udp_prot = {	.name		   = "UDP",	.owner		   = THIS_MODULE,	.close		   = udp_lib_close,	.connect	   = ip4_datagram_connect,	.disconnect	   = udp_disconnect,	.ioctl		   = udp_ioctl,	.destroy	   = udp_destroy_sock,	.setsockopt	   = udp_setsockopt,	.getsockopt	   = udp_getsockopt,	.sendmsg	   = udp_sendmsg,	.recvmsg	   = udp_recvmsg,	.sendpage	   = udp_sendpage,	.backlog_rcv	   = udp_queue_rcv_skb,	.hash		   = udp_lib_hash,	.unhash		   = udp_lib_unhash,	.get_port	   = udp_v4_get_port,	.obj_size	   = sizeof(struct udp_sock),#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_udp_setsockopt,	.compat_getsockopt = compat_udp_getsockopt,#endif	REF_PROTO_INUSE(udp)};/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSstatic struct sock *udp_get_first(struct seq_file *seq){	struct sock *sk;	struct udp_iter_state *state = seq->private;	for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {		struct hlist_node *node;		sk_for_each(sk, node, state->hashtable + state->bucket) {			if (sk->sk_family == state->family)				goto found;		}	}	sk = NULL;found:	return sk;}static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk){	struct udp_iter_state *state = seq->private;	do {		sk = sk_next(sk);try_again:		;	} while (sk && sk->sk_family != state->family);	if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {		sk = sk_head(state->hashtable + state->bucket);		goto try_again;	}	return sk;}static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos){	struct sock *sk = udp_get_first(seq);	if (sk)		while (pos && (sk = udp_get_next(seq, sk)) != NULL)			--pos;	return pos ? NULL : sk;}static void *udp_seq_start(struct seq_file *seq, loff_t *pos){	read_lock(&udp_hash_lock);	return *pos ? udp_get_idx(seq, *pos-1) : (void *)1;}static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct sock *sk;	if (v == (void *)1)		sk = udp_get_idx(seq, 0);	else		sk = udp_get_next(seq, v);	++*pos;	return sk;}static void udp_seq_stop(struct seq_file *seq, void *v){	read_unlock(&udp_hash_lock);}static int udp_seq_open(struct inode *inode, struct file *file){	struct udp_seq_afinfo *afinfo = PDE(inode)->data;	struct seq_file *seq;	int rc = -ENOMEM;	struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);	if (!s)		goto out;	s->family		= afinfo->family;	s->hashtable		= afinfo->hashtable;	s->seq_ops.start	= udp_seq_start;	s->seq_ops.next		= udp_seq_next;	s->seq_ops.show		= afinfo->seq_show;	s->seq_ops.stop		= udp_seq_stop;	rc = seq_open(file, &s->seq_ops);	if (rc)		goto out_kfree;	seq	     = file->private_data;	seq->private = s;out:	return rc;out_kfree:	kfree(s);	goto out;}/* ------------------------------------------------------------------------ */int udp_proc_register(struct udp_seq_afinfo *afinfo){	struct proc_dir_entry *p;	int rc = 0;	if (!afinfo)		return -EINVAL;	afinfo->seq_fops->owner		= afinfo->owner;	afinfo->seq_fops->open		= udp_seq_open;	afinfo->seq_fops->read		= seq_read;	afinfo->seq_fops->llseek	= seq_lseek;	afinfo->seq_fops->release	= seq_release_private;	p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);	if (p)		p->data = afinfo;	else		rc = -ENOMEM;	return rc;}void udp_proc_unregister(struct udp_seq_afinfo *afinfo){	if (!afinfo)		return;	proc_net_remove(&init_net, afinfo->name);	memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));}/* ------------------------------------------------------------------------ */static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket){	struct inet_sock *inet = inet_sk(sp);	__be32 dest = inet->daddr;	__be32 src  = inet->rcv_saddr;	__u16 destp	  = ntohs(inet->dport);	__u16 srcp	  = ntohs(inet->sport);	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",		bucket, src, srcp, dest, destp, sp->sk_state,		atomic_read(&sp->sk_wmem_alloc),		atomic_read(&sp->sk_rmem_alloc),		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),		atomic_read(&sp->sk_refcnt), sp);}int udp4_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN)		seq_printf(seq, "%-127s\n",			   "  sl  local_address rem_address   st tx_queue "			   "rx_queue tr tm->when retrnsmt   uid  timeout "			   "inode");	else {		char tmpbuf[129];		struct udp_iter_state *state = seq->private;		udp4_format_sock(v, tmpbuf, state->bucket);		seq_printf(seq, "%-127s\n", tmpbuf);	}	return 0;}/* ------------------------------------------------------------------------ */static struct file_operations udp4_seq_fops;static struct udp_seq_afinfo udp4_seq_afinfo = {	.owner		= THIS_MODULE,	.name		= "udp",	.family		= AF_INET,	.hashtable	= udp_hash,	.seq_show	= udp4_seq_show,	.seq_fops	= &udp4_seq_fops,};int __init udp4_proc_init(void){	return udp_proc_register(&udp4_seq_afinfo);}void udp4_proc_exit(void){	udp_proc_unregister(&udp4_seq_afinfo);}#endif /* CONFIG_PROC_FS */EXPORT_SYMBOL(udp_disconnect);EXPORT_SYMBOL(udp_hash);EXPORT_SYMBOL(udp_hash_lock);EXPORT_SYMBOL(udp_ioctl);EXPORT_SYMBOL(udp_get_port);EXPORT_SYMBOL(udp_prot);EXPORT_SYMBOL(udp_sendmsg);EXPORT_SYMBOL(udp_lib_getsockopt);EXPORT_SYMBOL(udp_lib_setsockopt);EXPORT_SYMBOL(udp_poll);#ifdef CONFIG_PROC_FSEXPORT_SYMBOL(udp_proc_register);EXPORT_SYMBOL(udp_proc_unregister);#endif

⌨️ 快捷键说明

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