aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/dst.h1
-rw-r--r--net/ipv6/ip6_output.c68
-rw-r--r--net/xfrm/xfrm_policy.c3
3 files changed, 54 insertions, 18 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index bed833d9796a..8197eadca819 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -60,6 +60,7 @@ struct dst_entry {
60#define DST_NOCOUNT 0x0020 60#define DST_NOCOUNT 0x0020
61#define DST_NOPEER 0x0040 61#define DST_NOPEER 0x0040
62#define DST_FAKE_RTABLE 0x0080 62#define DST_FAKE_RTABLE 0x0080
63#define DST_XFRM_TUNNEL 0x0100
63 64
64 short error; 65 short error;
65 short obsolete; 66 short obsolete;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d99fdc699625..17b8c67998bb 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1187,6 +1187,29 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
1187 return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; 1187 return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
1188} 1188}
1189 1189
1190static void ip6_append_data_mtu(int *mtu,
1191 int *maxfraglen,
1192 unsigned int fragheaderlen,
1193 struct sk_buff *skb,
1194 struct rt6_info *rt)
1195{
1196 if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
1197 if (skb == NULL) {
1198 /* first fragment, reserve header_len */
1199 *mtu = *mtu - rt->dst.header_len;
1200
1201 } else {
1202 /*
1203 * this fragment is not first, the headers
1204 * space is regarded as data space.
1205 */
1206 *mtu = dst_mtu(rt->dst.path);
1207 }
1208 *maxfraglen = ((*mtu - fragheaderlen) & ~7)
1209 + fragheaderlen - sizeof(struct frag_hdr);
1210 }
1211}
1212
1190int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, 1213int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1191 int offset, int len, int odd, struct sk_buff *skb), 1214 int offset, int len, int odd, struct sk_buff *skb),
1192 void *from, int length, int transhdrlen, 1215 void *from, int length, int transhdrlen,
@@ -1196,7 +1219,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1196 struct inet_sock *inet = inet_sk(sk); 1219 struct inet_sock *inet = inet_sk(sk);
1197 struct ipv6_pinfo *np = inet6_sk(sk); 1220 struct ipv6_pinfo *np = inet6_sk(sk);
1198 struct inet_cork *cork; 1221 struct inet_cork *cork;
1199 struct sk_buff *skb; 1222 struct sk_buff *skb, *skb_prev = NULL;
1200 unsigned int maxfraglen, fragheaderlen; 1223 unsigned int maxfraglen, fragheaderlen;
1201 int exthdrlen; 1224 int exthdrlen;
1202 int dst_exthdrlen; 1225 int dst_exthdrlen;
@@ -1253,8 +1276,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1253 inet->cork.fl.u.ip6 = *fl6; 1276 inet->cork.fl.u.ip6 = *fl6;
1254 np->cork.hop_limit = hlimit; 1277 np->cork.hop_limit = hlimit;
1255 np->cork.tclass = tclass; 1278 np->cork.tclass = tclass;
1256 mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? 1279 if (rt->dst.flags & DST_XFRM_TUNNEL)
1257 rt->dst.dev->mtu : dst_mtu(&rt->dst); 1280 mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
1281 rt->dst.dev->mtu : dst_mtu(&rt->dst);
1282 else
1283 mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
1284 rt->dst.dev->mtu : dst_mtu(rt->dst.path);
1258 if (np->frag_size < mtu) { 1285 if (np->frag_size < mtu) {
1259 if (np->frag_size) 1286 if (np->frag_size)
1260 mtu = np->frag_size; 1287 mtu = np->frag_size;
@@ -1350,25 +1377,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1350 unsigned int fraglen; 1377 unsigned int fraglen;
1351 unsigned int fraggap; 1378 unsigned int fraggap;
1352 unsigned int alloclen; 1379 unsigned int alloclen;
1353 struct sk_buff *skb_prev;
1354alloc_new_skb: 1380alloc_new_skb:
1355 skb_prev = skb;
1356
1357 /* There's no room in the current skb */ 1381 /* There's no room in the current skb */
1358 if (skb_prev) 1382 if (skb)
1359 fraggap = skb_prev->len - maxfraglen; 1383 fraggap = skb->len - maxfraglen;
1360 else 1384 else
1361 fraggap = 0; 1385 fraggap = 0;
1386 /* update mtu and maxfraglen if necessary */
1387 if (skb == NULL || skb_prev == NULL)
1388 ip6_append_data_mtu(&mtu, &maxfraglen,
1389 fragheaderlen, skb, rt);
1390
1391 skb_prev = skb;
1362 1392
1363 /* 1393 /*
1364 * If remaining data exceeds the mtu, 1394 * If remaining data exceeds the mtu,
1365 * we know we need more fragment(s). 1395 * we know we need more fragment(s).
1366 */ 1396 */
1367 datalen = length + fraggap; 1397 datalen = length + fraggap;
1368 if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
1369 datalen = maxfraglen - fragheaderlen;
1370 1398
1371 fraglen = datalen + fragheaderlen; 1399 if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
1400 datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
1372 if ((flags & MSG_MORE) && 1401 if ((flags & MSG_MORE) &&
1373 !(rt->dst.dev->features&NETIF_F_SG)) 1402 !(rt->dst.dev->features&NETIF_F_SG))
1374 alloclen = mtu; 1403 alloclen = mtu;
@@ -1377,13 +1406,16 @@ alloc_new_skb:
1377 1406
1378 alloclen += dst_exthdrlen; 1407 alloclen += dst_exthdrlen;
1379 1408
1380 /* 1409 if (datalen != length + fraggap) {
1381 * The last fragment gets additional space at tail. 1410 /*
1382 * Note: we overallocate on fragments with MSG_MODE 1411 * this is not the last fragment, the trailer
1383 * because we have no idea if we're the last one. 1412 * space is regarded as data space.
1384 */ 1413 */
1385 if (datalen == length + fraggap) 1414 datalen += rt->dst.trailer_len;
1386 alloclen += rt->dst.trailer_len; 1415 }
1416
1417 alloclen += rt->dst.trailer_len;
1418 fraglen = datalen + fragheaderlen;
1387 1419
1388 /* 1420 /*
1389 * We just reserve space for fragment header. 1421 * We just reserve space for fragment header.
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index c53e8f42aa75..ccfbd328a69d 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1921,6 +1921,9 @@ no_transform:
1921 } 1921 }
1922ok: 1922ok:
1923 xfrm_pols_put(pols, drop_pols); 1923 xfrm_pols_put(pols, drop_pols);
1924 if (dst && dst->xfrm &&
1925 dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
1926 dst->flags |= DST_XFRM_TUNNEL;
1924 return dst; 1927 return dst;
1925 1928
1926nopol: 1929nopol: