gre: Support GRE over IPv6
GRE over IPv6 implementation. Signed-off-by: Dmitry Kozlov <xeb@mail.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								b7bc2a5b5b
							
						
					
				
			
			
				commit
				
					
						c12b395a46
					
				
			
		
					 9 changed files with 1933 additions and 26 deletions
				
			
		|  | @ -92,6 +92,7 @@ | ||||||
| #define ARPHRD_PHONET	820		/* PhoNet media type		*/ | #define ARPHRD_PHONET	820		/* PhoNet media type		*/ | ||||||
| #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/ | #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/ | ||||||
| #define ARPHRD_CAIF	822		/* CAIF media type		*/ | #define ARPHRD_CAIF	822		/* CAIF media type		*/ | ||||||
|  | #define ARPHRD_IP6GRE	823		/* GRE over IPv6		*/ | ||||||
| 
 | 
 | ||||||
| #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */ | #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */ | ||||||
| #define ARPHRD_NONE	  0xFFFE	/* zero header length */ | #define ARPHRD_NONE	  0xFFFE	/* zero header length */ | ||||||
|  |  | ||||||
|  | @ -75,6 +75,9 @@ enum { | ||||||
| 	IFLA_GRE_TTL, | 	IFLA_GRE_TTL, | ||||||
| 	IFLA_GRE_TOS, | 	IFLA_GRE_TOS, | ||||||
| 	IFLA_GRE_PMTUDISC, | 	IFLA_GRE_PMTUDISC, | ||||||
|  | 	IFLA_GRE_ENCAP_LIMIT, | ||||||
|  | 	IFLA_GRE_FLOWINFO, | ||||||
|  | 	IFLA_GRE_FLAGS, | ||||||
| 	__IFLA_GRE_MAX, | 	__IFLA_GRE_MAX, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,4 +31,21 @@ struct ip6_tnl_parm { | ||||||
| 	struct in6_addr raddr;	/* remote tunnel end-point address */ | 	struct in6_addr raddr;	/* remote tunnel end-point address */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct ip6_tnl_parm2 { | ||||||
|  | 	char name[IFNAMSIZ];	/* name of tunnel device */ | ||||||
|  | 	int link;		/* ifindex of underlying L2 interface */ | ||||||
|  | 	__u8 proto;		/* tunnel protocol */ | ||||||
|  | 	__u8 encap_limit;	/* encapsulation limit for tunnel */ | ||||||
|  | 	__u8 hop_limit;		/* hop limit for tunnel */ | ||||||
|  | 	__be32 flowinfo;	/* traffic class and flowlabel for tunnel */ | ||||||
|  | 	__u32 flags;		/* tunnel flags */ | ||||||
|  | 	struct in6_addr laddr;	/* local tunnel end-point address */ | ||||||
|  | 	struct in6_addr raddr;	/* remote tunnel end-point address */ | ||||||
|  | 
 | ||||||
|  | 	__be16			i_flags; | ||||||
|  | 	__be16			o_flags; | ||||||
|  | 	__be32			i_key; | ||||||
|  | 	__be32			o_key; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
| #include <linux/netdevice.h> | #include <linux/netdevice.h> | ||||||
| #include <linux/ip6_tunnel.h> | #include <linux/ip6_tunnel.h> | ||||||
| 
 | 
 | ||||||
|  | #define IP6TUNNEL_ERR_TIMEO (30*HZ) | ||||||
|  | 
 | ||||||
| /* capable of sending packets */ | /* capable of sending packets */ | ||||||
| #define IP6_TNL_F_CAP_XMIT 0x10000 | #define IP6_TNL_F_CAP_XMIT 0x10000 | ||||||
| /* capable of receiving packets */ | /* capable of receiving packets */ | ||||||
|  | @ -12,15 +14,40 @@ | ||||||
| /* determine capability on a per-packet basis */ | /* determine capability on a per-packet basis */ | ||||||
| #define IP6_TNL_F_CAP_PER_PACKET 0x40000 | #define IP6_TNL_F_CAP_PER_PACKET 0x40000 | ||||||
| 
 | 
 | ||||||
| /* IPv6 tunnel */ | struct __ip6_tnl_parm { | ||||||
|  | 	char name[IFNAMSIZ];	/* name of tunnel device */ | ||||||
|  | 	int link;		/* ifindex of underlying L2 interface */ | ||||||
|  | 	__u8 proto;		/* tunnel protocol */ | ||||||
|  | 	__u8 encap_limit;	/* encapsulation limit for tunnel */ | ||||||
|  | 	__u8 hop_limit;		/* hop limit for tunnel */ | ||||||
|  | 	__be32 flowinfo;	/* traffic class and flowlabel for tunnel */ | ||||||
|  | 	__u32 flags;		/* tunnel flags */ | ||||||
|  | 	struct in6_addr laddr;	/* local tunnel end-point address */ | ||||||
|  | 	struct in6_addr raddr;	/* remote tunnel end-point address */ | ||||||
| 
 | 
 | ||||||
|  | 	__be16			i_flags; | ||||||
|  | 	__be16			o_flags; | ||||||
|  | 	__be32			i_key; | ||||||
|  | 	__be32			o_key; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* IPv6 tunnel */ | ||||||
| struct ip6_tnl { | struct ip6_tnl { | ||||||
| 	struct ip6_tnl __rcu *next;	/* next tunnel in list */ | 	struct ip6_tnl __rcu *next;	/* next tunnel in list */ | ||||||
| 	struct net_device *dev;	/* virtual device associated with tunnel */ | 	struct net_device *dev;	/* virtual device associated with tunnel */ | ||||||
| 	struct ip6_tnl_parm parms;	/* tunnel configuration parameters */ | 	struct __ip6_tnl_parm parms;	/* tunnel configuration parameters */ | ||||||
| 	struct flowi fl;	/* flowi template for xmit */ | 	struct flowi fl;	/* flowi template for xmit */ | ||||||
| 	struct dst_entry *dst_cache;    /* cached dst */ | 	struct dst_entry *dst_cache;    /* cached dst */ | ||||||
| 	u32 dst_cookie; | 	u32 dst_cookie; | ||||||
|  | 
 | ||||||
|  | 	int err_count; | ||||||
|  | 	unsigned long err_time; | ||||||
|  | 
 | ||||||
|  | 	/* These fields used only by GRE */ | ||||||
|  | 	__u32 i_seqno;	/* The last seen seqno	*/ | ||||||
|  | 	__u32 o_seqno;	/* The last output seqno */ | ||||||
|  | 	int hlen;       /* Precalculated GRE header length */ | ||||||
|  | 	int mlink; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Tunnel encapsulation limit destination sub-option */ | /* Tunnel encapsulation limit destination sub-option */ | ||||||
|  | @ -31,4 +58,14 @@ struct ipv6_tlv_tnl_enc_lim { | ||||||
| 	__u8 encap_limit;	/* tunnel encapsulation limit   */ | 	__u8 encap_limit;	/* tunnel encapsulation limit   */ | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
|  | struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t); | ||||||
|  | void ip6_tnl_dst_reset(struct ip6_tnl *t); | ||||||
|  | void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst); | ||||||
|  | int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr, | ||||||
|  | 		const struct in6_addr *raddr); | ||||||
|  | int ip6_tnl_xmit_ctl(struct ip6_tnl *t); | ||||||
|  | __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw); | ||||||
|  | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr, | ||||||
|  | 			     const struct in6_addr *raddr); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -34,6 +34,7 @@ | ||||||
| #define NEXTHDR_IPV6		41	/* IPv6 in IPv6 */ | #define NEXTHDR_IPV6		41	/* IPv6 in IPv6 */ | ||||||
| #define NEXTHDR_ROUTING		43	/* Routing header. */ | #define NEXTHDR_ROUTING		43	/* Routing header. */ | ||||||
| #define NEXTHDR_FRAGMENT	44	/* Fragmentation/reassembly header. */ | #define NEXTHDR_FRAGMENT	44	/* Fragmentation/reassembly header. */ | ||||||
|  | #define NEXTHDR_GRE		47	/* GRE header. */ | ||||||
| #define NEXTHDR_ESP		50	/* Encapsulating security payload. */ | #define NEXTHDR_ESP		50	/* Encapsulating security payload. */ | ||||||
| #define NEXTHDR_AUTH		51	/* Authentication header. */ | #define NEXTHDR_AUTH		51	/* Authentication header. */ | ||||||
| #define NEXTHDR_ICMP		58	/* ICMP for IPv6. */ | #define NEXTHDR_ICMP		58	/* ICMP for IPv6. */ | ||||||
|  |  | ||||||
|  | @ -201,6 +201,22 @@ config IPV6_TUNNEL | ||||||
| 
 | 
 | ||||||
| 	  If unsure, say N. | 	  If unsure, say N. | ||||||
| 
 | 
 | ||||||
|  | config IPV6_GRE | ||||||
|  | 	tristate "IPv6: GRE tunnel" | ||||||
|  | 	select IPV6_TUNNEL | ||||||
|  | 	---help--- | ||||||
|  | 	  Tunneling means encapsulating data of one protocol type within | ||||||
|  | 	  another protocol and sending it over a channel that understands the | ||||||
|  | 	  encapsulating protocol. This particular tunneling driver implements | ||||||
|  | 	  GRE (Generic Routing Encapsulation) and at this time allows | ||||||
|  | 	  encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure. | ||||||
|  | 	  This driver is useful if the other endpoint is a Cisco router: Cisco | ||||||
|  | 	  likes GRE much better than the other Linux tunneling driver ("IP | ||||||
|  | 	  tunneling" above). In addition, GRE allows multicast redistribution | ||||||
|  | 	  through the tunnel. | ||||||
|  | 
 | ||||||
|  | 	  Saying M here will produce a module called ip6_gre. If unsure, say N. | ||||||
|  | 
 | ||||||
| config IPV6_MULTIPLE_TABLES | config IPV6_MULTIPLE_TABLES | ||||||
| 	bool "IPv6: Multiple Routing Tables" | 	bool "IPv6: Multiple Routing Tables" | ||||||
| 	depends on EXPERIMENTAL | 	depends on EXPERIMENTAL | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER)	+= netfilter/ | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_IPV6_SIT) += sit.o | obj-$(CONFIG_IPV6_SIT) += sit.o | ||||||
| obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | ||||||
|  | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | ||||||
| 
 | 
 | ||||||
| obj-y += addrconf_core.o exthdrs_core.o | obj-y += addrconf_core.o exthdrs_core.o | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1790
									
								
								net/ipv6/ip6_gre.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1790
									
								
								net/ipv6/ip6_gre.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -126,7 +126,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev) | ||||||
