aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_flowlabel.c8
-rw-r--r--net/ipv6/ip6_output.c67
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c25
4 files changed, 82 insertions, 20 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index c62dd247774f..7712578bdc66 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -323,17 +323,21 @@ static struct ip6_flowlabel *
323fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, 323fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
324 int optlen, int *err_p) 324 int optlen, int *err_p)
325{ 325{
326 struct ip6_flowlabel *fl; 326 struct ip6_flowlabel *fl = NULL;
327 int olen; 327 int olen;
328 int addr_type; 328 int addr_type;
329 int err; 329 int err;
330 330
331 olen = optlen - CMSG_ALIGN(sizeof(*freq));
332 err = -EINVAL;
333 if (olen > 64 * 1024)
334 goto done;
335
331 err = -ENOMEM; 336 err = -ENOMEM;
332 fl = kzalloc(sizeof(*fl), GFP_KERNEL); 337 fl = kzalloc(sizeof(*fl), GFP_KERNEL);
333 if (fl == NULL) 338 if (fl == NULL)
334 goto done; 339 goto done;
335 340
336 olen = optlen - CMSG_ALIGN(sizeof(*freq));
337 if (olen > 0) { 341 if (olen > 0) {
338 struct msghdr msg; 342 struct msghdr msg;
339 struct flowi flowi; 343 struct flowi flowi;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4b15938bef4d..9fb49c3b518a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1105,6 +1105,18 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1105 return err; 1105 return err;
1106} 1106}
1107 1107
1108static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
1109 gfp_t gfp)
1110{
1111 return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
1112}
1113
1114static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
1115 gfp_t gfp)
1116{
1117 return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
1118}
1119
1108int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, 1120int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1109 int offset, int len, int odd, struct sk_buff *skb), 1121 int offset, int len, int odd, struct sk_buff *skb),
1110 void *from, int length, int transhdrlen, 1122 void *from, int length, int transhdrlen,
@@ -1130,17 +1142,37 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1130 * setup for corking 1142 * setup for corking
1131 */ 1143 */
1132 if (opt) { 1144 if (opt) {
1133 if (np->cork.opt == NULL) { 1145 if (WARN_ON(np->cork.opt))
1134 np->cork.opt = kmalloc(opt->tot_len,
1135 sk->sk_allocation);
1136 if (unlikely(np->cork.opt == NULL))
1137 return -ENOBUFS;
1138 } else if (np->cork.opt->tot_len < opt->tot_len) {
1139 printk(KERN_DEBUG "ip6_append_data: invalid option length\n");
1140 return -EINVAL; 1146 return -EINVAL;
1141 } 1147
1142 memcpy(np->cork.opt, opt, opt->tot_len); 1148 np->cork.opt = kmalloc(opt->tot_len, sk->sk_allocation);
1143 inet->cork.flags |= IPCORK_OPT; 1149 if (unlikely(np->cork.opt == NULL))
1150 return -ENOBUFS;
1151
1152 np->cork.opt->tot_len = opt->tot_len;
1153 np->cork.opt->opt_flen = opt->opt_flen;
1154 np->cork.opt->opt_nflen = opt->opt_nflen;
1155
1156 np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
1157 sk->sk_allocation);
1158 if (opt->dst0opt && !np->cork.opt->dst0opt)
1159 return -ENOBUFS;
1160
1161 np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
1162 sk->sk_allocation);
1163 if (opt->dst1opt && !np->cork.opt->dst1opt)
1164 return -ENOBUFS;
1165
1166 np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
1167 sk->sk_allocation);
1168 if (opt->hopopt && !np->cork.opt->hopopt)
1169 return -ENOBUFS;
1170
1171 np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
1172 sk->sk_allocation);
1173 if (opt->srcrt && !np->cork.opt->srcrt)
1174 return -ENOBUFS;
1175
1144 /* need source address above miyazawa*/ 1176 /* need source address above miyazawa*/
1145 } 1177 }
1146 dst_hold(&rt->u.dst); 1178 dst_hold(&rt->u.dst);
@@ -1167,8 +1199,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1167 } else { 1199 } else {
1168 rt = (struct rt6_info *)inet->cork.dst; 1200 rt = (struct rt6_info *)inet->cork.dst;
1169 fl = &inet->cork.fl; 1201 fl = &inet->cork.fl;
1170 if (inet->cork.flags & IPCORK_OPT) 1202 opt = np->cork.opt;
1171 opt = np->cork.opt;
1172 transhdrlen = 0; 1203 transhdrlen = 0;
1173 exthdrlen = 0; 1204 exthdrlen = 0;
1174 mtu = inet->cork.fragsize; 1205 mtu = inet->cork.fragsize;
@@ -1407,9 +1438,15 @@ error:
1407 1438
1408static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) 1439static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
1409{ 1440{
1410 inet->cork.flags &= ~IPCORK_OPT; 1441 if (np->cork.opt) {
1411 kfree(np->cork.opt); 1442 kfree(np->cork.opt->dst0opt);
1412 np->cork.opt = NULL; 1443 kfree(np->cork.opt->dst1opt);
1444 kfree(np->cork.opt->hopopt);
1445 kfree(np->cork.opt->srcrt);
1446 kfree(np->cork.opt);
1447 np->cork.opt = NULL;
1448 }
1449
1413 if (inet->cork.dst) { 1450 if (inet->cork.dst) {
1414 dst_release(inet->cork.dst); 1451 dst_release(inet->cork.dst);
1415 inet->cork.dst = NULL; 1452 inet->cork.dst = NULL;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 58e2b0d93758..d994c55a5b16 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -249,8 +249,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
249 } 249 }
250 250
251 t = netdev_priv(dev); 251 t = netdev_priv(dev);
252 ip6_tnl_dev_init(dev);
253 t->parms = *p; 252 t->parms = *p;
253 ip6_tnl_dev_init(dev);
254 254
255 if ((err = register_netdevice(dev)) < 0) 255 if ((err = register_netdevice(dev)) < 0)
256 goto failed_free; 256 goto failed_free;
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index c455cf4ee756..c323643ffcf9 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -49,8 +49,19 @@ static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb,
49static const u_int8_t invmap[] = { 49static const u_int8_t invmap[] = {
50 [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, 50 [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1,
51 [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, 51 [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1,
52 [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, 52 [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_REPLY + 1,
53 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 53 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_QUERY +1
54};
55
56static const u_int8_t noct_valid_new[] = {
57 [ICMPV6_MGM_QUERY - 130] = 1,
58 [ICMPV6_MGM_REPORT -130] = 1,
59 [ICMPV6_MGM_REDUCTION - 130] = 1,
60 [NDISC_ROUTER_SOLICITATION - 130] = 1,
61 [NDISC_ROUTER_ADVERTISEMENT - 130] = 1,
62 [NDISC_NEIGHBOUR_SOLICITATION - 130] = 1,
63 [NDISC_NEIGHBOUR_ADVERTISEMENT - 130] = 1,
64 [ICMPV6_MLD2_REPORT - 130] = 1
54}; 65};
55 66
56static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, 67static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
@@ -178,6 +189,7 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
178{ 189{
179 const struct icmp6hdr *icmp6h; 190 const struct icmp6hdr *icmp6h;
180 struct icmp6hdr _ih; 191 struct icmp6hdr _ih;
192 int type;
181 193
182 icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); 194 icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
183 if (icmp6h == NULL) { 195 if (icmp6h == NULL) {
@@ -194,6 +206,15 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
194 return -NF_ACCEPT; 206 return -NF_ACCEPT;
195 } 207 }
196 208
209 type = icmp6h->icmp6_type - 130;
210 if (type >= 0 && type < sizeof(noct_valid_new) &&
211 noct_valid_new[type]) {
212 skb->nfct = &nf_conntrack_untracked.ct_general;
213 skb->nfctinfo = IP_CT_NEW;
214 nf_conntrack_get(skb->nfct);
215 return NF_ACCEPT;
216 }
217
197 /* is not error message ? */ 218 /* is not error message ? */
198 if (icmp6h->icmp6_type >= 128) 219 if (icmp6h->icmp6_type >= 128)
199 return NF_ACCEPT; 220 return NF_ACCEPT;