2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
6 * The options processing module for ip.c
8 * Authors: A.N.Kuznetsov
12 #include <linux/capability.h>
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include <linux/types.h>
16 #include <asm/uaccess.h>
17 #include <linux/skbuff.h>
19 #include <linux/icmp.h>
20 #include <linux/netdevice.h>
21 #include <linux/rtnetlink.h>
25 #include <net/route.h>
26 #include <net/cipso_ipv4.h>
29 * Write options to IP header, record destination address to
30 * source route option, address of outgoing interface
31 * (we should already know it, so that this function is allowed be
32 * called only after routing decision) and timestamp,
33 * if we originate this datagram.
35 * daddr is real destination address, next hop is recorded in IP header.
36 * saddr is address of outgoing interface.
39 void ip_options_build(struct sk_buff
*skb
, struct ip_options
*opt
,
40 __be32 daddr
, struct rtable
*rt
, int is_frag
)
42 unsigned char *iph
= skb_network_header(skb
);
44 memcpy(&(IPCB(skb
)->opt
), opt
, sizeof(struct ip_options
));
45 memcpy(iph
+sizeof(struct iphdr
), opt
->__data
, opt
->optlen
);
46 opt
= &(IPCB(skb
)->opt
);
49 memcpy(iph
+opt
->srr
+iph
[opt
->srr
+1]-4, &daddr
, 4);
53 ip_rt_get_source(iph
+opt
->rr
+iph
[opt
->rr
+2]-5, skb
, rt
);
55 ip_rt_get_source(iph
+opt
->ts
+iph
[opt
->ts
+2]-9, skb
, rt
);
56 if (opt
->ts_needtime
) {
60 midtime
= htonl((tv
.tv_sec
% 86400) * MSEC_PER_SEC
+ tv
.tv_nsec
/ NSEC_PER_MSEC
);
61 memcpy(iph
+opt
->ts
+iph
[opt
->ts
+2]-5, &midtime
, 4);
66 memset(iph
+opt
->rr
, IPOPT_NOP
, iph
[opt
->rr
+1]);
71 memset(iph
+opt
->ts
, IPOPT_NOP
, iph
[opt
->ts
+1]);
73 opt
->ts_needaddr
= opt
->ts_needtime
= 0;
78 * Provided (sopt, skb) points to received options,
79 * build in dopt compiled option set appropriate for answering.
80 * i.e. invert SRR option, copy anothers,
81 * and grab room in RR/TS options.
83 * NOTE: dopt cannot point to skb.
86 int ip_options_echo(struct ip_options
*dopt
, struct sk_buff
*skb
)
88 const struct ip_options
*sopt
;
89 unsigned char *sptr
, *dptr
;
94 memset(dopt
, 0, sizeof(struct ip_options
));
96 sopt
= &(IPCB(skb
)->opt
);
98 if (sopt
->optlen
== 0)
101 sptr
= skb_network_header(skb
);
104 daddr
= skb_rtable(skb
)->rt_spec_dst
;
107 optlen
= sptr
[sopt
->rr
+1];
108 soffset
= sptr
[sopt
->rr
+2];
109 dopt
->rr
= dopt
->optlen
+ sizeof(struct iphdr
);
110 memcpy(dptr
, sptr
+sopt
->rr
, optlen
);
111 if (sopt
->rr_needaddr
&& soffset
<= optlen
) {
112 if (soffset
+ 3 > optlen
)
114 dptr
[2] = soffset
+ 4;
115 dopt
->rr_needaddr
= 1;
118 dopt
->optlen
+= optlen
;
121 optlen
= sptr
[sopt
->ts
+1];
122 soffset
= sptr
[sopt
->ts
+2];
123 dopt
->ts
= dopt
->optlen
+ sizeof(struct iphdr
);
124 memcpy(dptr
, sptr
+sopt
->ts
, optlen
);
125 if (soffset
<= optlen
) {
126 if (sopt
->ts_needaddr
) {
127 if (soffset
+ 3 > optlen
)
129 dopt
->ts_needaddr
= 1;
132 if (sopt
->ts_needtime
) {
133 if (soffset
+ 3 > optlen
)
135 if ((dptr
[3]&0xF) != IPOPT_TS_PRESPEC
) {
136 dopt
->ts_needtime
= 1;
139 dopt
->ts_needtime
= 0;
141 if (soffset
+ 7 <= optlen
) {
144 memcpy(&addr
, dptr
+soffset
-1, 4);
145 if (inet_addr_type(dev_net(skb_dst(skb
)->dev
), addr
) != RTN_UNICAST
) {
146 dopt
->ts_needtime
= 1;
155 dopt
->optlen
+= optlen
;
158 unsigned char *start
= sptr
+sopt
->srr
;
164 if (soffset
> optlen
)
165 soffset
= optlen
+ 1;
168 memcpy(&faddr
, &start
[soffset
-1], 4);
169 for (soffset
-=4, doffset
=4; soffset
> 3; soffset
-=4, doffset
+=4)
170 memcpy(&dptr
[doffset
-1], &start
[soffset
-1], 4);
172 * RFC1812 requires to fix illegal source routes.
174 if (memcmp(&ip_hdr(skb
)->saddr
,
175 &start
[soffset
+ 3], 4) == 0)
179 memcpy(&start
[doffset
-1], &daddr
, 4);
185 dopt
->srr
= dopt
->optlen
+ sizeof(struct iphdr
);
186 dopt
->optlen
+= doffset
+3;
187 dopt
->is_strictroute
= sopt
->is_strictroute
;
191 optlen
= sptr
[sopt
->cipso
+1];
192 dopt
->cipso
= dopt
->optlen
+sizeof(struct iphdr
);
193 memcpy(dptr
, sptr
+sopt
->cipso
, optlen
);
195 dopt
->optlen
+= optlen
;
197 while (dopt
->optlen
& 3) {
205 * Options "fragmenting", just fill options not
206 * allowed in fragments with NOOPs.
207 * Simple and stupid 8), but the most efficient way.
210 void ip_options_fragment(struct sk_buff
* skb
)
212 unsigned char *optptr
= skb_network_header(skb
) + sizeof(struct iphdr
);
213 struct ip_options
* opt
= &(IPCB(skb
)->opt
);
227 if (optlen
<2 || optlen
>l
)
229 if (!IPOPT_COPIED(*optptr
))
230 memset(optptr
, IPOPT_NOOP
, optlen
);
236 opt
->rr_needaddr
= 0;
237 opt
->ts_needaddr
= 0;
238 opt
->ts_needtime
= 0;
242 * Verify options and fill pointers in struct options.
243 * Caller should clear *opt, and set opt->data.
244 * If opt == NULL, then skb->data should point to IP header.
247 int ip_options_compile(struct net
*net
,
248 struct ip_options
* opt
, struct sk_buff
* skb
)
252 unsigned char * optptr
;
254 unsigned char * pp_ptr
= NULL
;
255 struct rtable
*rt
= NULL
;
258 rt
= skb_rtable(skb
);
259 optptr
= (unsigned char *)&(ip_hdr(skb
)[1]);
261 optptr
= opt
->__data
;
262 iph
= optptr
- sizeof(struct iphdr
);
264 for (l
= opt
->optlen
; l
> 0; ) {
267 for (optptr
++, l
--; l
>0; optptr
++, l
--) {
268 if (*optptr
!= IPOPT_END
) {
280 if (optlen
<2 || optlen
>l
) {
295 /* NB: cf RFC-1812 5.2.4.1 */
301 if (optptr
[2] != 4 || optlen
< 7 || ((optlen
-3) & 3)) {
305 memcpy(&opt
->faddr
, &optptr
[3], 4);
307 memmove(&optptr
[3], &optptr
[7], optlen
-7);
309 opt
->is_strictroute
= (optptr
[0] == IPOPT_SSRR
);
310 opt
->srr
= optptr
- iph
;
325 if (optptr
[2] <= optlen
) {
326 if (optptr
[2]+3 > optlen
) {
331 memcpy(&optptr
[optptr
[2]-1], &rt
->rt_spec_dst
, 4);
335 opt
->rr_needaddr
= 1;
337 opt
->rr
= optptr
- iph
;
339 case IPOPT_TIMESTAMP
:
352 if (optptr
[2] <= optlen
) {
353 __be32
*timeptr
= NULL
;
354 if (optptr
[2]+3 > optptr
[1]) {
358 switch (optptr
[3]&0xF) {
359 case IPOPT_TS_TSONLY
:
360 opt
->ts
= optptr
- iph
;
362 timeptr
= (__be32
*)&optptr
[optptr
[2]-1];
363 opt
->ts_needtime
= 1;
366 case IPOPT_TS_TSANDADDR
:
367 if (optptr
[2]+7 > optptr
[1]) {
371 opt
->ts
= optptr
- iph
;
373 memcpy(&optptr
[optptr
[2]-1], &rt
->rt_spec_dst
, 4);
374 timeptr
= (__be32
*)&optptr
[optptr
[2]+3];
376 opt
->ts_needaddr
= 1;
377 opt
->ts_needtime
= 1;
380 case IPOPT_TS_PRESPEC
:
381 if (optptr
[2]+7 > optptr
[1]) {
385 opt
->ts
= optptr
- iph
;
388 memcpy(&addr
, &optptr
[optptr
[2]-1], 4);
389 if (inet_addr_type(net
, addr
) == RTN_UNICAST
)
392 timeptr
= (__be32
*)&optptr
[optptr
[2]+3];
394 opt
->ts_needtime
= 1;
398 if (!skb
&& !capable(CAP_NET_RAW
)) {
408 midtime
= htonl((tv
.tv_sec
% 86400) * MSEC_PER_SEC
+ tv
.tv_nsec
/ NSEC_PER_MSEC
);
409 memcpy(timeptr
, &midtime
, sizeof(__be32
));
413 unsigned overflow
= optptr
[3]>>4;
414 if (overflow
== 15) {
418 opt
->ts
= optptr
- iph
;
420 optptr
[3] = (optptr
[3]&0xF)|((overflow
+1)<<4);
430 if (optptr
[2] == 0 && optptr
[3] == 0)
431 opt
->router_alert
= optptr
- iph
;
434 if ((!skb
&& !capable(CAP_NET_RAW
)) || opt
->cipso
) {
438 opt
->cipso
= optptr
- iph
;
439 if (cipso_v4_validate(skb
, &optptr
)) {
447 if (!skb
&& !capable(CAP_NET_RAW
)) {
463 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, htonl((pp_ptr
-iph
)<<24));
467 EXPORT_SYMBOL(ip_options_compile
);
470 * Undo all the changes done by ip_options_compile().
473 void ip_options_undo(struct ip_options
* opt
)
476 unsigned char * optptr
= opt
->__data
+opt
->srr
-sizeof(struct iphdr
);
477 memmove(optptr
+7, optptr
+3, optptr
[1]-7);
478 memcpy(optptr
+3, &opt
->faddr
, 4);
480 if (opt
->rr_needaddr
) {
481 unsigned char * optptr
= opt
->__data
+opt
->rr
-sizeof(struct iphdr
);
483 memset(&optptr
[optptr
[2]-1], 0, 4);
486 unsigned char * optptr
= opt
->__data
+opt
->ts
-sizeof(struct iphdr
);
487 if (opt
->ts_needtime
) {
489 memset(&optptr
[optptr
[2]-1], 0, 4);
490 if ((optptr
[3]&0xF) == IPOPT_TS_PRESPEC
)
493 if (opt
->ts_needaddr
) {
495 memset(&optptr
[optptr
[2]-1], 0, 4);
500 static struct ip_options_rcu
*ip_options_get_alloc(const int optlen
)
502 return kzalloc(sizeof(struct ip_options_rcu
) + ((optlen
+ 3) & ~3),
506 static int ip_options_get_finish(struct net
*net
, struct ip_options_rcu
**optp
,
507 struct ip_options_rcu
*opt
, int optlen
)
510 opt
->opt
.__data
[optlen
++] = IPOPT_END
;
511 opt
->opt
.optlen
= optlen
;
512 if (optlen
&& ip_options_compile(net
, &opt
->opt
, NULL
)) {
521 int ip_options_get_from_user(struct net
*net
, struct ip_options_rcu
**optp
,
522 unsigned char __user
*data
, int optlen
)
524 struct ip_options_rcu
*opt
= ip_options_get_alloc(optlen
);
528 if (optlen
&& copy_from_user(opt
->opt
.__data
, data
, optlen
)) {
532 return ip_options_get_finish(net
, optp
, opt
, optlen
);
535 int ip_options_get(struct net
*net
, struct ip_options_rcu
**optp
,
536 unsigned char *data
, int optlen
)
538 struct ip_options_rcu
*opt
= ip_options_get_alloc(optlen
);
543 memcpy(opt
->opt
.__data
, data
, optlen
);
544 return ip_options_get_finish(net
, optp
, opt
, optlen
);
547 void ip_forward_options(struct sk_buff
*skb
)
549 struct ip_options
* opt
= &(IPCB(skb
)->opt
);
550 unsigned char * optptr
;
551 struct rtable
*rt
= skb_rtable(skb
);
552 unsigned char *raw
= skb_network_header(skb
);
554 if (opt
->rr_needaddr
) {
555 optptr
= (unsigned char *)raw
+ opt
->rr
;
556 ip_rt_get_source(&optptr
[optptr
[2]-5], skb
, rt
);
559 if (opt
->srr_is_hit
) {
560 int srrptr
, srrspace
;
562 optptr
= raw
+ opt
->srr
;
564 for ( srrptr
=optptr
[2], srrspace
= optptr
[1];
568 if (srrptr
+ 3 > srrspace
)
570 if (memcmp(&ip_hdr(skb
)->daddr
, &optptr
[srrptr
-1], 4) == 0)
573 if (srrptr
+ 3 <= srrspace
) {
575 ip_rt_get_source(&optptr
[srrptr
-1], skb
, rt
);
576 optptr
[2] = srrptr
+4;
577 } else if (net_ratelimit())
578 printk(KERN_CRIT
"ip_forward(): Argh! Destination lost!\n");
579 if (opt
->ts_needaddr
) {
580 optptr
= raw
+ opt
->ts
;
581 ip_rt_get_source(&optptr
[optptr
[2]-9], skb
, rt
);
585 if (opt
->is_changed
) {
587 ip_send_check(ip_hdr(skb
));
591 int ip_options_rcv_srr(struct sk_buff
*skb
)
593 struct ip_options
*opt
= &(IPCB(skb
)->opt
);
594 int srrspace
, srrptr
;
596 struct iphdr
*iph
= ip_hdr(skb
);
597 unsigned char *optptr
= skb_network_header(skb
) + opt
->srr
;
598 struct rtable
*rt
= skb_rtable(skb
);
600 unsigned long orefdst
;
606 if (skb
->pkt_type
!= PACKET_HOST
)
608 if (rt
->rt_type
== RTN_UNICAST
) {
609 if (!opt
->is_strictroute
)
611 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, htonl(16<<24));
614 if (rt
->rt_type
!= RTN_LOCAL
)
617 for (srrptr
=optptr
[2], srrspace
= optptr
[1]; srrptr
<= srrspace
; srrptr
+= 4) {
618 if (srrptr
+ 3 > srrspace
) {
619 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, htonl((opt
->srr
+2)<<24));
622 memcpy(&nexthop
, &optptr
[srrptr
-1], 4);
624 orefdst
= skb
->_skb_refdst
;
625 skb_dst_set(skb
, NULL
);
626 err
= ip_route_input(skb
, nexthop
, iph
->saddr
, iph
->tos
, skb
->dev
);
627 rt2
= skb_rtable(skb
);
628 if (err
|| (rt2
->rt_type
!= RTN_UNICAST
&& rt2
->rt_type
!= RTN_LOCAL
)) {
630 skb
->_skb_refdst
= orefdst
;
633 refdst_drop(orefdst
);
634 if (rt2
->rt_type
!= RTN_LOCAL
)
636 /* Superfast 8) loopback forward */
637 iph
->daddr
= nexthop
;
640 if (srrptr
<= srrspace
) {
646 EXPORT_SYMBOL(ip_options_rcv_srr
);