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

📄 udp.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
short_packet:		if (net_ratelimit())		printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len);discard:	UDP6_INC_STATS_BH(UDP_MIB_INERRORS);	kfree_skb(skb);	return(0);	}/* * Throw away all pending data and cancel the corking. Socket is locked. */static void udp_v6_flush_pending_frames(struct sock *sk){	struct udp_opt *up = udp_sk(sk);	if (up->pending) {		up->len = 0;		up->pending = 0;		ip6_flush_pending_frames(sk);        }}/* *	Sending */static int udp_v6_push_pending_frames(struct sock *sk, struct udp_opt *up){	struct sk_buff *skb;	struct udphdr *uh;	struct inet_opt *inet = inet_sk(sk);	struct flowi *fl = &inet->cork.fl;	int err = 0;	/* Grab the skbuff where UDP header space exists. */	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)		goto out;	/*	 * Create a UDP header	 */	uh = skb->h.uh;	uh->source = fl->fl_ip_sport;	uh->dest = fl->fl_ip_dport;	uh->len = htons(up->len);	uh->check = 0;	if (sk->sk_no_check == UDP_CSUM_NOXMIT) {		skb->ip_summed = CHECKSUM_NONE;		goto send;	}	if (skb_queue_len(&sk->sk_write_queue) == 1) {		skb->csum = csum_partial((char *)uh,				sizeof(struct udphdr), skb->csum);		uh->check = csum_ipv6_magic(&fl->fl6_src,					    &fl->fl6_dst,					    up->len, fl->proto, skb->csum);	} else {		u32 tmp_csum = 0;		skb_queue_walk(&sk->sk_write_queue, skb) {			tmp_csum = csum_add(tmp_csum, skb->csum);		}		tmp_csum = csum_partial((char *)uh,				sizeof(struct udphdr), tmp_csum);                tmp_csum = csum_ipv6_magic(&fl->fl6_src,					   &fl->fl6_dst,					   up->len, fl->proto, tmp_csum);                uh->check = tmp_csum;	}	if (uh->check == 0)		uh->check = -1;send:	err = ip6_push_pending_frames(sk);out:	up->len = 0;	up->pending = 0;	return err;}static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, 		  struct msghdr *msg, size_t len){	struct ipv6_txoptions opt_space;	struct udp_opt *up = udp_sk(sk);	struct inet_opt *inet = inet_sk(sk);	struct ipv6_pinfo *np = inet6_sk(sk);	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;	struct in6_addr *daddr, *final_p = NULL, final;	struct ipv6_txoptions *opt = NULL;	struct ip6_flowlabel *flowlabel = NULL;	struct flowi *fl = &inet->cork.fl;	struct dst_entry *dst;	int addr_len = msg->msg_namelen;	int ulen = len;	int hlimit = -1;	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;	int err;	/* destination address check */	if (sin6) {		if (addr_len < offsetof(struct sockaddr, sa_data))			return -EINVAL;		switch (sin6->sin6_family) {		case AF_INET6:			if (addr_len < SIN6_LEN_RFC2133)				return -EINVAL;			daddr = &sin6->sin6_addr;			break;		case AF_INET:			goto do_udp_sendmsg;		case AF_UNSPEC:			msg->msg_name = sin6 = NULL;			msg->msg_namelen = addr_len = 0;			daddr = NULL;			break;		default:			return -EINVAL;		}	} else if (!up->pending) {		if (sk->sk_state != TCP_ESTABLISHED)			return -EDESTADDRREQ;		daddr = &np->daddr;	} else 		daddr = NULL;	if (daddr) {		if (ipv6_addr_type(daddr) == IPV6_ADDR_MAPPED) {			struct sockaddr_in sin;			sin.sin_family = AF_INET;			sin.sin_port = sin6 ? sin6->sin6_port : inet->dport;			sin.sin_addr.s_addr = daddr->s6_addr32[3];			msg->msg_name = &sin;			msg->msg_namelen = sizeof(sin);do_udp_sendmsg:			if (__ipv6_only_sock(sk))				return -ENETUNREACH;			return udp_sendmsg(iocb, sk, msg, len);		}	}	if (up->pending == AF_INET)		return udp_sendmsg(iocb, sk, msg, len);	/* Rough check on arithmetic overflow,	   better check is made in ip6_build_xmit	   */	if (len > INT_MAX - sizeof(struct udphdr))		return -EMSGSIZE;		if (up->pending) {		/*		 * 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_INET6)) {				release_sock(sk);				return -EINVAL;			}			dst = NULL;			goto do_append_data;		}		release_sock(sk);	}	ulen += sizeof(struct udphdr);	memset(fl, 0, sizeof(*fl));	if (sin6) {		if (sin6->sin6_port == 0)			return -EINVAL;		fl->fl_ip_dport = sin6->sin6_port;		daddr = &sin6->sin6_addr;		if (np->sndflow) {			fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;			if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) {				flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);				if (flowlabel == NULL)					return -EINVAL;				daddr = &flowlabel->dst;			}		}		/*		 * Otherwise it will be difficult to maintain		 * sk->sk_dst_cache.		 */		if (sk->sk_state == TCP_ESTABLISHED &&		    !ipv6_addr_cmp(daddr, &np->daddr))			daddr = &np->daddr;		if (addr_len >= sizeof(struct sockaddr_in6) &&		    sin6->sin6_scope_id &&		    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)			fl->oif = sin6->sin6_scope_id;	} else {		if (sk->sk_state != TCP_ESTABLISHED)			return -EDESTADDRREQ;		fl->fl_ip_dport = inet->dport;		daddr = &np->daddr;		fl->fl6_flowlabel = np->flow_label;	}	if (!fl->oif)		fl->oif = sk->sk_bound_dev_if;	if (msg->msg_controllen) {		opt = &opt_space;		memset(opt, 0, sizeof(struct ipv6_txoptions));		opt->tot_len = sizeof(*opt);		err = datagram_send_ctl(msg, fl, opt, &hlimit);		if (err < 0) {			fl6_sock_release(flowlabel);			return err;		}		if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {			flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);			if (flowlabel == NULL)				return -EINVAL;		}		if (!(opt->opt_nflen|opt->opt_flen))			opt = NULL;	}	if (opt == NULL)		opt = np->opt;	if (flowlabel)		opt = fl6_merge_options(&opt_space, flowlabel, opt);	fl->proto = IPPROTO_UDP;	ipv6_addr_copy(&fl->fl6_dst, daddr);	if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr))		ipv6_addr_copy(&fl->fl6_src, &np->saddr);	fl->fl_ip_sport = inet->sport;		/* merge ip6_build_xmit from ip6_output */	if (opt && opt->srcrt) {		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;		ipv6_addr_copy(&final, &fl->fl6_dst);		ipv6_addr_copy(&fl->fl6_dst, rt0->addr);		final_p = &final;	}	if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst))		fl->oif = np->mcast_oif;	err = ip6_dst_lookup(sk, &dst, fl);	if (err)		goto out;	if (final_p)		ipv6_addr_copy(&fl->fl6_dst, final_p);	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {		dst_release(dst);		goto out;	}	if (hlimit < 0) {		if (ipv6_addr_is_multicast(&fl->fl6_dst))			hlimit = np->mcast_hops;		else			hlimit = np->hop_limit;		if (hlimit < 0)			hlimit = dst_metric(dst, RTAX_HOPLIMIT);	}	if (msg->msg_flags&MSG_CONFIRM)		goto do_confirm;back_from_confirm:	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);		LIMIT_NETDEBUG(printk(KERN_DEBUG "udp cork app bug 2\n"));		err = -EINVAL;		goto out;	}	up->pending = AF_INET6;do_append_data:	up->len += ulen;	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr),			      hlimit, opt, fl, (struct rt6_info*)dst,			      corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);	if (err)		udp_v6_flush_pending_frames(sk);	else if (!corkreq)		err = udp_v6_push_pending_frames(sk, up);	if (dst)		ip6_dst_store(sk, dst,			      !ipv6_addr_cmp(&fl->fl6_dst, &np->daddr) ?			      &np->daddr : NULL);	if (err > 0)		err = np->recverr ? net_xmit_errno(err) : 0;	release_sock(sk);out:	fl6_sock_release(flowlabel);	if (!err) {		UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);		return len;	}	return err;do_confirm:	dst_confirm(dst);	if (!(msg->msg_flags&MSG_PROBE) || len)		goto back_from_confirm;	err = 0;	goto out;}static int udpv6_destroy_sock(struct sock *sk){	lock_sock(sk);	udp_v6_flush_pending_frames(sk);	release_sock(sk);	inet6_destroy_sock(sk);	return 0;}/* *	Socket option code for UDP */static int udpv6_setsockopt(struct sock *sk, int level, int optname, 			  char __user *optval, int optlen){	struct udp_opt *up = udp_sk(sk);	int val;	int err = 0;	if (level != SOL_UDP)		return ipv6_setsockopt(sk, level, optname, optval, optlen);	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);			udp_v6_push_pending_frames(sk, up);			release_sock(sk);		}		break;			case UDP_ENCAP:		switch (val) {		case 0:			up->encap_type = val;			break;		default:			err = -ENOPROTOOPT;			break;		}		break;	default:		err = -ENOPROTOOPT;		break;	};	return err;}static int udpv6_getsockopt(struct sock *sk, int level, int optname, 			  char __user *optval, int __user *optlen){	struct udp_opt *up = udp_sk(sk);	int val, len;	if (level != SOL_UDP)		return ipv6_getsockopt(sk, level, optname, optval, optlen);	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;	default:		return -ENOPROTOOPT;	};  	if(put_user(len, optlen))  		return -EFAULT;	if(copy_to_user(optval, &val,len))		return -EFAULT;  	return 0;}static struct inet6_protocol udpv6_protocol = {	.handler	=	udpv6_rcv,	.err_handler	=	udpv6_err,	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,};/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSstatic void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket){	struct inet_opt *inet = inet_sk(sp);	struct ipv6_pinfo *np = inet6_sk(sp);	struct in6_addr *dest, *src;	__u16 destp, srcp;	dest  = &np->daddr;	src   = &np->rcv_saddr;	destp = ntohs(inet->dport);	srcp  = ntohs(inet->sport);	seq_printf(seq,		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n",		   bucket,		   src->s6_addr32[0], src->s6_addr32[1],		   src->s6_addr32[2], src->s6_addr32[3], srcp,		   dest->s6_addr32[0], dest->s6_addr32[1],		   dest->s6_addr32[2], dest->s6_addr32[3], 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);}static int udp6_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN)		seq_printf(seq,			   "  sl  "			   "local_address                         "			   "remote_address                        "			   "st tx_queue rx_queue tr tm->when retrnsmt"			   "   uid  timeout inode\n");	else		udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket);	return 0;}static struct file_operations udp6_seq_fops;static struct udp_seq_afinfo udp6_seq_afinfo = {	.owner		= THIS_MODULE,	.name		= "udp6",	.family		= AF_INET6,	.seq_show	= udp6_seq_show,	.seq_fops	= &udp6_seq_fops,};int __init udp6_proc_init(void){	return udp_proc_register(&udp6_seq_afinfo);}void udp6_proc_exit(void) {	udp_proc_unregister(&udp6_seq_afinfo);}#endif /* CONFIG_PROC_FS *//* ------------------------------------------------------------------------ */struct proto udpv6_prot = {	.name =		"UDP",	.close =	udpv6_close,	.connect =	ip6_datagram_connect,	.disconnect =	udp_disconnect,	.ioctl =	udp_ioctl,	.destroy =	udpv6_destroy_sock,	.setsockopt =	udpv6_setsockopt,	.getsockopt =	udpv6_getsockopt,	.sendmsg =	udpv6_sendmsg,	.recvmsg =	udpv6_recvmsg,	.backlog_rcv =	udpv6_queue_rcv_skb,	.hash =		udp_v6_hash,	.unhash =	udp_v6_unhash,	.get_port =	udp_v6_get_port,	.slab_obj_size = sizeof(struct udp6_sock),};extern struct proto_ops inet6_dgram_ops;static struct inet_protosw udpv6_protosw = {	.type =      SOCK_DGRAM,	.protocol =  IPPROTO_UDP,	.prot =      &udpv6_prot,	.ops =       &inet6_dgram_ops,	.capability =-1,	.no_check =  UDP_CSUM_DEFAULT,	.flags =     INET_PROTOSW_PERMANENT,};void __init udpv6_init(void){	if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0)		printk(KERN_ERR "udpv6_init: Could not register protocol\n");	inet6_register_protosw(&udpv6_protosw);}

⌨️ 快捷键说明

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