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

📄 udp.c

📁 ipv6地址转换器
💻 C
📖 第 1 页 / 共 2 页
字号:
		return;	if (sk->net_pinfo.af_inet6.recverr)		ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));	sk->err = err;	sk->error_report(sk);}static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb){#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_stats_in6.UdpInErrors++;			ipv6_statistics.Ip6InDiscards++;			kfree_skb(skb);			return 0;		}		skb->ip_summed = CHECKSUM_UNNECESSARY;	}#endif	if (sock_queue_rcv_skb(sk,skb)<0) {		udp_stats_in6.UdpInErrors++;		ipv6_statistics.Ip6InDiscards++;		kfree_skb(skb);		return 0;	}  	ipv6_statistics.Ip6InDelivers++;	udp_stats_in6.UdpInDatagrams++;	return 0;}static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr){	struct ipv6_mc_socklist *mc;			for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {		if (ipv6_addr_cmp(&mc->addr, addr) == 0)			return 1;	}	return 0;}static struct sock *udp_v6_mcast_next(struct sock *sk,				      u16 loc_port, struct in6_addr *loc_addr,				      u16 rmt_port, struct in6_addr *rmt_addr,				      int dif){	struct sock *s = sk;	unsigned short num = ntohs(loc_port);	for(; s; s = s->next) {		if((s->num == num)		&&		   !(s->dead && (s->state == TCP_CLOSE))) {			struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;			if(s->dport) {				if(s->dport != rmt_port)					continue;			}			if(!ipv6_addr_any(&np->daddr) &&			   ipv6_addr_cmp(&np->daddr, rmt_addr))				continue;			if (s->bound_dev_if && s->bound_dev_if != dif)				continue;			if(!ipv6_addr_any(&np->rcv_saddr)) {				if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)					return s;			}			if(!inet6_mc_check(s, loc_addr))				continue;			return s;		}	}	return NULL;}/* * Note: called only from the BH handler context, * so we don't need to lock the hashes. */static void udpv6_mcast_deliver(struct udphdr *uh,				struct in6_addr *saddr, struct in6_addr *daddr,				struct sk_buff *skb){	struct sock *sk, *sk2;	struct sk_buff *buff;	int dif;	sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];	dif = skb->dev->ifindex;	sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);	if (!sk)		goto free_skb;	buff = NULL;	sk2 = sk;	while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,						  uh->source, daddr, dif))) {		if (!buff) {			buff = skb_clone(skb, GFP_ATOMIC);			if (!buff)				continue;		}		if (sock_queue_rcv_skb(sk2, buff) >= 0)			buff = NULL;	}	if (buff)		kfree_skb(buff);	if (sock_queue_rcv_skb(sk, skb) < 0) {free_skb:		kfree_skb(skb);	}}int udpv6_rcv(struct sk_buff *skb, unsigned long len){	struct sock *sk;  	struct udphdr *uh;	struct device *dev = skb->dev;	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;	u32 ulen;	uh = skb->h.uh;	__skb_pull(skb, skb->h.raw - skb->data);	ulen = ntohs(uh->len);	/* Check for jumbo payload */	if (ulen == 0 && skb->nh.ipv6h->payload_len == 0)		ulen = len;	if (ulen > len || len < sizeof(*uh)) {		if (net_ratelimit())			printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len);		udp_stats_in6.UdpInErrors++;		kfree_skb(skb);		return(0);	}	if (uh->check == 0) {		/* IPv6 draft-v2 section 8.1 says that we SHOULD log		   this error. Well, it is reasonable.		 */		if (net_ratelimit())			printk(KERN_INFO "IPv6: udp checksum is 0\n");		goto discard;	}	skb_trim(skb, ulen);#ifndef CONFIG_UDP_DELAY_CSUM	switch (skb->ip_summed) {	case CHECKSUM_NONE:		skb->csum = csum_partial((char*)uh, ulen, 0);	case CHECKSUM_HW:		if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {			printk(KERN_DEBUG "IPv6: udp checksum error\n");			goto discard;		}	};#else	if (skb->ip_summed==CHECKSUM_HW) {		if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))			goto discard;		skb->ip_summed = CHECKSUM_UNNECESSARY;	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)		skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);#endif	len = ulen;	/* 	 *	Multicast receive code 	 */	if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {		udpv6_mcast_deliver(uh, saddr, daddr, skb);		return 0;	}	/* Unicast */		/* 	 * check socket cache ... must talk to Alan about his plans	 * for sock caches... i'll skip this for now.	 */		sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);		if (sk == NULL) {#ifdef CONFIG_UDP_DELAY_CSUM		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&		    (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum)))			goto discard;#endif		udp_stats_in6.UdpNoPorts++;		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);		kfree_skb(skb);		return(0);	}		/* deliver */		udpv6_queue_rcv_skb(sk, skb);		return(0);	discard:	udp_stats_in6.UdpInErrors++;	kfree_skb(skb);	return(0);	}/* *	Sending */struct udpv6fakehdr {	struct udphdr	uh;	struct iovec	*iov;	__u32		wcheck;	__u32		pl_len;	struct in6_addr *daddr;};/* *	with checksum */static int udpv6_getfrag(const void *data, struct in6_addr *addr,			 char *buff, unsigned int offset, unsigned int len){	struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;	char *dst;	int final = 0;	int clen = len;	dst = buff;	if (offset) {		offset -= sizeof(struct udphdr);	} else {		dst += sizeof(struct udphdr);		final = 1;		clen -= sizeof(struct udphdr);	}	if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,					   clen, &udh->wcheck))		return -EFAULT;	if (final) {		struct in6_addr *daddr;				udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),					   udh->wcheck);		if (udh->daddr) {			daddr = udh->daddr;		} else {			/*			 *	use packet destination address			 *	this should improve cache locality			 */			daddr = addr + 1;		}		udh->uh.check = csum_ipv6_magic(addr, daddr,						udh->pl_len, IPPROTO_UDP,						udh->wcheck);		if (udh->uh.check == 0)			udh->uh.check = -1;		memcpy(buff, udh, sizeof(struct udphdr));	}	return 0;}static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen){	struct ipv6_txoptions opt_space;	struct udpv6fakehdr udh;	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;	struct ipv6_txoptions *opt = NULL;	struct ip6_flowlabel *flowlabel = NULL;	struct flowi fl;	int addr_len = msg->msg_namelen;	struct in6_addr *daddr;	int len = ulen + sizeof(struct udphdr);	int addr_type;	int hlimit = -1;		int err;		/* Rough check on arithmetic overflow,	   better check is made in ip6_build_xmit	   */	if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))		return -EMSGSIZE;		if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))		return(-EINVAL);	fl.fl6_flowlabel = 0;	if (sin6) {		if (sin6->sin6_family == AF_INET)			return udp_sendmsg(sk, msg, ulen);		if (addr_len < sizeof(*sin6))			return(-EINVAL);		if (sin6->sin6_family && sin6->sin6_family != AF_INET6)			return(-EINVAL);		if (sin6->sin6_port == 0)			return(-EINVAL);		udh.uh.dest = 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->dst_cache. */		if (sk->state == TCP_ESTABLISHED &&		    !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))			daddr = &sk->net_pinfo.af_inet6.daddr;	} else {		if (sk->state != TCP_ESTABLISHED)			return(-ENOTCONN);		udh.uh.dest = sk->dport;		daddr = &sk->net_pinfo.af_inet6.daddr;		fl.fl6_flowlabel = np->flow_label;	}	addr_type = ipv6_addr_type(daddr);	if (addr_type == IPV6_ADDR_MAPPED) {		struct sockaddr_in sin;		sin.sin_family = AF_INET;		sin.sin_addr.s_addr = daddr->s6_addr32[3];		sin.sin_port = udh.uh.dest;		msg->msg_name = (struct sockaddr *)(&sin);		msg->msg_namelen = sizeof(sin);		fl6_sock_release(flowlabel);		return udp_sendmsg(sk, msg, ulen);	}	udh.daddr = NULL;	fl.oif = sk->bound_dev_if;	fl.fl6_src = NULL;	if (msg->msg_controllen) {		opt = &opt_space;		memset(opt, 0, sizeof(struct ipv6_txoptions));		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);	if (opt && opt->srcrt)		udh.daddr = daddr;	udh.uh.source = sk->sport;	udh.uh.len = len < 0x10000 ? htons(len) : 0;	udh.uh.check = 0;	udh.iov = msg->msg_iov;	udh.wcheck = 0;	udh.pl_len = len;	fl.proto = IPPROTO_UDP;	fl.fl6_dst = daddr;	fl.uli_u.ports.dport = udh.uh.dest;	fl.uli_u.ports.sport = udh.uh.source;	err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,			     msg->msg_flags);	fl6_sock_release(flowlabel);	if (err < 0)		return err;	udp_stats_in6.UdpOutDatagrams++;	return ulen;}static struct inet6_protocol udpv6_protocol = {	udpv6_rcv,		/* UDP handler		*/	udpv6_err,		/* UDP error control	*/	NULL,			/* next			*/	IPPROTO_UDP,		/* protocol ID		*/	0,			/* copy			*/	NULL,			/* data			*/	"UDPv6"			/* name			*/};struct proto udpv6_prot = {	(struct sock *)&udpv6_prot,	/* sklist_next */	(struct sock *)&udpv6_prot,	/* sklist_prev */	udpv6_close,			/* close */	udpv6_connect,			/* connect */	NULL,				/* accept */	NULL,				/* retransmit */	NULL,				/* write_wakeup */	NULL,				/* read_wakeup */	datagram_poll,			/* poll */	udp_ioctl,			/* ioctl */	NULL,				/* init */	inet6_destroy_sock,		/* destroy */	NULL,				/* shutdown */	ipv6_setsockopt,		/* setsockopt */	ipv6_getsockopt,		/* getsockopt */	udpv6_sendmsg,			/* sendmsg */	udpv6_recvmsg,			/* recvmsg */	NULL,				/* bind */	udpv6_queue_rcv_skb,		/* backlog_rcv */	udp_v6_hash,			/* hash */	udp_v6_unhash,			/* unhash */	udp_v6_get_port,		/* get_port */	128,				/* max_header */	0,				/* retransmits */	"UDP",				/* name */	0,				/* inuse */	0				/* highestinuse */};void __init udpv6_init(void){	inet6_add_protocol(&udpv6_protocol);}

⌨️ 快捷键说明

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