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_PIPE 821		/* PhoNet pipe header		*/ | ||||
| #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_NONE	  0xFFFE	/* zero header length */ | ||||
|  |  | |||
|  | @ -75,6 +75,9 @@ enum { | |||
| 	IFLA_GRE_TTL, | ||||
| 	IFLA_GRE_TOS, | ||||
| 	IFLA_GRE_PMTUDISC, | ||||
| 	IFLA_GRE_ENCAP_LIMIT, | ||||
| 	IFLA_GRE_FLOWINFO, | ||||
| 	IFLA_GRE_FLAGS, | ||||
| 	__IFLA_GRE_MAX, | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,4 +31,21 @@ struct ip6_tnl_parm { | |||
| 	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 | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| #include <linux/netdevice.h> | ||||
| #include <linux/ip6_tunnel.h> | ||||
| 
 | ||||
| #define IP6TUNNEL_ERR_TIMEO (30*HZ) | ||||
| 
 | ||||
| /* capable of sending packets */ | ||||
| #define IP6_TNL_F_CAP_XMIT 0x10000 | ||||
| /* capable of receiving packets */ | ||||
|  | @ -12,15 +14,40 @@ | |||
| /* determine capability on a per-packet basis */ | ||||
| #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 __rcu *next;	/* next tunnel in list */ | ||||
| 	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 dst_entry *dst_cache;    /* cached dst */ | ||||
| 	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 */ | ||||
|  | @ -31,4 +58,14 @@ struct ipv6_tlv_tnl_enc_lim { | |||
| 	__u8 encap_limit;	/* tunnel encapsulation limit   */ | ||||
| } __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 | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ | |||
| #define NEXTHDR_IPV6		41	/* IPv6 in IPv6 */ | ||||
| #define NEXTHDR_ROUTING		43	/* Routing header. */ | ||||
| #define NEXTHDR_FRAGMENT	44	/* Fragmentation/reassembly header. */ | ||||
| #define NEXTHDR_GRE		47	/* GRE header. */ | ||||
| #define NEXTHDR_ESP		50	/* Encapsulating security payload. */ | ||||
| #define NEXTHDR_AUTH		51	/* Authentication header. */ | ||||
| #define NEXTHDR_ICMP		58	/* ICMP for IPv6. */ | ||||
|  |  | |||
|  | @ -201,6 +201,22 @@ config IPV6_TUNNEL | |||
| 
 | ||||
| 	  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 | ||||
| 	bool "IPv6: Multiple Routing Tables" | ||||
| 	depends on EXPERIMENTAL | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER)	+= netfilter/ | |||
| 
 | ||||
| obj-$(CONFIG_IPV6_SIT) += sit.o | ||||
| obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | ||||
| obj-$(CONFIG_IPV6_GRE) += ip6_gre.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 | ||||
|  */ | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  | @ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | |||
| 
 | ||||
| 	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); | ||||
| 	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; | ||||
| 	t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | ||||
| 	dst_release(t->dst_cache); | ||||
| 	t->dst_cache = dst; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); | ||||
| 
 | ||||
| /**
 | ||||
|  * 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 ** | ||||
| 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 *local = &p->laddr; | ||||
|  | @ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev) | |||
|  *   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 ip6_tnl *t; | ||||
|  | @ -322,7 +325,7 @@ failed: | |||
|  **/ | ||||
| 
 | ||||
| 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 *local = &p->laddr; | ||||
|  | @ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
|  *   else index to encapsulation limit | ||||
|  **/ | ||||
| 
 | ||||
| static __u16 | ||||
| parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | ||||
| __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) | ||||
| { | ||||
| 	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; | ||||
| 	__u8 nexthdr = ipv6h->nexthdr; | ||||
|  | @ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | |||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim); | ||||
| 
 | ||||
| /**
 | ||||
|  * 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: | ||||
| 		teli = 0; | ||||
| 		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) { | ||||
| 			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)); | ||||
| } | ||||
| 
 | ||||
| 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 *raddr) | ||||
| { | ||||
| 	struct ip6_tnl_parm *p = &t->parms; | ||||
| 	struct __ip6_tnl_parm *p = &t->parms; | ||||
| 	int ltype = ipv6_addr_type(laddr); | ||||
| 	int rtype = ipv6_addr_type(raddr); | ||||
| 	__u32 flags = 0; | ||||
|  | @ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | |||
| 	} | ||||
| 	return flags; | ||||
| } | ||||
| EXPORT_SYMBOL(ip6_tnl_get_cap); | ||||
| 
 | ||||
| /* 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 *raddr) | ||||
| { | ||||
| 	struct ip6_tnl_parm *p = &t->parms; | ||||
| 	struct __ip6_tnl_parm *p = &t->parms; | ||||
| 	int ret = 0; | ||||
| 	struct net *net = dev_net(t->dev); | ||||
| 
 | ||||
|  | @ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | |||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); | ||||
| 
 | ||||
| /**
 | ||||
|  * 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); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	struct net *net = dev_net(t->dev); | ||||
| 
 | ||||
|  | @ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl); | ||||
| 
 | ||||
| /**
 | ||||
|  * ip6_tnl_xmit2 - encapsulate packet and send | ||||
|  *   @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)) | ||||
| 		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) { | ||||
| 		struct ipv6_tlv_tnl_enc_lim *tel; | ||||
| 		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) | ||||
| { | ||||
| 	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; | ||||
| 
 | ||||
| 	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 | ||||
| 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.raddr = p->raddr; | ||||
|  | @ -1230,6 +1237,34 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) | |||
| 	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 | ||||
|  *   @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; | ||||
| 	struct ip6_tnl_parm p; | ||||
| 	struct __ip6_tnl_parm p1; | ||||
| 	struct ip6_tnl *t = NULL; | ||||
| 	struct net *net = dev_net(dev); | ||||
| 	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; | ||||
| 				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) | ||||
| 			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))) { | ||||
| 			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 && | ||||
| 		    p.proto != 0) | ||||
| 			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 (t != NULL) { | ||||
| 				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); | ||||
| 			synchronize_net(); | ||||
| 			err = ip6_tnl_change(t, &p); | ||||
| 			err = ip6_tnl_change(t, &p1); | ||||
| 			ip6_tnl_link(ip6n, t); | ||||
| 			netdev_state_change(dev); | ||||
| 		} | ||||
| 		if (t) { | ||||
| 			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; | ||||
| 
 | ||||
| 		} 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))) | ||||
| 				break; | ||||
| 			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; | ||||
| 			err = -EPERM; | ||||
| 			if (t->dev == ip6n->fb_tnl_dev) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 xeb@mail.ru
				xeb@mail.ru