Blame view
net/ipv4/ip_options.c
14.8 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 |
/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * The options processing module for ip.c * |
1da177e4c Linux-2.6.12-rc2 |
9 |
* Authors: A.N.Kuznetsov |
e905a9eda [NET] IPV4: Fix w... |
10 |
* |
1da177e4c Linux-2.6.12-rc2 |
11 |
*/ |
afd465030 net: ipv4: Standa... |
12 |
#define pr_fmt(fmt) "IPv4: " fmt |
4fc268d24 [PATCH] capable/c... |
13 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
15 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
16 |
#include <linux/types.h> |
7c0f6ba68 Replace <asm/uacc... |
17 |
#include <linux/uaccess.h> |
48bdf072c ip_options_compil... |
18 |
#include <asm/unaligned.h> |
1da177e4c Linux-2.6.12-rc2 |
19 20 21 22 23 24 25 26 |
#include <linux/skbuff.h> #include <linux/ip.h> #include <linux/icmp.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> #include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> |
14c850212 [INET_SOCK]: Move... |
27 |
#include <net/route.h> |
11a03f78f [NetLabel]: core ... |
28 |
#include <net/cipso_ipv4.h> |
35ebf65e8 ipv4: Create and ... |
29 |
#include <net/ip_fib.h> |
1da177e4c Linux-2.6.12-rc2 |
30 |
|
e905a9eda [NET] IPV4: Fix w... |
31 |
/* |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 35 36 37 38 39 40 |
* Write options to IP header, record destination address to * source route option, address of outgoing interface * (we should already know it, so that this function is allowed be * called only after routing decision) and timestamp, * if we originate this datagram. * * daddr is real destination address, next hop is recorded in IP header. * saddr is address of outgoing interface. */ |
f6d8bd051 inet: add RCU pro... |
41 |
void ip_options_build(struct sk_buff *skb, struct ip_options *opt, |
8e36360ae ipv4: Remove rout... |
42 |
__be32 daddr, struct rtable *rt, int is_frag) |
1da177e4c Linux-2.6.12-rc2 |
43 |
{ |
d56f90a7c [SK_BUFF]: Introd... |
44 |
unsigned char *iph = skb_network_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
45 46 |
memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); |
343d8c601 net: clean up cod... |
47 |
memcpy(iph + sizeof(struct iphdr), opt->__data, opt->optlen); |
1da177e4c Linux-2.6.12-rc2 |
48 |
opt = &(IPCB(skb)->opt); |
1da177e4c Linux-2.6.12-rc2 |
49 50 |
if (opt->srr) |
343d8c601 net: clean up cod... |
51 |
memcpy(iph + opt->srr + iph[opt->srr + 1] - 4, &daddr, 4); |
1da177e4c Linux-2.6.12-rc2 |
52 53 54 |
if (!is_frag) { if (opt->rr_needaddr) |
343d8c601 net: clean up cod... |
55 |
ip_rt_get_source(iph + opt->rr + iph[opt->rr + 2] - 5, skb, rt); |
1da177e4c Linux-2.6.12-rc2 |
56 |
if (opt->ts_needaddr) |
343d8c601 net: clean up cod... |
57 |
ip_rt_get_source(iph + opt->ts + iph[opt->ts + 2] - 9, skb, rt); |
1da177e4c Linux-2.6.12-rc2 |
58 |
if (opt->ts_needtime) { |
e25d2ca6b [IPV4]: trivial i... |
59 |
__be32 midtime; |
822c86853 net: ipv4: Conver... |
60 61 |
midtime = inet_current_timestamp(); |
343d8c601 net: clean up cod... |
62 |
memcpy(iph + opt->ts + iph[opt->ts + 2] - 5, &midtime, 4); |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 |
} return; } if (opt->rr) { |
343d8c601 net: clean up cod... |
67 |
memset(iph + opt->rr, IPOPT_NOP, iph[opt->rr + 1]); |
1da177e4c Linux-2.6.12-rc2 |
68 69 70 71 |
opt->rr = 0; opt->rr_needaddr = 0; } if (opt->ts) { |
343d8c601 net: clean up cod... |
72 |
memset(iph + opt->ts, IPOPT_NOP, iph[opt->ts + 1]); |
1da177e4c Linux-2.6.12-rc2 |
73 74 75 76 |
opt->ts = 0; opt->ts_needaddr = opt->ts_needtime = 0; } } |
e905a9eda [NET] IPV4: Fix w... |
77 |
/* |
1da177e4c Linux-2.6.12-rc2 |
78 79 80 81 82 83 84 |
* Provided (sopt, skb) points to received options, * build in dopt compiled option set appropriate for answering. * i.e. invert SRR option, copy anothers, * and grab room in RR/TS options. * * NOTE: dopt cannot point to skb. */ |
91ed1e666 ip/options: expli... |
85 86 |
int __ip_options_echo(struct net *net, struct ip_options *dopt, struct sk_buff *skb, const struct ip_options *sopt) |
1da177e4c Linux-2.6.12-rc2 |
87 |
{ |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 |
unsigned char *sptr, *dptr; int soffset, doffset; int optlen; |
1da177e4c Linux-2.6.12-rc2 |
91 92 |
memset(dopt, 0, sizeof(struct ip_options)); |
f6d8bd051 inet: add RCU pro... |
93 |
if (sopt->optlen == 0) |
1da177e4c Linux-2.6.12-rc2 |
94 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
95 |
|
d56f90a7c [SK_BUFF]: Introd... |
96 |
sptr = skb_network_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
97 |
dptr = dopt->__data; |
1da177e4c Linux-2.6.12-rc2 |
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
if (sopt->rr) { optlen = sptr[sopt->rr+1]; soffset = sptr[sopt->rr+2]; dopt->rr = dopt->optlen + sizeof(struct iphdr); memcpy(dptr, sptr+sopt->rr, optlen); if (sopt->rr_needaddr && soffset <= optlen) { if (soffset + 3 > optlen) return -EINVAL; dptr[2] = soffset + 4; dopt->rr_needaddr = 1; } dptr += optlen; dopt->optlen += optlen; } if (sopt->ts) { optlen = sptr[sopt->ts+1]; soffset = sptr[sopt->ts+2]; dopt->ts = dopt->optlen + sizeof(struct iphdr); memcpy(dptr, sptr+sopt->ts, optlen); if (soffset <= optlen) { if (sopt->ts_needaddr) { if (soffset + 3 > optlen) return -EINVAL; dopt->ts_needaddr = 1; soffset += 4; } if (sopt->ts_needtime) { if (soffset + 3 > optlen) return -EINVAL; if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) { dopt->ts_needtime = 1; soffset += 4; } else { dopt->ts_needtime = 0; |
8628bd8af ipv4: Fix IP time... |
132 |
if (soffset + 7 <= optlen) { |
fd6832220 [IPV4]: inet_addr... |
133 |
__be32 addr; |
1da177e4c Linux-2.6.12-rc2 |
134 |
|
8628bd8af ipv4: Fix IP time... |
135 |
memcpy(&addr, dptr+soffset-1, 4); |
91ed1e666 ip/options: expli... |
136 |
if (inet_addr_type(net, addr) != RTN_UNICAST) { |
1da177e4c Linux-2.6.12-rc2 |
137 138 139 140 141 142 143 144 145 146 147 148 |
dopt->ts_needtime = 1; soffset += 8; } } } } dptr[2] = soffset; } dptr += optlen; dopt->optlen += optlen; } if (sopt->srr) { |
f6d8bd051 inet: add RCU pro... |
149 |
unsigned char *start = sptr+sopt->srr; |
3ca3c68e7 [IPV4]: struct ip... |
150 |
__be32 faddr; |
1da177e4c Linux-2.6.12-rc2 |
151 152 153 154 155 156 157 158 159 |
optlen = start[1]; soffset = start[2]; doffset = 0; if (soffset > optlen) soffset = optlen + 1; soffset -= 4; if (soffset > 3) { memcpy(&faddr, &start[soffset-1], 4); |
a22318e83 ipv4: do clean up... |
160 |
for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4) |
1da177e4c Linux-2.6.12-rc2 |
161 162 163 164 |
memcpy(&dptr[doffset-1], &start[soffset-1], 4); /* * RFC1812 requires to fix illegal source routes. */ |
eddc9ec53 [SK_BUFF]: Introd... |
165 166 |
if (memcmp(&ip_hdr(skb)->saddr, &start[soffset + 3], 4) == 0) |
1da177e4c Linux-2.6.12-rc2 |
167 168 169 |
doffset -= 4; } if (doffset > 3) { |
1da177e4c Linux-2.6.12-rc2 |
170 171 172 173 174 175 176 177 178 179 |
dopt->faddr = faddr; dptr[0] = start[0]; dptr[1] = doffset+3; dptr[2] = 4; dptr += doffset+3; dopt->srr = dopt->optlen + sizeof(struct iphdr); dopt->optlen += doffset+3; dopt->is_strictroute = sopt->is_strictroute; } } |
11a03f78f [NetLabel]: core ... |
180 181 182 183 184 185 186 |
if (sopt->cipso) { optlen = sptr[sopt->cipso+1]; dopt->cipso = dopt->optlen+sizeof(struct iphdr); memcpy(dptr, sptr+sopt->cipso, optlen); dptr += optlen; dopt->optlen += optlen; } |
1da177e4c Linux-2.6.12-rc2 |
187 188 189 190 191 192 193 194 195 196 197 198 |
while (dopt->optlen & 3) { *dptr++ = IPOPT_END; dopt->optlen++; } return 0; } /* * Options "fragmenting", just fill options not * allowed in fragments with NOOPs. * Simple and stupid 8), but the most efficient way. */ |
5e73ea1a3 ipv4: fix checkpa... |
199 |
void ip_options_fragment(struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
200 |
{ |
d56f90a7c [SK_BUFF]: Introd... |
201 |
unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr); |
5e73ea1a3 ipv4: fix checkpa... |
202 |
struct ip_options *opt = &(IPCB(skb)->opt); |
1da177e4c Linux-2.6.12-rc2 |
203 204 205 206 207 208 209 210 211 212 213 214 215 |
int l = opt->optlen; int optlen; while (l > 0) { switch (*optptr) { case IPOPT_END: return; case IPOPT_NOOP: l--; optptr++; continue; } optlen = optptr[1]; |
a22318e83 ipv4: do clean up... |
216 |
if (optlen < 2 || optlen > l) |
1da177e4c Linux-2.6.12-rc2 |
217 218 219 220 221 222 223 224 225 226 227 |
return; if (!IPOPT_COPIED(*optptr)) memset(optptr, IPOPT_NOOP, optlen); l -= optlen; optptr += optlen; } opt->ts = 0; opt->rr = 0; opt->rr_needaddr = 0; opt->ts_needaddr = 0; opt->ts_needtime = 0; |
1da177e4c Linux-2.6.12-rc2 |
228 |
} |
bf5e53e37 ipv4: defer fib_c... |
229 230 231 232 233 234 235 236 |
/* helper used by ip_options_compile() to call fib_compute_spec_dst() * at most one time. */ static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb) { if (*spec_dst == htonl(INADDR_ANY)) *spec_dst = fib_compute_spec_dst(skb); } |
1da177e4c Linux-2.6.12-rc2 |
237 238 239 240 241 |
/* * Verify options and fill pointers in struct options. * Caller should clear *opt, and set opt->data. * If opt == NULL, then skb->data should point to IP header. */ |
3da1ed7ac net: avoid use IP... |
242 243 244 |
int __ip_options_compile(struct net *net, struct ip_options *opt, struct sk_buff *skb, __be32 *info) |
1da177e4c Linux-2.6.12-rc2 |
245 |
{ |
bf5e53e37 ipv4: defer fib_c... |
246 |
__be32 spec_dst = htonl(INADDR_ANY); |
5e73ea1a3 ipv4: fix checkpa... |
247 |
unsigned char *pp_ptr = NULL; |
11604721a ipv4: Fix crashes... |
248 |
struct rtable *rt = NULL; |
35ebf65e8 ipv4: Create and ... |
249 250 251 |
unsigned char *optptr; unsigned char *iph; int optlen, l; |
1da177e4c Linux-2.6.12-rc2 |
252 |
|
00db41243 ipv4: coding styl... |
253 |
if (skb) { |
11604721a ipv4: Fix crashes... |
254 |
rt = skb_rtable(skb); |
22aba383c [IPV4]: Always pa... |
255 256 |
optptr = (unsigned char *)&(ip_hdr(skb)[1]); } else |
10fe7d85e [IPV4]: Remove un... |
257 |
optptr = opt->__data; |
22aba383c [IPV4]: Always pa... |
258 |
iph = optptr - sizeof(struct iphdr); |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 |
for (l = opt->optlen; l > 0; ) { switch (*optptr) { |
dd9b45598 ipv4: switch and ... |
262 |
case IPOPT_END: |
a22318e83 ipv4: do clean up... |
263 |
for (optptr++, l--; l > 0; optptr++, l--) { |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 269 |
if (*optptr != IPOPT_END) { *optptr = IPOPT_END; opt->is_changed = 1; } } goto eol; |
dd9b45598 ipv4: switch and ... |
270 |
case IPOPT_NOOP: |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 274 |
l--; optptr++; continue; } |
10ec9472f ipv4: fix buffer ... |
275 276 277 278 |
if (unlikely(l < 2)) { pp_ptr = optptr; goto error; } |
1da177e4c Linux-2.6.12-rc2 |
279 |
optlen = optptr[1]; |
a22318e83 ipv4: do clean up... |
280 |
if (optlen < 2 || optlen > l) { |
1da177e4c Linux-2.6.12-rc2 |
281 282 283 284 |
pp_ptr = optptr; goto error; } switch (*optptr) { |
dd9b45598 ipv4: switch and ... |
285 286 |
case IPOPT_SSRR: case IPOPT_LSRR: |
1da177e4c Linux-2.6.12-rc2 |
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
if (optlen < 3) { pp_ptr = optptr + 1; goto error; } if (optptr[2] < 4) { pp_ptr = optptr + 2; goto error; } /* NB: cf RFC-1812 5.2.4.1 */ if (opt->srr) { pp_ptr = optptr; goto error; } if (!skb) { if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) { pp_ptr = optptr + 1; goto error; } memcpy(&opt->faddr, &optptr[3], 4); if (optlen > 7) memmove(&optptr[3], &optptr[7], optlen-7); } opt->is_strictroute = (optptr[0] == IPOPT_SSRR); opt->srr = optptr - iph; break; |
dd9b45598 ipv4: switch and ... |
312 |
case IPOPT_RR: |
1da177e4c Linux-2.6.12-rc2 |
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
if (opt->rr) { pp_ptr = optptr; goto error; } if (optlen < 3) { pp_ptr = optptr + 1; goto error; } if (optptr[2] < 4) { pp_ptr = optptr + 2; goto error; } if (optptr[2] <= optlen) { if (optptr[2]+3 > optlen) { pp_ptr = optptr + 2; goto error; } |
11604721a ipv4: Fix crashes... |
330 |
if (rt) { |
bf5e53e37 ipv4: defer fib_c... |
331 |
spec_dst_fill(&spec_dst, skb); |
35ebf65e8 ipv4: Create and ... |
332 |
memcpy(&optptr[optptr[2]-1], &spec_dst, 4); |
1da177e4c Linux-2.6.12-rc2 |
333 334 335 336 337 338 339 |
opt->is_changed = 1; } optptr[2] += 4; opt->rr_needaddr = 1; } opt->rr = optptr - iph; break; |
dd9b45598 ipv4: switch and ... |
340 |
case IPOPT_TIMESTAMP: |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 344 345 346 347 348 349 350 351 352 353 |
if (opt->ts) { pp_ptr = optptr; goto error; } if (optlen < 4) { pp_ptr = optptr + 1; goto error; } if (optptr[2] < 5) { pp_ptr = optptr + 2; goto error; } if (optptr[2] <= optlen) { |
48bdf072c ip_options_compil... |
354 |
unsigned char *timeptr = NULL; |
5a2b646ff ipv4: Use predefi... |
355 |
if (optptr[2]+3 > optlen) { |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 |
pp_ptr = optptr + 2; goto error; } switch (optptr[3]&0xF) { |
dd9b45598 ipv4: switch and ... |
360 |
case IPOPT_TS_TSONLY: |
e905a9eda [NET] IPV4: Fix w... |
361 |
if (skb) |
48bdf072c ip_options_compil... |
362 |
timeptr = &optptr[optptr[2]-1]; |
1da177e4c Linux-2.6.12-rc2 |
363 364 365 |
opt->ts_needtime = 1; optptr[2] += 4; break; |
dd9b45598 ipv4: switch and ... |
366 |
case IPOPT_TS_TSANDADDR: |
5a2b646ff ipv4: Use predefi... |
367 |
if (optptr[2]+7 > optlen) { |
1da177e4c Linux-2.6.12-rc2 |
368 369 370 |
pp_ptr = optptr + 2; goto error; } |
11604721a ipv4: Fix crashes... |
371 |
if (rt) { |
bf5e53e37 ipv4: defer fib_c... |
372 |
spec_dst_fill(&spec_dst, skb); |
35ebf65e8 ipv4: Create and ... |
373 |
memcpy(&optptr[optptr[2]-1], &spec_dst, 4); |
48bdf072c ip_options_compil... |
374 |
timeptr = &optptr[optptr[2]+3]; |
1da177e4c Linux-2.6.12-rc2 |
375 376 377 378 379 |
} opt->ts_needaddr = 1; opt->ts_needtime = 1; optptr[2] += 8; break; |
dd9b45598 ipv4: switch and ... |
380 |
case IPOPT_TS_PRESPEC: |
5a2b646ff ipv4: Use predefi... |
381 |
if (optptr[2]+7 > optlen) { |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 |
pp_ptr = optptr + 2; goto error; } |
1da177e4c Linux-2.6.12-rc2 |
385 |
{ |
fd6832220 [IPV4]: inet_addr... |
386 |
__be32 addr; |
1da177e4c Linux-2.6.12-rc2 |
387 |
memcpy(&addr, &optptr[optptr[2]-1], 4); |
0e6bd4a1c [NETNS]: Add name... |
388 |
if (inet_addr_type(net, addr) == RTN_UNICAST) |
1da177e4c Linux-2.6.12-rc2 |
389 390 |
break; if (skb) |
48bdf072c ip_options_compil... |
391 |
timeptr = &optptr[optptr[2]+3]; |
1da177e4c Linux-2.6.12-rc2 |
392 393 394 395 |
} opt->ts_needtime = 1; optptr[2] += 8; break; |
dd9b45598 ipv4: switch and ... |
396 |
default: |
52e804c6d net: Allow userns... |
397 |
if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { |
1da177e4c Linux-2.6.12-rc2 |
398 399 400 401 402 403 |
pp_ptr = optptr + 3; goto error; } break; } if (timeptr) { |
822c86853 net: ipv4: Conver... |
404 405 406 407 |
__be32 midtime; midtime = inet_current_timestamp(); memcpy(timeptr, &midtime, 4); |
1da177e4c Linux-2.6.12-rc2 |
408 409 |
opt->is_changed = 1; } |
fa2b04f45 net/ipv4: Timesta... |
410 |
} else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) { |
95c961747 net: cleanup unsi... |
411 |
unsigned int overflow = optptr[3]>>4; |
1da177e4c Linux-2.6.12-rc2 |
412 413 414 415 |
if (overflow == 15) { pp_ptr = optptr + 3; goto error; } |
1da177e4c Linux-2.6.12-rc2 |
416 417 418 419 420 |
if (skb) { optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4); opt->is_changed = 1; } } |
4660c7f49 net/ipv4: Ensure ... |
421 |
opt->ts = optptr - iph; |
1da177e4c Linux-2.6.12-rc2 |
422 |
break; |
dd9b45598 ipv4: switch and ... |
423 |
case IPOPT_RA: |
1da177e4c Linux-2.6.12-rc2 |
424 425 426 427 428 429 430 |
if (optlen < 4) { pp_ptr = optptr + 1; goto error; } if (optptr[2] == 0 && optptr[3] == 0) opt->router_alert = optptr - iph; break; |
dd9b45598 ipv4: switch and ... |
431 |
case IPOPT_CIPSO: |
52e804c6d net: Allow userns... |
432 |
if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) { |
11a03f78f [NetLabel]: core ... |
433 434 435 436 |
pp_ptr = optptr; goto error; } opt->cipso = optptr - iph; |
15c45f7b2 cipso: Add suppor... |
437 |
if (cipso_v4_validate(skb, &optptr)) { |
11a03f78f [NetLabel]: core ... |
438 439 440 441 |
pp_ptr = optptr; goto error; } break; |
dd9b45598 ipv4: switch and ... |
442 443 444 |
case IPOPT_SEC: case IPOPT_SID: default: |
52e804c6d net: Allow userns... |
445 |
if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { |
1da177e4c Linux-2.6.12-rc2 |
446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
pp_ptr = optptr; goto error; } break; } l -= optlen; optptr += optlen; } eol: if (!pp_ptr) return 0; error: |
3da1ed7ac net: avoid use IP... |
460 461 |
if (info) *info = htonl((pp_ptr-iph)<<24); |
1da177e4c Linux-2.6.12-rc2 |
462 463 |
return -EINVAL; } |
dbb5281a1 netfilter: nf_tab... |
464 |
EXPORT_SYMBOL(__ip_options_compile); |
3da1ed7ac net: avoid use IP... |
465 466 467 468 469 470 471 472 473 474 475 476 |
int ip_options_compile(struct net *net, struct ip_options *opt, struct sk_buff *skb) { int ret; __be32 info; ret = __ip_options_compile(net, opt, skb, &info); if (ret != 0 && skb) icmp_send(skb, ICMP_PARAMETERPROB, 0, info); return ret; } |
462fb2af9 bridge : Sanitize... |
477 |
EXPORT_SYMBOL(ip_options_compile); |
1da177e4c Linux-2.6.12-rc2 |
478 479 480 481 |
/* * Undo all the changes done by ip_options_compile(). */ |
5e73ea1a3 ipv4: fix checkpa... |
482 |
void ip_options_undo(struct ip_options *opt) |
1da177e4c Linux-2.6.12-rc2 |
483 484 |
{ if (opt->srr) { |
343d8c601 net: clean up cod... |
485 486 487 488 |
unsigned char *optptr = opt->__data + opt->srr - sizeof(struct iphdr); memmove(optptr + 7, optptr + 3, optptr[1] - 7); memcpy(optptr + 3, &opt->faddr, 4); |
1da177e4c Linux-2.6.12-rc2 |
489 490 |
} if (opt->rr_needaddr) { |
343d8c601 net: clean up cod... |
491 |
unsigned char *optptr = opt->__data + opt->rr - sizeof(struct iphdr); |
1da177e4c Linux-2.6.12-rc2 |
492 |
optptr[2] -= 4; |
343d8c601 net: clean up cod... |
493 |
memset(&optptr[optptr[2] - 1], 0, 4); |
1da177e4c Linux-2.6.12-rc2 |
494 495 |
} if (opt->ts) { |
343d8c601 net: clean up cod... |
496 |
unsigned char *optptr = opt->__data + opt->ts - sizeof(struct iphdr); |
1da177e4c Linux-2.6.12-rc2 |
497 498 |
if (opt->ts_needtime) { optptr[2] -= 4; |
343d8c601 net: clean up cod... |
499 500 |
memset(&optptr[optptr[2] - 1], 0, 4); if ((optptr[3] & 0xF) == IPOPT_TS_PRESPEC) |
1da177e4c Linux-2.6.12-rc2 |
501 502 503 504 |
optptr[2] -= 4; } if (opt->ts_needaddr) { optptr[2] -= 4; |
343d8c601 net: clean up cod... |
505 |
memset(&optptr[optptr[2] - 1], 0, 4); |
1da177e4c Linux-2.6.12-rc2 |
506 507 508 |
} } } |
de40a3e88 net/ipv4: merge i... |
509 510 |
int ip_options_get(struct net *net, struct ip_options_rcu **optp, sockptr_t data, int optlen) |
1da177e4c Linux-2.6.12-rc2 |
511 |
{ |
de40a3e88 net/ipv4: merge i... |
512 513 514 |
struct ip_options_rcu *opt; opt = kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3), |
376407039 [IPV4] ip_options... |
515 |
GFP_KERNEL); |
de40a3e88 net/ipv4: merge i... |
516 517 518 519 520 521 |
if (!opt) return -ENOMEM; if (optlen && copy_from_sockptr(opt->opt.__data, data, optlen)) { kfree(opt); return -EFAULT; } |
1da177e4c Linux-2.6.12-rc2 |
522 |
|
1da177e4c Linux-2.6.12-rc2 |
523 |
while (optlen & 3) |
f6d8bd051 inet: add RCU pro... |
524 525 526 |
opt->opt.__data[optlen++] = IPOPT_END; opt->opt.optlen = optlen; if (optlen && ip_options_compile(net, &opt->opt, NULL)) { |
1da177e4c Linux-2.6.12-rc2 |
527 528 529 |
kfree(opt); return -EINVAL; } |
a51482bde [NET]: kfree cleanup |
530 |
kfree(*optp); |
1da177e4c Linux-2.6.12-rc2 |
531 532 533 534 535 536 |
*optp = opt; return 0; } void ip_forward_options(struct sk_buff *skb) { |
5e73ea1a3 ipv4: fix checkpa... |
537 538 |
struct ip_options *opt = &(IPCB(skb)->opt); unsigned char *optptr; |
511c3f92a net: skb->rtable ... |
539 |
struct rtable *rt = skb_rtable(skb); |
d56f90a7c [SK_BUFF]: Introd... |
540 |
unsigned char *raw = skb_network_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
541 542 543 |
if (opt->rr_needaddr) { optptr = (unsigned char *)raw + opt->rr; |
8e36360ae ipv4: Remove rout... |
544 |
ip_rt_get_source(&optptr[optptr[2]-5], skb, rt); |
1da177e4c Linux-2.6.12-rc2 |
545 546 547 548 549 550 |
opt->is_changed = 1; } if (opt->srr_is_hit) { int srrptr, srrspace; optptr = raw + opt->srr; |
a22318e83 ipv4: do clean up... |
551 |
for ( srrptr = optptr[2], srrspace = optptr[1]; |
1da177e4c Linux-2.6.12-rc2 |
552 553 554 555 556 |
srrptr <= srrspace; srrptr += 4 ) { if (srrptr + 3 > srrspace) break; |
ac8a48106 ipv4: Save nextho... |
557 |
if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0) |
1da177e4c Linux-2.6.12-rc2 |
558 559 560 561 |
break; } if (srrptr + 3 <= srrspace) { opt->is_changed = 1; |
ac8a48106 ipv4: Save nextho... |
562 |
ip_hdr(skb)->daddr = opt->nexthop; |
5dc7883f2 ipv4: Fix wrong o... |
563 |
ip_rt_get_source(&optptr[srrptr-1], skb, rt); |
1da177e4c Linux-2.6.12-rc2 |
564 |
optptr[2] = srrptr+4; |
e87cc4728 net: Convert net_... |
565 566 567 568 569 |
} else { net_crit_ratelimited("%s(): Argh! Destination lost! ", __func__); } |
1da177e4c Linux-2.6.12-rc2 |
570 571 |
if (opt->ts_needaddr) { optptr = raw + opt->ts; |
8e36360ae ipv4: Remove rout... |
572 |
ip_rt_get_source(&optptr[optptr[2]-9], skb, rt); |
1da177e4c Linux-2.6.12-rc2 |
573 574 575 576 577 |
opt->is_changed = 1; } } if (opt->is_changed) { opt->is_changed = 0; |
eddc9ec53 [SK_BUFF]: Introd... |
578 |
ip_send_check(ip_hdr(skb)); |
1da177e4c Linux-2.6.12-rc2 |
579 580 |
} } |
8c83f2df9 vrf: check accept... |
581 |
int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
582 583 584 |
{ struct ip_options *opt = &(IPCB(skb)->opt); int srrspace, srrptr; |
9e12bb22e [IPV4]: ip_route_... |
585 |
__be32 nexthop; |
eddc9ec53 [SK_BUFF]: Introd... |
586 |
struct iphdr *iph = ip_hdr(skb); |
d56f90a7c [SK_BUFF]: Introd... |
587 |
unsigned char *optptr = skb_network_header(skb) + opt->srr; |
511c3f92a net: skb->rtable ... |
588 |
struct rtable *rt = skb_rtable(skb); |
1da177e4c Linux-2.6.12-rc2 |
589 |
struct rtable *rt2; |
7fee226ad net: add a noref ... |
590 |
unsigned long orefdst; |
1da177e4c Linux-2.6.12-rc2 |
591 |
int err; |
10949550b ipv4: Kill spurio... |
592 |
if (!rt) |
1da177e4c Linux-2.6.12-rc2 |
593 594 595 596 597 598 599 600 601 602 603 604 |
return 0; if (skb->pkt_type != PACKET_HOST) return -EINVAL; if (rt->rt_type == RTN_UNICAST) { if (!opt->is_strictroute) return 0; icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24)); return -EINVAL; } if (rt->rt_type != RTN_LOCAL) return -EINVAL; |
a22318e83 ipv4: do clean up... |
605 |
for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) { |
1da177e4c Linux-2.6.12-rc2 |
606 607 608 609 610 |
if (srrptr + 3 > srrspace) { icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24)); return -EINVAL; } memcpy(&nexthop, &optptr[srrptr-1], 4); |
7fee226ad net: add a noref ... |
611 |
orefdst = skb->_skb_refdst; |
adf30907d net: skb->dst acc... |
612 |
skb_dst_set(skb, NULL); |
8c83f2df9 vrf: check accept... |
613 |
err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, dev); |
511c3f92a net: skb->rtable ... |
614 |
rt2 = skb_rtable(skb); |
1da177e4c Linux-2.6.12-rc2 |
615 |
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { |
7fee226ad net: add a noref ... |
616 617 |
skb_dst_drop(skb); skb->_skb_refdst = orefdst; |
1da177e4c Linux-2.6.12-rc2 |
618 619 |
return -EINVAL; } |
7fee226ad net: add a noref ... |
620 |
refdst_drop(orefdst); |
1da177e4c Linux-2.6.12-rc2 |
621 622 623 |
if (rt2->rt_type != RTN_LOCAL) break; /* Superfast 8) loopback forward */ |
c30883bdf ipv4: Simplify ip... |
624 |
iph->daddr = nexthop; |
1da177e4c Linux-2.6.12-rc2 |
625 626 627 628 |
opt->is_changed = 1; } if (srrptr <= srrspace) { opt->srr_is_hit = 1; |
ac8a48106 ipv4: Save nextho... |
629 |
opt->nexthop = nexthop; |
1da177e4c Linux-2.6.12-rc2 |
630 631 632 633 |
opt->is_changed = 1; } return 0; } |
462fb2af9 bridge : Sanitize... |
634 |
EXPORT_SYMBOL(ip_options_rcv_srr); |