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

📄 udp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		up->pending = 0;		ip6_flush_pending_frames(sk);	}}/* *	Sending */static int udp_v6_push_pending_frames(struct sock *sk){	struct sk_buff *skb;	struct udphdr *uh;	struct udp_sock  *up = udp_sk(sk);	struct inet_sock *inet = inet_sk(sk);	struct flowi *fl = &inet->cork.fl;	int err = 0;	__wsum csum = 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 = udp_hdr(skb);	uh->source = fl->fl_ip_sport;	uh->dest = fl->fl_ip_dport;	uh->len = htons(up->len);	uh->check = 0;	if (up->pcflag)		csum = udplite_csum_outgoing(sk, skb);	 else		csum = udp_csum_outgoing(sk, skb);	/* add protocol-dependent pseudo-header */	uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst,				    up->len, fl->proto, csum   );	if (uh->check == 0)		uh->check = CSUM_MANGLED_0;	err = ip6_push_pending_frames(sk);out:	up->len = 0;	up->pending = 0;	if (!err)		UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, up->pcflag);	return err;}int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,		  struct msghdr *msg, size_t len){	struct ipv6_txoptions opt_space;	struct udp_sock *up = udp_sk(sk);	struct inet_sock *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;	struct dst_entry *dst;	int addr_len = msg->msg_namelen;	int ulen = len;	int hlimit = -1;	int tclass = -1;	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;	int err;	int connected = 0;	int is_udplite = up->pcflag;	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);	/* 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_v4mapped(daddr)) {			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_append_data().	   */	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 -EAFNOSUPPORT;			}			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_equal(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;		connected = 1;	}	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, &tclass);		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;		connected = 0;	}	if (opt == NULL)		opt = np->opt;	if (flowlabel)		opt = fl6_merge_options(&opt_space, flowlabel, opt);	opt = ipv6_fixup_options(&opt_space, opt);	fl.proto = sk->sk_protocol;	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;		connected = 0;	}	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {		fl.oif = np->mcast_oif;		connected = 0;	}	security_sk_classify_flow(sk, &fl);	err = ip6_sk_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, 1)) < 0) {		if (err == -EREMOTE)			err = ip6_dst_blackhole(sk, &dst, &fl);		if (err < 0)			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 (hlimit < 0)			hlimit = ipv6_get_hoplimit(dst->dev);	}	if (tclass < 0) {		tclass = np->tclass;		if (tclass < 0)			tclass = 0;	}	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(KERN_DEBUG "udp cork app bug 2\n");		err = -EINVAL;		goto out;	}	up->pending = AF_INET6;do_append_data:	up->len += ulen;	getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;	err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,		sizeof(struct udphdr), hlimit, tclass, 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);	else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))		up->pending = 0;	if (dst) {		if (connected) {			ip6_dst_store(sk, dst,				      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?				      &np->daddr : NULL,#ifdef CONFIG_IPV6_SUBTREES				      ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?				      &np->saddr :#endif				      NULL);		} else {			dst_release(dst);		}	}	if (err > 0)		err = np->recverr ? net_xmit_errno(err) : 0;	release_sock(sk);out:	fl6_sock_release(flowlabel);	if (!err)		return len;	/*	 * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space.  Reporting	 * ENOBUFS might not be good (it's not tunable per se), but otherwise	 * we don't have a good statistic (IpOutDiscards but it can be too many	 * things).  We could add another new stat but at least for now that	 * seems like overkill.	 */	if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {		UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite);	}	return err;do_confirm:	dst_confirm(dst);	if (!(msg->msg_flags&MSG_PROBE) || len)		goto back_from_confirm;	err = 0;	goto out;}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 */int udpv6_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_v6_push_pending_frames);	return ipv6_setsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATint compat_udpv6_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_v6_push_pending_frames);	return compat_ipv6_setsockopt(sk, level, optname, optval, optlen);}#endifint udpv6_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 ipv6_getsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATint compat_udpv6_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_ipv6_getsockopt(sk, level, optname, optval, optlen);}#endifstatic 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_sock *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);}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,	.hashtable	= udp_hash,	.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 *//* ------------------------------------------------------------------------ */DEFINE_PROTO_INUSE(udpv6)struct proto udpv6_prot = {	.name		   = "UDPv6",	.owner		   = THIS_MODULE,	.close		   = udp_lib_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_lib_hash,	.unhash		   = udp_lib_unhash,	.get_port	   = udp_v6_get_port,	.obj_size	   = sizeof(struct udp6_sock),#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_udpv6_setsockopt,	.compat_getsockopt = compat_udpv6_getsockopt,#endif	REF_PROTO_INUSE(udpv6)};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 + -