|  * Locking : hash tables are protected by RCU and RTNL |  * Locking : hash tables are protected by RCU and RTNL | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | ||||||
| { | { | ||||||
| 	struct dst_entry *dst = t->dst_cache; | 	struct dst_entry *dst = t->dst_cache; | ||||||
| 
 | 
 | ||||||
|  | @ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | ||||||
| 
 | 
 | ||||||
| 	return dst; | 	return dst; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(ip6_tnl_dst_check); | ||||||
| 
 | 
 | ||||||
| static inline void ip6_tnl_dst_reset(struct ip6_tnl *t) | void ip6_tnl_dst_reset(struct ip6_tnl *t) | ||||||
| { | { | ||||||
| 	dst_release(t->dst_cache); | 	dst_release(t->dst_cache); | ||||||
| 	t->dst_cache = NULL; | 	t->dst_cache = NULL; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset); | ||||||
| 
 | 
 | ||||||
| static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | ||||||
| { | { | ||||||
| 	struct rt6_info *rt = (struct rt6_info *) dst; | 	struct rt6_info *rt = (struct rt6_info *) dst; | ||||||
| 	t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | 	t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | ||||||
| 	dst_release(t->dst_cache); | 	dst_release(t->dst_cache); | ||||||
| 	t->dst_cache = dst; | 	t->dst_cache = dst; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses |  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses | ||||||
|  | @ -200,7 +203,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ | ||||||
|  **/ |  **/ | ||||||
| 
 | 
 | ||||||
| static struct ip6_tnl __rcu ** | static struct ip6_tnl __rcu ** | ||||||
| ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p) | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p) | ||||||
| { | { | ||||||
| 	const struct in6_addr *remote = &p->raddr; | 	const struct in6_addr *remote = &p->raddr; | ||||||
| 	const struct in6_addr *local = &p->laddr; | 	const struct in6_addr *local = &p->laddr; | ||||||
|  | @ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev) | ||||||
|  *   created tunnel or NULL |  *   created tunnel or NULL | ||||||
|  **/ |  **/ | ||||||
| 
 | 
 | ||||||
| static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) | ||||||
| { | { | ||||||
| 	struct net_device *dev; | 	struct net_device *dev; | ||||||
| 	struct ip6_tnl *t; | 	struct ip6_tnl *t; | ||||||
|  | @ -322,7 +325,7 @@ failed: | ||||||
|  **/ |  **/ | ||||||
| 
 | 
 | ||||||
| static struct ip6_tnl *ip6_tnl_locate(struct net *net, | static struct ip6_tnl *ip6_tnl_locate(struct net *net, | ||||||
| 		struct ip6_tnl_parm *p, int create) | 		struct __ip6_tnl_parm *p, int create) | ||||||
| { | { | ||||||
| 	const struct in6_addr *remote = &p->raddr; | 	const struct in6_addr *remote = &p->raddr; | ||||||
| 	const struct in6_addr *local = &p->laddr; | 	const struct in6_addr *local = &p->laddr; | ||||||
|  | @ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) | ||||||
|  *   else index to encapsulation limit |  *   else index to encapsulation limit | ||||||
|  **/ |  **/ | ||||||
| 
 | 
 | ||||||
| static __u16 | __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) | ||||||
| parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) |  | ||||||
| { | { | ||||||
| 	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; | 	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; | ||||||
| 	__u8 nexthdr = ipv6h->nexthdr; | 	__u8 nexthdr = ipv6h->nexthdr; | ||||||
|  | @ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ip6_tnl_err - tunnel error handler |  * ip6_tnl_err - tunnel error handler | ||||||
|  | @ -480,7 +483,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | ||||||
| 	case ICMPV6_PARAMPROB: | 	case ICMPV6_PARAMPROB: | ||||||
| 		teli = 0; | 		teli = 0; | ||||||
| 		if ((*code) == ICMPV6_HDR_FIELD) | 		if ((*code) == ICMPV6_HDR_FIELD) | ||||||
| 			teli = parse_tlv_tnl_enc_lim(skb, skb->data); | 			teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); | ||||||
| 
 | 
 | ||||||
| 		if (teli && teli == *info - 2) { | 		if (teli && teli == *info - 2) { | ||||||
| 			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | 			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | ||||||
|  | @ -693,11 +696,11 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | ||||||
| 		IP6_ECN_set_ce(ipv6_hdr(skb)); | 		IP6_ECN_set_ce(ipv6_hdr(skb)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | ||||||
| 			     const struct in6_addr *laddr, | 			     const struct in6_addr *laddr, | ||||||
| 			     const struct in6_addr *raddr) | 			     const struct in6_addr *raddr) | ||||||
| { | { | ||||||
| 	struct ip6_tnl_parm *p = &t->parms; | 	struct __ip6_tnl_parm *p = &t->parms; | ||||||
| 	int ltype = ipv6_addr_type(laddr); | 	int ltype = ipv6_addr_type(laddr); | ||||||
| 	int rtype = ipv6_addr_type(raddr); | 	int rtype = ipv6_addr_type(raddr); | ||||||
| 	__u32 flags = 0; | 	__u32 flags = 0; | ||||||
|  | @ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | ||||||
| 	} | 	} | ||||||
| 	return flags; | 	return flags; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL(ip6_tnl_get_cap); | ||||||
| 
 | 
 | ||||||
| /* called with rcu_read_lock() */ | /* called with rcu_read_lock() */ | ||||||
| static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | ||||||
| 				  const struct in6_addr *laddr, | 				  const struct in6_addr *laddr, | ||||||
| 				  const struct in6_addr *raddr) | 				  const struct in6_addr *raddr) | ||||||
| { | { | ||||||
| 	struct ip6_tnl_parm *p = &t->parms; | 	struct __ip6_tnl_parm *p = &t->parms; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	struct net *net = dev_net(t->dev); | 	struct net *net = dev_net(t->dev); | ||||||
| 
 | 
 | ||||||
|  | @ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | ||||||
| 	} | 	} | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally |  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally | ||||||
|  | @ -859,9 +864,9 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) | ||||||
| 	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | 	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | ||||||
| { | { | ||||||
| 	struct ip6_tnl_parm *p = &t->parms; | 	struct __ip6_tnl_parm *p = &t->parms; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	struct net *net = dev_net(t->dev); | 	struct net *net = dev_net(t->dev); | ||||||
| 
 | 
 | ||||||
|  | @ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | ||||||
| 	} | 	} | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ip6_tnl_xmit2 - encapsulate packet and send |  * ip6_tnl_xmit2 - encapsulate packet and send | ||||||
|  *   @skb: the outgoing socket buffer |  *   @skb: the outgoing socket buffer | ||||||
|  | @ -1085,7 +1092,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | ||||||
| 	    !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) | 	    !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb)); | 	offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb)); | ||||||
| 	if (offset > 0) { | 	if (offset > 0) { | ||||||
| 		struct ipv6_tlv_tnl_enc_lim *tel; | 		struct ipv6_tlv_tnl_enc_lim *tel; | ||||||
| 		tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 		tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | ||||||
|  | @ -1152,7 +1159,7 @@ tx_err: | ||||||
| static void ip6_tnl_link_config(struct ip6_tnl *t) | static void ip6_tnl_link_config(struct ip6_tnl *t) | ||||||
| { | { | ||||||
| 	struct net_device *dev = t->dev; | 	struct net_device *dev = t->dev; | ||||||
| 	struct ip6_tnl_parm *p = &t->parms; | 	struct __ip6_tnl_parm *p = &t->parms; | ||||||
| 	struct flowi6 *fl6 = &t->fl.u.ip6; | 	struct flowi6 *fl6 = &t->fl.u.ip6; | ||||||
| 
 | 
 | ||||||
| 	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | 	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | ||||||
|  | @ -1215,7 +1222,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | ||||||
|  **/ |  **/ | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) | ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) | ||||||
| { | { | ||||||
| 	t->parms.laddr = p->laddr; | 	t->parms.laddr = p->laddr; | ||||||
| 	t->parms.raddr = p->raddr; | 	t->parms.raddr = p->raddr; | ||||||
|  | @ -1230,6 +1237,34 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) | ||||||
|  | { | ||||||
|  | 	p->laddr = u->laddr; | ||||||
|  | 	p->raddr = u->raddr; | ||||||
|  | 	p->flags = u->flags; | ||||||
|  | 	p->hop_limit = u->hop_limit; | ||||||
|  | 	p->encap_limit = u->encap_limit; | ||||||
|  | 	p->flowinfo = u->flowinfo; | ||||||
|  | 	p->link = u->link; | ||||||
|  | 	p->proto = u->proto; | ||||||
|  | 	memcpy(p->name, u->name, sizeof(u->name)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p) | ||||||
|  | { | ||||||
|  | 	u->laddr = p->laddr; | ||||||
|  | 	u->raddr = p->raddr; | ||||||
|  | 	u->flags = p->flags; | ||||||
|  | 	u->hop_limit = p->hop_limit; | ||||||
|  | 	u->encap_limit = p->encap_limit; | ||||||
|  | 	u->flowinfo = p->flowinfo; | ||||||
|  | 	u->link = p->link; | ||||||
|  | 	u->proto = p->proto; | ||||||
|  | 	memcpy(u->name, p->name, sizeof(u->name)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ip6_tnl_ioctl - configure ipv6 tunnels from userspace |  * ip6_tnl_ioctl - configure ipv6 tunnels from userspace | ||||||
|  *   @dev: virtual device associated with tunnel |  *   @dev: virtual device associated with tunnel | ||||||
|  | @ -1263,6 +1298,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| { | { | ||||||
| 	int err = 0; | 	int err = 0; | ||||||
| 	struct ip6_tnl_parm p; | 	struct ip6_tnl_parm p; | ||||||
|  | 	struct __ip6_tnl_parm p1; | ||||||
| 	struct ip6_tnl *t = NULL; | 	struct ip6_tnl *t = NULL; | ||||||
| 	struct net *net = dev_net(dev); | 	struct net *net = dev_net(dev); | ||||||
| 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||||||
|  | @ -1274,11 +1310,12 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| 				err = -EFAULT; | 				err = -EFAULT; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			t = ip6_tnl_locate(net, &p, 0); | 			ip6_tnl_parm_from_user(&p1, &p); | ||||||
|  | 			t = ip6_tnl_locate(net, &p1, 0); | ||||||
| 		} | 		} | ||||||
| 		if (t == NULL) | 		if (t == NULL) | ||||||
| 			t = netdev_priv(dev); | 			t = netdev_priv(dev); | ||||||
| 		memcpy(&p, &t->parms, sizeof (p)); | 		ip6_tnl_parm_to_user(&p, &t->parms); | ||||||
| 		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { | 		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { | ||||||
| 			err = -EFAULT; | 			err = -EFAULT; | ||||||
| 		} | 		} | ||||||
|  | @ -1295,7 +1332,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| 		if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && | 		if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && | ||||||
| 		    p.proto != 0) | 		    p.proto != 0) | ||||||
| 			break; | 			break; | ||||||
| 		t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL); | 		ip6_tnl_parm_from_user(&p1, &p); | ||||||
|  | 		t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL); | ||||||
| 		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { | 		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { | ||||||
| 			if (t != NULL) { | 			if (t != NULL) { | ||||||
| 				if (t->dev != dev) { | 				if (t->dev != dev) { | ||||||
|  | @ -1307,13 +1345,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| 
 | 
 | ||||||
| 			ip6_tnl_unlink(ip6n, t); | 			ip6_tnl_unlink(ip6n, t); | ||||||
| 			synchronize_net(); | 			synchronize_net(); | ||||||
| 			err = ip6_tnl_change(t, &p); | 			err = ip6_tnl_change(t, &p1); | ||||||
| 			ip6_tnl_link(ip6n, t); | 			ip6_tnl_link(ip6n, t); | ||||||
| 			netdev_state_change(dev); | 			netdev_state_change(dev); | ||||||
| 		} | 		} | ||||||
| 		if (t) { | 		if (t) { | ||||||
| 			err = 0; | 			err = 0; | ||||||
| 			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p))) | 			ip6_tnl_parm_to_user(&p, &t->parms); | ||||||
|  | 			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||||||
| 				err = -EFAULT; | 				err = -EFAULT; | ||||||
| 
 | 
 | ||||||
| 		} else | 		} else | ||||||
|  | @ -1329,7 +1368,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | ||||||
| 				break; | 				break; | ||||||
| 			err = -ENOENT; | 			err = -ENOENT; | ||||||
| 			if ((t = ip6_tnl_locate(net, &p, 0)) == NULL) | 			ip6_tnl_parm_from_user(&p1, &p); | ||||||
|  | 			t = ip6_tnl_locate(net, &p1, 0); | ||||||
|  | 			if (t == NULL) | ||||||
| 				break; | 				break; | ||||||
| 			err = -EPERM; | 			err = -EPERM; | ||||||
| 			if (t->dev == ip6n->fb_tnl_dev) | 			if (t->dev == ip6n->fb_tnl_dev) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 xeb@mail.ru
				xeb@mail.ru