bcm47xx: Fix compilation on non-PCI configs.
[openwrt.git] / target / linux / generic-2.4 / patches / 700-multiple_default_gateways.patch
1 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h
2 ===================================================================
3 --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_nat.h
4 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h
5 @@ -121,5 +121,13 @@ extern int ip_nat_used_tuple(const struc
6  extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
7                                     u_int32_t newval,
8                                     u_int16_t oldcheck);
9 +
10 +/* Call input routing for SNAT-ed traffic */
11 +extern unsigned int ip_nat_route_input(unsigned int hooknum,
12 +                                      struct sk_buff **pskb,
13 +                                      const struct net_device *in,
14 +                                      const struct net_device *out,
15 +                                      int (*okfn)(struct sk_buff *));
16 +
17  #endif /*__KERNEL__*/
18  #endif
19 Index: linux-2.4.35.4/include/linux/rtnetlink.h
20 ===================================================================
21 --- linux-2.4.35.4.orig/include/linux/rtnetlink.h
22 +++ linux-2.4.35.4/include/linux/rtnetlink.h
23 @@ -234,6 +234,8 @@ struct rtnexthop
24  #define RTNH_F_DEAD            1       /* Nexthop is dead (used by multipath)  */
25  #define RTNH_F_PERVASIVE       2       /* Do recursive gateway lookup  */
26  #define RTNH_F_ONLINK          4       /* Gateway is forced on link    */
27 +#define RTNH_F_SUSPECT         8       /* We don't know the real state */
28 +#define RTNH_F_BADSTATE                (RTNH_F_DEAD | RTNH_F_SUSPECT)
29  
30  /* Macros to handle hexthops */
31  
32 Index: linux-2.4.35.4/include/net/ip_fib.h
33 ===================================================================
34 --- linux-2.4.35.4.orig/include/net/ip_fib.h
35 +++ linux-2.4.35.4/include/net/ip_fib.h
36 @@ -162,7 +162,8 @@ static inline int fib_lookup(const struc
37  
38  static inline void fib_select_default(const struct rt_key *key, struct fib_result *res)
39  {
40 -       if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
41 +       if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
42 +           FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
43                 main_table->tb_select_default(main_table, key, res);
44  }
45  
46 @@ -174,6 +175,7 @@ extern struct fib_table * fib_tables[RT_
47  extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
48  extern struct fib_table *__fib_new_table(int id);
49  extern void fib_rule_put(struct fib_rule *r);
50 +extern int fib_result_table(struct fib_result *res);
51  
52  static inline struct fib_table *fib_get_table(int id)
53  {
54 @@ -275,5 +277,6 @@ static inline void fib_res_put(struct fi
55  #endif
56  }
57  
58 +extern rwlock_t fib_nhflags_lock;
59  
60  #endif  /* _NET_FIB_H */
61 Index: linux-2.4.35.4/include/net/route.h
62 ===================================================================
63 --- linux-2.4.35.4.orig/include/net/route.h
64 +++ linux-2.4.35.4/include/net/route.h
65 @@ -49,6 +49,8 @@ struct rt_key
66  {
67         __u32                   dst;
68         __u32                   src;
69 +       __u32                   lsrc;
70 +       __u32                   gw;
71         int                     iif;
72         int                     oif;
73  #ifdef CONFIG_IP_ROUTE_FWMARK
74 @@ -128,6 +130,7 @@ extern void         ip_rt_advice(struct rtable 
75  extern void            rt_cache_flush(int how);
76  extern int             ip_route_output_key(struct rtable **, const struct rt_key *key);
77  extern int             ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
78 +extern int             ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc);
79  extern unsigned short  ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
80  extern void            ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
81  extern void            ip_rt_send_redirect(struct sk_buff *skb);
82 @@ -148,6 +151,15 @@ static inline int ip_route_output(struct
83  }
84  
85  
86 +static inline int
87 +ip_route_output_lookup(struct rtable **rp,
88 +                      u32 daddr, u32 saddr, u32 tos, int oif, u32 gw)
89 +{
90 +       struct rt_key key = { dst:daddr, src:saddr, gw:gw, oif:oif, tos:tos };
91 +
92 +       return ip_route_output_key(rp, &key);
93 +}
94 +
95  static inline void ip_rt_put(struct rtable * rt)
96  {
97         if (rt)
98 Index: linux-2.4.35.4/net/ipv4/fib_frontend.c
99 ===================================================================
100 --- linux-2.4.35.4.orig/net/ipv4/fib_frontend.c
101 +++ linux-2.4.35.4/net/ipv4/fib_frontend.c
102 @@ -54,6 +54,8 @@
103  struct fib_table *local_table;
104  struct fib_table *main_table;
105  
106 +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
107 +
108  #else
109  
110  #define RT_TABLE_MIN 1
111 @@ -71,6 +73,7 @@ struct fib_table *__fib_new_table(int id
112         return tb;
113  }
114  
115 +#define FIB_RES_TABLE(r) (fib_result_table(r))
116  
117  #endif /* CONFIG_IP_MULTIPLE_TABLES */
118  
119 @@ -209,6 +212,9 @@ int fib_validate_source(u32 src, u32 dst
120         struct in_device *in_dev;
121         struct rt_key key;
122         struct fib_result res;
123 +       int table;
124 +       unsigned char prefixlen;
125 +       unsigned char scope;
126         int no_addr, rpf;
127         int ret;
128  
129 @@ -216,6 +222,7 @@ int fib_validate_source(u32 src, u32 dst
130         key.src = dst;
131         key.tos = tos;
132         key.oif = 0;
133 +       key.gw  = 0;
134         key.iif = oif;
135         key.scope = RT_SCOPE_UNIVERSE;
136  
137 @@ -237,31 +244,35 @@ int fib_validate_source(u32 src, u32 dst
138                 goto e_inval_res;
139         *spec_dst = FIB_RES_PREFSRC(res);
140         fib_combine_itag(itag, &res);
141 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
142 -       if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
143 -#else
144         if (FIB_RES_DEV(res) == dev)
145 -#endif
146         {
147                 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
148                 fib_res_put(&res);
149                 return ret;
150         }
151 +       table = FIB_RES_TABLE(&res);
152 +       prefixlen = res.prefixlen;
153 +       scope = res.scope;
154         fib_res_put(&res);
155         if (no_addr)
156                 goto last_resort;
157 -       if (rpf)
158 -               goto e_inval;
159         key.oif = dev->ifindex;
160  
161         ret = 0;
162         if (fib_lookup(&key, &res) == 0) {
163 -               if (res.type == RTN_UNICAST) {
164 +               if (res.type == RTN_UNICAST &&
165 +                   ((table == FIB_RES_TABLE(&res) &&
166 +                     res.prefixlen >= prefixlen && res.scope >= scope) ||
167 +                    !rpf)) {
168                         *spec_dst = FIB_RES_PREFSRC(res);
169                         ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
170 +                       fib_res_put(&res);
171 +                       return ret;
172                 }
173                 fib_res_put(&res);
174         }
175 +       if (rpf)
176 +               goto e_inval;
177         return ret;
178  
179  last_resort:
180 @@ -579,9 +590,7 @@ static int fib_inetaddr_event(struct not
181         switch (event) {
182         case NETDEV_UP:
183                 fib_add_ifaddr(ifa);
184 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
185                 fib_sync_up(ifa->ifa_dev->dev);
186 -#endif
187                 rt_cache_flush(-1);
188                 break;
189         case NETDEV_DOWN:
190 @@ -617,9 +626,7 @@ static int fib_netdev_event(struct notif
191                 for_ifa(in_dev) {
192                         fib_add_ifaddr(ifa);
193                 } endfor_ifa(in_dev);
194 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
195                 fib_sync_up(dev);
196 -#endif
197                 rt_cache_flush(-1);
198                 break;
199         case NETDEV_DOWN:
200 Index: linux-2.4.35.4/net/ipv4/fib_hash.c
201 ===================================================================
202 --- linux-2.4.35.4.orig/net/ipv4/fib_hash.c
203 +++ linux-2.4.35.4/net/ipv4/fib_hash.c
204 @@ -71,6 +71,7 @@ struct fib_node
205         struct fib_info         *fn_info;
206  #define FIB_INFO(f)    ((f)->fn_info)
207         fn_key_t                fn_key;
208 +       int                     fn_last_dflt;
209         u8                      fn_tos;
210         u8                      fn_type;
211         u8                      fn_scope;
212 @@ -336,72 +337,123 @@ out:
213         return err;
214  }
215  
216 -static int fn_hash_last_dflt=-1;
217 -
218 -static int fib_detect_death(struct fib_info *fi, int order,
219 -                           struct fib_info **last_resort, int *last_idx)
220 +static int fib_detect_death(struct fib_info *fi, int order, int last_dflt,
221 +                           struct fib_info **last_resort, int *last_idx,
222 +                           int *last_nhsel, const struct rt_key *key)
223  {
224         struct neighbour *n;
225 -       int state = NUD_NONE;
226 +       int nhsel;
227 +       int state;
228 +       struct fib_nh * nh;
229 +       u32 dst;
230 +       int flag, dead = 1;
231 +
232 +       /* change_nexthops(fi) { */
233 +       for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
234 +               if (key->oif && key->oif != nh->nh_oif)
235 +                       continue;
236 +               if (key->gw && key->gw != nh->nh_gw && nh->nh_gw &&
237 +                   nh->nh_scope == RT_SCOPE_LINK)
238 +                       continue;
239 +               if (nh->nh_flags & RTNH_F_DEAD)
240 +                       continue;
241  
242 -       n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
243 -       if (n) {
244 -               state = n->nud_state;
245 -               neigh_release(n);
246 +               flag = 0;
247 +               if (nh->nh_dev->flags & IFF_NOARP) {
248 +                       dead = 0;
249 +                       goto setfl;
250 +               }
251 +
252 +               dst = nh->nh_gw;
253 +               if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
254 +                       dst = key->dst;
255 +
256 +               state = NUD_NONE;
257 +               n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
258 +               if (n) {
259 +                       state = n->nud_state;
260 +                       neigh_release(n);
261 +               }
262 +               if (state==NUD_REACHABLE ||
263 +                       ((state&NUD_VALID) && order != last_dflt)) {
264 +                       dead = 0;
265 +                       goto setfl;
266 +               }
267 +               if (!(state&NUD_VALID))
268 +                       flag = 1;
269 +               if (!dead)
270 +                       goto setfl;
271 +               if ((state&NUD_VALID) ||
272 +                   (*last_idx<0 && order >= last_dflt)) {
273 +                       *last_resort = fi;
274 +                       *last_idx = order;
275 +                       *last_nhsel = nhsel;
276 +               }
277 +
278 +               setfl:
279 +
280 +               read_lock_bh(&fib_nhflags_lock);
281 +               if (flag)
282 +                       nh->nh_flags |= RTNH_F_SUSPECT;
283 +               else
284 +                       nh->nh_flags &= ~RTNH_F_SUSPECT;
285 +               read_unlock_bh(&fib_nhflags_lock);
286         }
287 -       if (state==NUD_REACHABLE)
288 -               return 0;
289 -       if ((state&NUD_VALID) && order != fn_hash_last_dflt)
290 -               return 0;
291 -       if ((state&NUD_VALID) ||
292 -           (*last_idx<0 && order > fn_hash_last_dflt)) {
293 -               *last_resort = fi;
294 -               *last_idx = order;
295 -       }
296 -       return 1;
297 +       /* } endfor_nexthops(fi) */
298 +
299 +       return dead;
300  }
301  
302  static void
303  fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
304  {
305 -       int order, last_idx;
306 -       struct fib_node *f;
307 +       int order, last_idx, last_dflt, last_nhsel;
308 +       struct fib_node *f, *first_node;
309         struct fib_info *fi = NULL;
310         struct fib_info *last_resort;
311         struct fn_hash *t = (struct fn_hash*)tb->tb_data;
312 -       struct fn_zone *fz = t->fn_zones[0];
313 +       struct fn_zone *fz = t->fn_zones[res->prefixlen];
314 +       fn_key_t k;
315  
316         if (fz == NULL)
317                 return;
318  
319 +       k = fz_key(key->dst, fz);
320 +       last_dflt = -2;
321 +       first_node = NULL;
322         last_idx = -1;
323         last_resort = NULL;
324 +       last_nhsel = 0;
325         order = -1;
326  
327         read_lock(&fib_hash_lock);
328 -       for (f = fz->fz_hash[0]; f; f = f->fn_next) {
329 +       for (f = fz_chain(k, fz); f; f = f->fn_next) {
330                 struct fib_info *next_fi = FIB_INFO(f);
331  
332 -               if ((f->fn_state&FN_S_ZOMBIE) ||
333 +               if (!fn_key_eq(k, f->fn_key) ||
334 +                   (f->fn_state&FN_S_ZOMBIE) ||
335                     f->fn_scope != res->scope ||
336 +#ifdef CONFIG_IP_ROUTE_TOS
337 +                   (f->fn_tos && f->fn_tos != key->tos) ||
338 +#endif
339                     f->fn_type != RTN_UNICAST)
340                         continue;
341  
342                 if (next_fi->fib_priority > res->fi->fib_priority)
343                         break;
344 -               if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
345 -                       continue;
346                 f->fn_state |= FN_S_ACCESSED;
347  
348 -               if (fi == NULL) {
349 -                       if (next_fi != res->fi)
350 -                               break;
351 -               } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
352 +               if (!first_node) {
353 +                       last_dflt = f->fn_last_dflt;
354 +                       first_node = f;
355 +               }
356 +               if (fi && !fib_detect_death(fi, order, last_dflt,
357 +                               &last_resort, &last_idx, &last_nhsel, key)) {
358                         if (res->fi)
359                                 fib_info_put(res->fi);
360                         res->fi = fi;
361                         atomic_inc(&fi->fib_clntref);
362 -                       fn_hash_last_dflt = order;
363 +                       first_node->fn_last_dflt = order;
364                         goto out;
365                 }
366                 fi = next_fi;
367 @@ -409,16 +461,25 @@ fn_hash_select_default(struct fib_table 
368         }
369  
370         if (order<=0 || fi==NULL) {
371 -               fn_hash_last_dflt = -1;
372 +               if (fi && fi->fib_nhs > 1 &&
373 +                   fib_detect_death(fi, order, last_dflt,
374 +                       &last_resort, &last_idx, &last_nhsel, key) &&
375 +                   last_resort == fi) {
376 +                       read_lock_bh(&fib_nhflags_lock);
377 +                       fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
378 +                       read_unlock_bh(&fib_nhflags_lock);
379 +               }
380 +               if (first_node) first_node->fn_last_dflt = -1;
381                 goto out;
382         }
383  
384 -       if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
385 +       if (!fib_detect_death(fi, order, last_dflt, &last_resort, &last_idx,
386 +                             &last_nhsel, key)) {
387                 if (res->fi)
388                         fib_info_put(res->fi);
389                 res->fi = fi;
390                 atomic_inc(&fi->fib_clntref);
391 -               fn_hash_last_dflt = order;
392 +               first_node->fn_last_dflt = order;
393                 goto out;
394         }
395  
396 @@ -428,8 +489,11 @@ fn_hash_select_default(struct fib_table 
397                 res->fi = last_resort;
398                 if (last_resort)
399                         atomic_inc(&last_resort->fib_clntref);
400 +               read_lock_bh(&fib_nhflags_lock);
401 +               last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
402 +               read_unlock_bh(&fib_nhflags_lock);
403 +               first_node->fn_last_dflt = last_idx;
404         }
405 -       fn_hash_last_dflt = last_idx;
406  out:
407         read_unlock(&fib_hash_lock);
408  }
409 @@ -589,6 +653,7 @@ replace:
410  
411         memset(new_f, 0, sizeof(struct fib_node));
412  
413 +       new_f->fn_last_dflt = -1;
414         new_f->fn_key = key;
415  #ifdef CONFIG_IP_ROUTE_TOS
416         new_f->fn_tos = tos;
417 Index: linux-2.4.35.4/net/ipv4/fib_rules.c
418 ===================================================================
419 --- linux-2.4.35.4.orig/net/ipv4/fib_rules.c
420 +++ linux-2.4.35.4/net/ipv4/fib_rules.c
421 @@ -307,6 +307,11 @@ static void fib_rules_attach(struct net_
422         }
423  }
424  
425 +int fib_result_table(struct fib_result *res)
426 +{
427 +       return res->r->r_table;
428 +}
429 +
430  int fib_lookup(const struct rt_key *key, struct fib_result *res)
431  {
432         int err;
433 @@ -371,8 +376,10 @@ FRprintk("FAILURE\n");
434  
435  void fib_select_default(const struct rt_key *key, struct fib_result *res)
436  {
437 -       if (res->r && res->r->r_action == RTN_UNICAST &&
438 -           FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
439 +       if (res->r &&
440 +           (res->r->r_action == RTN_UNICAST || res->r->r_action == RTN_NAT) &&
441 +           ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
442 +            FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
443                 struct fib_table *tb;
444                 if ((tb = fib_get_table(res->r->r_table)) != NULL)
445                         tb->tb_select_default(tb, key, res);
446 Index: linux-2.4.35.4/net/ipv4/fib_semantics.c
447 ===================================================================
448 --- linux-2.4.35.4.orig/net/ipv4/fib_semantics.c
449 +++ linux-2.4.35.4/net/ipv4/fib_semantics.c
450 @@ -48,6 +48,7 @@
451  static struct fib_info         *fib_info_list;
452  static rwlock_t fib_info_lock = RW_LOCK_UNLOCKED;
453  int fib_info_cnt;
454 +rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
455  
456  #define for_fib_info() { struct fib_info *fi; \
457         for (fi = fib_info_list; fi; fi = fi->fib_next)
458 @@ -150,7 +151,7 @@ static __inline__ int nh_comp(const stru
459  #ifdef CONFIG_NET_CLS_ROUTE
460                     nh->nh_tclassid != onh->nh_tclassid ||
461  #endif
462 -                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
463 +                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
464                         return -1;
465                 onh++;
466         } endfor_nexthops(fi);
467 @@ -166,7 +167,7 @@ static __inline__ struct fib_info * fib_
468                     nfi->fib_prefsrc == fi->fib_prefsrc &&
469                     nfi->fib_priority == fi->fib_priority &&
470                     memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
471 -                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
472 +                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
473                     (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
474                         return fi;
475         } endfor_fib_info();
476 @@ -365,8 +366,11 @@ static int fib_check_nh(const struct rtm
477                                 return -EINVAL;
478                         if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
479                                 return -ENODEV;
480 -                       if (!(dev->flags&IFF_UP))
481 -                               return -ENETDOWN;
482 +                       if (!(dev->flags&IFF_UP)) {
483 +                               if (fi->fib_protocol != RTPROT_STATIC)
484 +                                       return -ENETDOWN;
485 +                               nh->nh_flags |= RTNH_F_DEAD;
486 +                       }
487                         nh->nh_dev = dev;
488                         dev_hold(dev);
489                         nh->nh_scope = RT_SCOPE_LINK;
490 @@ -380,23 +384,48 @@ static int fib_check_nh(const struct rtm
491                 /* It is not necessary, but requires a bit of thinking */
492                 if (key.scope < RT_SCOPE_LINK)
493                         key.scope = RT_SCOPE_LINK;
494 -               if ((err = fib_lookup(&key, &res)) != 0)
495 -                       return err;
496 -               err = -EINVAL;
497 -               if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
498 -                       goto out;
499 -               nh->nh_scope = res.scope;
500 -               nh->nh_oif = FIB_RES_OIF(res);
501 -               if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
502 -                       goto out;
503 -               dev_hold(nh->nh_dev);
504 -               err = -ENETDOWN;
505 -               if (!(nh->nh_dev->flags & IFF_UP))
506 -                       goto out;
507 -               err = 0;
508 +
509 +               err = fib_lookup(&key, &res);
510 +               if (err) {
511 +                       struct in_device *in_dev;
512 +
513 +                       if (err != -ENETUNREACH ||
514 +                           fi->fib_protocol != RTPROT_STATIC)
515 +                               return err;
516 +
517 +                       in_dev = inetdev_by_index(nh->nh_oif);
518 +                       if (in_dev == NULL ||
519 +                           in_dev->dev->flags & IFF_UP) {
520 +                               if (in_dev)
521 +                                       in_dev_put(in_dev);
522 +                               return err;
523 +                       }
524 +                       nh->nh_flags |= RTNH_F_DEAD;
525 +                       nh->nh_scope = RT_SCOPE_LINK;
526 +                       nh->nh_dev = in_dev->dev;
527 +                       dev_hold(nh->nh_dev);
528 +                       in_dev_put(in_dev);
529 +               } else {
530 +                       err = -EINVAL;
531 +                       if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
532 +                               goto out;
533 +                       nh->nh_scope = res.scope;
534 +                       nh->nh_oif = FIB_RES_OIF(res);
535 +                       if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
536 +                               goto out;
537 +                       dev_hold(nh->nh_dev);
538 +                       if (!(nh->nh_dev->flags & IFF_UP)) {
539 +                               if (fi->fib_protocol != RTPROT_STATIC) {
540 +                                       err = -ENETDOWN;
541 +                                       goto out;
542 +                               }
543 +                               nh->nh_flags |= RTNH_F_DEAD;
544 +                       }
545 +                       err = 0;
546  out:
547 -               fib_res_put(&res);
548 -               return err;
549 +                       fib_res_put(&res);
550 +                       return err;
551 +               }
552         } else {
553                 struct in_device *in_dev;
554  
555 @@ -407,8 +436,11 @@ out:
556                 if (in_dev == NULL)
557                         return -ENODEV;
558                 if (!(in_dev->dev->flags&IFF_UP)) {
559 -                       in_dev_put(in_dev);
560 -                       return -ENETDOWN;
561 +                       if (fi->fib_protocol != RTPROT_STATIC) {
562 +                               in_dev_put(in_dev);
563 +                               return -ENETDOWN;
564 +                       }
565 +                       nh->nh_flags |= RTNH_F_DEAD;
566                 }
567                 nh->nh_dev = in_dev->dev;
568                 dev_hold(nh->nh_dev);
569 @@ -606,8 +638,12 @@ fib_semantic_match(int type, struct fib_
570                         for_nexthops(fi) {
571                                 if (nh->nh_flags&RTNH_F_DEAD)
572                                         continue;
573 -                               if (!key->oif || key->oif == nh->nh_oif)
574 -                                       break;
575 +                               if (key->oif && key->oif != nh->nh_oif)
576 +                                       continue;
577 +                               if (key->gw && key->gw != nh->nh_gw &&
578 +                                   nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
579 +                                       continue;
580 +                               break;
581                         }
582  #ifdef CONFIG_IP_ROUTE_MULTIPATH
583                         if (nhsel < fi->fib_nhs) {
584 @@ -873,22 +909,35 @@ int fib_sync_down(u32 local, struct net_
585                 if (local && fi->fib_prefsrc == local) {
586                         fi->fib_flags |= RTNH_F_DEAD;
587                         ret++;
588 -               } else if (dev && fi->fib_nhs) {
589 +               } else if (fi->fib_nhs) {
590                         int dead = 0;
591  
592                         change_nexthops(fi) {
593 -                               if (nh->nh_flags&RTNH_F_DEAD)
594 -                                       dead++;
595 -                               else if (nh->nh_dev == dev &&
596 -                                        nh->nh_scope != scope) {
597 -                                       nh->nh_flags |= RTNH_F_DEAD;
598 +                               if (nh->nh_flags&RTNH_F_DEAD) {
599 +                                       if (fi->fib_protocol!=RTPROT_STATIC ||
600 +                                           nh->nh_dev == NULL ||
601 +                                           !__in_dev_get(nh->nh_dev) ||
602 +                                           nh->nh_dev->flags&IFF_UP)
603 +                                               dead++;
604 +                               } else if ((nh->nh_dev == dev && dev &&
605 +                                           nh->nh_scope != scope) ||
606 +                                           (local == nh->nh_gw && local &&
607 +                                            nh->nh_oif)) {
608 +                                       write_lock_bh(&fib_nhflags_lock);
609  #ifdef CONFIG_IP_ROUTE_MULTIPATH
610 -                                       spin_lock_bh(&fib_multipath_lock);
611 +                                       spin_lock(&fib_multipath_lock);
612 +                                       nh->nh_flags |= RTNH_F_DEAD;
613                                         fi->fib_power -= nh->nh_power;
614                                         nh->nh_power = 0;
615 -                                       spin_unlock_bh(&fib_multipath_lock);
616 +                                       spin_unlock(&fib_multipath_lock);
617 +#else
618 +                                       nh->nh_flags |= RTNH_F_DEAD;
619  #endif
620 -                                       dead++;
621 +                                       write_unlock_bh(&fib_nhflags_lock);
622 +                                       if (fi->fib_protocol!=RTPROT_STATIC ||
623 +                                           force ||
624 +                                           (dev && __in_dev_get(dev) == NULL))
625 +                                               dead++;
626                                 }
627  #ifdef CONFIG_IP_ROUTE_MULTIPATH
628                                 if (force > 1 && nh->nh_dev == dev) {
629 @@ -906,37 +955,55 @@ int fib_sync_down(u32 local, struct net_
630         return ret;
631  }
632  
633 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
634 -
635  /*
636 -   Dead device goes up. We wake up dead nexthops.
637 -   It takes sense only on multipath routes.
638 +   Dead device goes up or new address is added. We wake up dead nexthops.
639   */
640  
641  int fib_sync_up(struct net_device *dev)
642  {
643 -       int ret = 0;
644 +       struct rt_key key;
645 +       struct fib_result res;
646 +       int ret, rep;
647  
648 +repeat:
649         if (!(dev->flags&IFF_UP))
650                 return 0;
651  
652 +       ret = 0;
653 +       rep = 0;
654         for_fib_info() {
655                 int alive = 0;
656  
657                 change_nexthops(fi) {
658 -                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
659 -                               alive++;
660 +                       if (!(nh->nh_flags&RTNH_F_DEAD))
661                                 continue;
662 -                       }
663                         if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
664                                 continue;
665                         if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
666                                 continue;
667 +                       if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
668 +                               memset(&key, 0, sizeof(key));
669 +                               key.dst = nh->nh_gw;
670 +                               key.oif = nh->nh_oif;
671 +                               key.scope = nh->nh_scope;
672 +                               if (fib_lookup(&key, &res) != 0)
673 +                                       continue;
674 +                               if (res.type != RTN_UNICAST &&
675 +                                   res.type != RTN_LOCAL) {
676 +                                       fib_res_put(&res);
677 +                                       continue;
678 +                               }
679 +                               nh->nh_scope = res.scope;
680 +                               fib_res_put(&res);
681 +                               rep = 1;
682 +                       }
683                         alive++;
684 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
685                         spin_lock_bh(&fib_multipath_lock);
686                         nh->nh_power = 0;
687                         nh->nh_flags &= ~RTNH_F_DEAD;
688                         spin_unlock_bh(&fib_multipath_lock);
689 +#endif
690                 } endfor_nexthops(fi)
691  
692                 if (alive > 0) {
693 @@ -944,9 +1011,13 @@ int fib_sync_up(struct net_device *dev)
694                         ret++;
695                 }
696         } endfor_fib_info();
697 +       if (rep)
698 +               goto repeat;
699         return ret;
700  }
701  
702 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
703 +
704  /*
705     The algorithm is suboptimal, but it provides really
706     fair weighted route distribution.
707 @@ -955,24 +1026,45 @@ int fib_sync_up(struct net_device *dev)
708  void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
709  {
710         struct fib_info *fi = res->fi;
711 -       int w;
712 +       int w, alive;
713  
714         spin_lock_bh(&fib_multipath_lock);
715 +       if (key->oif) {
716 +               int sel = -1;
717 +               w = -1;
718 +               change_nexthops(fi) {
719 +                       if (key->oif != nh->nh_oif)
720 +                               continue;
721 +                       if (key->gw && key->gw != nh->nh_gw &&
722 +                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
723 +                               continue;
724 +                       if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
725 +                               if (nh->nh_power > w) {
726 +                                       w = nh->nh_power;
727 +                                       sel = nhsel;
728 +                               }
729 +                       }
730 +               } endfor_nexthops(fi);
731 +               if (sel >= 0) {
732 +                       spin_unlock_bh(&fib_multipath_lock);
733 +                       res->nh_sel = sel;
734 +                       return;
735 +               }
736 +               goto last_resort;
737 +       }
738 +
739 +repeat:
740         if (fi->fib_power <= 0) {
741                 int power = 0;
742                 change_nexthops(fi) {
743 -                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
744 +                       if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
745                                 power += nh->nh_weight;
746                                 nh->nh_power = nh->nh_weight;
747                         }
748                 } endfor_nexthops(fi);
749                 fi->fib_power = power;
750 -               if (power <= 0) {
751 -                       spin_unlock_bh(&fib_multipath_lock);
752 -                       /* Race condition: route has just become dead. */
753 -                       res->nh_sel = 0;
754 -                       return;
755 -               }
756 +               if (power <= 0)
757 +                       goto last_resort;
758         }
759  
760  
761 @@ -982,20 +1074,40 @@ void fib_select_multipath(const struct r
762  
763         w = jiffies % fi->fib_power;
764  
765 +       alive = 0;
766         change_nexthops(fi) {
767 -               if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
768 +               if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
769                         if ((w -= nh->nh_power) <= 0) {
770                                 nh->nh_power--;
771                                 fi->fib_power--;
772 -                               res->nh_sel = nhsel;
773                                 spin_unlock_bh(&fib_multipath_lock);
774 +                               res->nh_sel = nhsel;
775                                 return;
776                         }
777 +                       alive = 1;
778 +               }
779 +       } endfor_nexthops(fi);
780 +       if (alive) {
781 +               fi->fib_power = 0;
782 +               goto repeat;
783 +       }
784 +
785 +last_resort:
786 +
787 +       for_nexthops(fi) {
788 +               if (!(nh->nh_flags&RTNH_F_DEAD)) {
789 +                       if (key->oif && key->oif != nh->nh_oif)
790 +                               continue;
791 +                       if (key->gw && key->gw != nh->nh_gw &&
792 +                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
793 +                               continue;
794 +                       spin_unlock_bh(&fib_multipath_lock);
795 +                       res->nh_sel = nhsel;
796 +                       return;
797                 }
798         } endfor_nexthops(fi);
799  
800         /* Race condition: route has just become dead. */
801 -       res->nh_sel = 0;
802         spin_unlock_bh(&fib_multipath_lock);
803  }
804  #endif
805 Index: linux-2.4.35.4/net/ipv4/ip_nat_dumb.c
806 ===================================================================
807 --- linux-2.4.35.4.orig/net/ipv4/ip_nat_dumb.c
808 +++ linux-2.4.35.4/net/ipv4/ip_nat_dumb.c
809 @@ -124,6 +124,7 @@ ip_do_nat(struct sk_buff *skb)
810                                         key.dst = ciph->saddr;
811                                         key.iif = skb->dev->ifindex;
812                                         key.oif = 0;
813 +                                       key.gw  = 0;
814  #ifdef CONFIG_IP_ROUTE_TOS
815                                         key.tos = RT_TOS(ciph->tos);
816  #endif
817 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c
818 ===================================================================
819 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_fw_compat_masq.c
820 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c
821 @@ -41,6 +41,10 @@ do_masquerade(struct sk_buff **pskb, con
822         enum ip_conntrack_info ctinfo;
823         struct ip_conntrack *ct;
824         unsigned int ret;
825 +       struct rtable *rt, *skb_rt;
826 +       struct net_device *skb_dev;
827 +       __u32 saddr;
828 +       int new;
829  
830         /* Sorry, only ICMP, TCP and UDP. */
831         if (iph->protocol != IPPROTO_ICMP
832 @@ -64,22 +68,28 @@ do_masquerade(struct sk_buff **pskb, con
833         }
834  
835         info = &ct->nat.info;
836 +       iph = (*pskb)->nh.iph;
837 +       saddr = iph->saddr;
838 +       new = 0;
839  
840         WRITE_LOCK(&ip_nat_lock);
841         /* Setup the masquerade, if not already */
842         if (!info->initialized) {
843                 u_int32_t newsrc;
844 -               struct rtable *rt;
845                 struct ip_nat_multi_range range;
846  
847 +               skb_rt = (struct rtable *) (*pskb)->dst;
848 +               skb_dev = skb_rt->u.dst.dev;
849                 /* Pass 0 instead of saddr, since it's going to be changed
850                    anyway. */
851 -               if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
852 +               if (ip_route_output_lookup(&rt, iph->daddr, 0, RT_TOS(iph->tos),
853 +                   skb_dev? skb_dev->ifindex : 0,
854 +                   skb_dev? skb_rt->rt_gateway : 0) != 0) {
855 +                       WRITE_UNLOCK(&ip_nat_lock);
856                         DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
857                         return NF_DROP;
858                 }
859 -               newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
860 -                                         RT_SCOPE_UNIVERSE);
861 +               newsrc = rt->rt_src;
862                 ip_rt_put(rt);
863                 range = ((struct ip_nat_multi_range)
864                          { 1,
865 @@ -92,11 +102,31 @@ do_masquerade(struct sk_buff **pskb, con
866                         WRITE_UNLOCK(&ip_nat_lock);
867                         return ret;
868                 }
869 +               new = 1;
870         } else
871                 DEBUGP("Masquerading already done on this conn.\n");
872         WRITE_UNLOCK(&ip_nat_lock);
873  
874 -       return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
875 +       ret = do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
876 +       if (ret != NF_ACCEPT || saddr == (*pskb)->nh.iph->saddr || new)
877 +               return ret;
878 +
879 +       iph = (*pskb)->nh.iph;
880 +       if (ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), 0) != 0)
881 +               return NF_DROP;
882 +       
883 +       skb_rt = (struct rtable *) (*pskb)->dst;
884 +       skb_dev = skb_rt->u.dst.dev;
885 +       if (skb_dev != rt->u.dst.dev || rt->rt_gateway != skb_rt->rt_gateway) {
886 +               if (skb_dev != rt->u.dst.dev) {
887 +                       /* TODO: check the new mtu and reply FRAG_NEEDED */
888 +               }
889 +               dst_release((*pskb)->dst);
890 +               (*pskb)->dst = &rt->u.dst;
891 +       } else {
892 +               ip_rt_put(rt);
893 +       }
894 +       return NF_ACCEPT;
895  }
896  
897  void
898 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
899 ===================================================================
900 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_core.c
901 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
902 @@ -994,6 +994,60 @@ icmp_reply_translation(struct sk_buff *s
903         return NF_ACCEPT;
904  }
905  
906 +unsigned int
907 +ip_nat_route_input(unsigned int hooknum,
908 +               struct sk_buff **pskb,
909 +               const struct net_device *in,
910 +               const struct net_device *out,
911 +               int (*okfn)(struct sk_buff *))
912 +{
913 +       struct sk_buff *skb = *pskb;
914 +       struct iphdr *iph;
915 +       struct ip_conntrack *ct;
916 +       enum ip_conntrack_info ctinfo;
917 +       struct ip_nat_info *info;
918 +       enum ip_conntrack_dir dir;
919 +       __u32 saddr;
920 +       int i;
921 +
922 +       if (!(ct = ip_conntrack_get(skb, &ctinfo)))
923 +               return NF_ACCEPT;
924 +
925 +       info = &ct->nat.info;
926 +       if (!info->initialized)
927 +               return NF_ACCEPT;
928 +
929 +       if (skb->dst)
930 +               return NF_ACCEPT;
931 +
932 +       if (skb->len < sizeof(struct iphdr))
933 +               return NF_ACCEPT;
934 +
935 +       iph = skb->nh.iph;
936 +       saddr = iph->saddr;
937 +       hooknum = NF_IP_POST_ROUTING;
938 +       dir = CTINFO2DIR(ctinfo);
939 +
940 +       READ_LOCK(&ip_nat_lock);
941 +       for (i = 0; i < info->num_manips; i++) {
942 +               if (info->manips[i].direction == dir
943 +                   && info->manips[i].hooknum == hooknum
944 +                   && info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
945 +                       saddr = info->manips[i].manip.ip;
946 +               }
947 +       }
948 +       READ_UNLOCK(&ip_nat_lock);
949 +
950 +       if (saddr == iph->saddr)
951 +               return NF_ACCEPT;
952 +
953 +       if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
954 +           skb->dev, saddr))
955 +               return NF_DROP;
956 +
957 +       return NF_ACCEPT;
958 +}
959 +
960  int __init ip_nat_init(void)
961  {
962         size_t i;
963 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c
964 ===================================================================
965 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_standalone.c
966 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c
967 @@ -245,6 +245,9 @@ ip_nat_local_fn(unsigned int hooknum,
968  /* Before packet filtering, change destination */
969  static struct nf_hook_ops ip_nat_in_ops
970  = { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
971 +/* Before routing, route before mangling */
972 +static struct nf_hook_ops ip_nat_inr_ops
973 += { { NULL, NULL }, ip_nat_route_input, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LAST-1 };
974  /* After packet filtering, change source */
975  static struct nf_hook_ops ip_nat_out_ops
976  = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
977 @@ -313,10 +316,15 @@ static int init_or_cleanup(int init)
978                 printk("ip_nat_init: can't register in hook.\n");
979                 goto cleanup_nat;
980         }
981 +       ret = nf_register_hook(&ip_nat_inr_ops);
982 +       if (ret < 0) {
983 +               printk("ip_nat_init: can't register inr hook.\n");
984 +               goto cleanup_inops;
985 +       }
986         ret = nf_register_hook(&ip_nat_out_ops);
987         if (ret < 0) {
988                 printk("ip_nat_init: can't register out hook.\n");
989 -               goto cleanup_inops;
990 +               goto cleanup_inrops;
991         }
992         ret = nf_register_hook(&ip_nat_local_out_ops);
993         if (ret < 0) {
994 @@ -336,6 +344,8 @@ static int init_or_cleanup(int init)
995         nf_unregister_hook(&ip_nat_local_out_ops);
996   cleanup_outops:
997         nf_unregister_hook(&ip_nat_out_ops);
998 + cleanup_inrops:
999 +       nf_unregister_hook(&ip_nat_inr_ops);
1000   cleanup_inops:
1001         nf_unregister_hook(&ip_nat_in_ops);
1002   cleanup_nat:
1003 Index: linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c
1004 ===================================================================
1005 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ipt_MASQUERADE.c
1006 +++ linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c
1007 @@ -87,7 +87,8 @@ masquerade_target(struct sk_buff **pskb,
1008         key.dst = (*pskb)->nh.iph->daddr;
1009         key.src = 0; /* Unknown: that's what we're trying to establish */
1010         key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
1011 -       key.oif = 0;
1012 +       key.oif = out->ifindex;
1013 +       key.gw  = ((struct rtable *) (*pskb)->dst)->rt_gateway;
1014  #ifdef CONFIG_IP_ROUTE_FWMARK
1015         key.fwmark = (*pskb)->nfmark;
1016  #endif
1017 @@ -98,13 +99,6 @@ masquerade_target(struct sk_buff **pskb,
1018                                 " No route: Rusty's brain broke!\n");
1019                  return NF_DROP;
1020          }
1021 -        if (rt->u.dst.dev != out) {
1022 -                if (net_ratelimit())
1023 -                        printk("MASQUERADE:"
1024 -                               " Route sent us somewhere else.\n");
1025 -                       ip_rt_put(rt);
1026 -               return NF_DROP;
1027 -       }
1028  
1029         newsrc = rt->rt_src;
1030         DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
1031 Index: linux-2.4.35.4/net/ipv4/route.c
1032 ===================================================================
1033 --- linux-2.4.35.4.orig/net/ipv4/route.c
1034 +++ linux-2.4.35.4/net/ipv4/route.c
1035 @@ -919,6 +919,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
1036  
1037                                 /* Gateway is different ... */
1038                                 rt->rt_gateway          = new_gw;
1039 +                               if (rt->key.gw) rt->key.gw = new_gw;
1040  
1041                                 /* Redirect received -> path was valid */
1042                                 dst_confirm(&rth->u.dst);
1043 @@ -1343,6 +1344,7 @@ static int ip_route_input_mc(struct sk_b
1044         rth->key.fwmark = skb->nfmark;
1045  #endif
1046         rth->key.src    = saddr;
1047 +       rth->key.lsrc   = 0;
1048         rth->rt_src     = saddr;
1049  #ifdef CONFIG_IP_ROUTE_NAT
1050         rth->rt_dst_map = daddr;
1051 @@ -1356,6 +1358,7 @@ static int ip_route_input_mc(struct sk_b
1052         rth->u.dst.dev  = &loopback_dev;
1053         dev_hold(rth->u.dst.dev);
1054         rth->key.oif    = 0;
1055 +       rth->key.gw     = 0;
1056         rth->rt_gateway = daddr;
1057         rth->rt_spec_dst= spec_dst;
1058         rth->rt_type    = RTN_MULTICAST;
1059 @@ -1395,7 +1398,7 @@ e_inval:
1060   */
1061  
1062  int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
1063 -                       u8 tos, struct net_device *dev)
1064 +                       u8 tos, struct net_device *dev, u32 lsrc)
1065  {
1066         struct rt_key   key;
1067         struct fib_result res;
1068 @@ -1415,16 +1418,17 @@ int ip_route_input_slow(struct sk_buff *
1069                 goto out;
1070  
1071         key.dst         = daddr;
1072 -       key.src         = saddr;
1073 +       key.src         = lsrc? : saddr;
1074         key.tos         = tos;
1075  #ifdef CONFIG_IP_ROUTE_FWMARK
1076         key.fwmark      = skb->nfmark;
1077  #endif
1078 -       key.iif         = dev->ifindex;
1079 +       key.iif         = lsrc? loopback_dev.ifindex : dev->ifindex;
1080         key.oif         = 0;
1081 +       key.gw          = 0;
1082         key.scope       = RT_SCOPE_UNIVERSE;
1083  
1084 -       hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
1085 +       hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
1086  
1087         /* Check for the most weird martians, which can be not detected
1088            by fib_lookup.
1089 @@ -1445,6 +1449,12 @@ int ip_route_input_slow(struct sk_buff *
1090         if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
1091                 goto martian_destination;
1092  
1093 +       if (lsrc) {
1094 +               if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
1095 +                   ZERONET(lsrc) || LOOPBACK(lsrc))
1096 +                       goto e_inval;
1097 +       }
1098 +
1099         /*
1100          *      Now we are ready to route packet.
1101          */
1102 @@ -1454,6 +1464,10 @@ int ip_route_input_slow(struct sk_buff *
1103                 goto no_route;
1104         }
1105         free_res = 1;
1106 +       if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
1107 +               goto e_inval;
1108 +       key.iif = dev->ifindex;
1109 +       key.src = saddr;
1110  
1111         rt_cache_stat[smp_processor_id()].in_slow_tot++;
1112  
1113 @@ -1464,7 +1478,7 @@ int ip_route_input_slow(struct sk_buff *
1114  
1115         if (1) {
1116                 u32 src_map = saddr;
1117 -               if (res.r)
1118 +               if (res.r && !lsrc)
1119                         src_map = fib_rules_policy(saddr, &res, &flags);
1120  
1121                 if (res.type == RTN_NAT) {
1122 @@ -1503,8 +1517,9 @@ int ip_route_input_slow(struct sk_buff *
1123         if (res.type != RTN_UNICAST)
1124                 goto martian_destination;
1125  
1126 +       fib_select_default(&key, &res);
1127  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1128 -       if (res.fi->fib_nhs > 1 && key.oif == 0)
1129 +       if (res.fi->fib_nhs > 1)
1130                 fib_select_multipath(&key, &res);
1131  #endif
1132         out_dev = in_dev_get(FIB_RES_DEV(res));
1133 @@ -1524,6 +1539,7 @@ int ip_route_input_slow(struct sk_buff *
1134                 flags |= RTCF_DIRECTSRC;
1135  
1136         if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
1137 +           !lsrc &&
1138             (IN_DEV_SHARED_MEDIA(out_dev) ||
1139              inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
1140                 flags |= RTCF_DOREDIRECT;
1141 @@ -1550,6 +1566,7 @@ int ip_route_input_slow(struct sk_buff *
1142  #endif
1143         rth->key.src    = saddr;
1144         rth->rt_src     = saddr;
1145 +       rth->key.lsrc   = lsrc;
1146         rth->rt_gateway = daddr;
1147  #ifdef CONFIG_IP_ROUTE_NAT
1148         rth->rt_src_map = key.src;
1149 @@ -1562,6 +1579,7 @@ int ip_route_input_slow(struct sk_buff *
1150         rth->u.dst.dev  = out_dev->dev;
1151         dev_hold(rth->u.dst.dev);
1152         rth->key.oif    = 0;
1153 +       rth->key.gw     = 0;
1154         rth->rt_spec_dst= spec_dst;
1155  
1156         rth->u.dst.input = ip_forward;
1157 @@ -1572,7 +1590,8 @@ int ip_route_input_slow(struct sk_buff *
1158         rth->rt_flags = flags;
1159  
1160  #ifdef CONFIG_NET_FASTROUTE
1161 -       if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
1162 +       if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) &&
1163 +           !lsrc) {
1164                 struct net_device *odev = rth->u.dst.dev;
1165                 if (odev != dev &&
1166                     dev->accept_fastpath &&
1167 @@ -1595,6 +1614,8 @@ out:      return err;
1168  brd_input:
1169         if (skb->protocol != htons(ETH_P_IP))
1170                 goto e_inval;
1171 +       if (lsrc)
1172 +               goto e_inval;
1173  
1174         if (ZERONET(saddr))
1175                 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
1176 @@ -1627,6 +1648,7 @@ local_input:
1177  #endif
1178         rth->key.src    = saddr;
1179         rth->rt_src     = saddr;
1180 +       rth->key.lsrc   = 0;
1181  #ifdef CONFIG_IP_ROUTE_NAT
1182         rth->rt_dst_map = key.dst;
1183         rth->rt_src_map = key.src;
1184 @@ -1639,6 +1661,7 @@ local_input:
1185         rth->u.dst.dev  = &loopback_dev;
1186         dev_hold(rth->u.dst.dev);
1187         rth->key.oif    = 0;
1188 +       rth->key.gw     = 0;
1189         rth->rt_gateway = daddr;
1190         rth->rt_spec_dst= spec_dst;
1191         rth->u.dst.input= ip_local_deliver;
1192 @@ -1704,8 +1727,9 @@ martian_source:
1193         goto e_inval;
1194  }
1195  
1196 -int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
1197 -                  u8 tos, struct net_device *dev)
1198 +static inline int
1199 +ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr,
1200 +                     u8 tos, struct net_device *dev, u32 lsrc)
1201  {
1202         struct rtable * rth;
1203         unsigned        hash;
1204 @@ -1719,6 +1743,7 @@ int ip_route_input(struct sk_buff *skb, 
1205                 if (rth->key.dst == daddr &&
1206                     rth->key.src == saddr &&
1207                     rth->key.iif == iif &&
1208 +                   rth->key.lsrc == lsrc &&
1209                     rth->key.oif == 0 &&
1210  #ifdef CONFIG_IP_ROUTE_FWMARK
1211                     rth->key.fwmark == skb->nfmark &&
1212 @@ -1766,9 +1791,21 @@ int ip_route_input(struct sk_buff *skb, 
1213                 read_unlock(&inetdev_lock);
1214                 return -EINVAL;
1215         }
1216 -       return ip_route_input_slow(skb, daddr, saddr, tos, dev);
1217 +       return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
1218 +}
1219 +
1220 +int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
1221 +                  u8 tos, struct net_device *dev)
1222 +{
1223 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
1224  }
1225  
1226 +int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr,
1227 +                         u8 tos, struct net_device *dev, u32 lsrc)
1228 +{
1229 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
1230 +}
1231
1232  /*
1233   * Major route resolver routine.
1234   */
1235 @@ -1791,6 +1828,7 @@ int ip_route_output_slow(struct rtable *
1236         key.tos         = tos & IPTOS_RT_MASK;
1237         key.iif         = loopback_dev.ifindex;
1238         key.oif         = oldkey->oif;
1239 +       key.gw          = oldkey->gw;
1240  #ifdef CONFIG_IP_ROUTE_FWMARK
1241         key.fwmark      = oldkey->fwmark;
1242  #endif
1243 @@ -1880,6 +1918,7 @@ int ip_route_output_slow(struct rtable *
1244                 dev_out = &loopback_dev;
1245                 dev_hold(dev_out);
1246                 key.oif = loopback_dev.ifindex;
1247 +               key.gw = 0;
1248                 res.type = RTN_LOCAL;
1249                 flags |= RTCF_LOCAL;
1250                 goto make_route;
1251 @@ -1887,7 +1926,7 @@ int ip_route_output_slow(struct rtable *
1252  
1253         if (fib_lookup(&key, &res)) {
1254                 res.fi = NULL;
1255 -               if (oldkey->oif) {
1256 +               if (oldkey->oif && dev_out->flags&IFF_UP) {
1257                         /* Apparently, routing tables are wrong. Assume,
1258                            that the destination is on link.
1259  
1260 @@ -1930,6 +1969,7 @@ int ip_route_output_slow(struct rtable *
1261                 dev_out = &loopback_dev;
1262                 dev_hold(dev_out);
1263                 key.oif = dev_out->ifindex;
1264 +               key.gw = 0;
1265                 if (res.fi)
1266                         fib_info_put(res.fi);
1267                 res.fi = NULL;
1268 @@ -1937,13 +1977,12 @@ int ip_route_output_slow(struct rtable *
1269                 goto make_route;
1270         }
1271  
1272 +       if (res.type == RTN_UNICAST)
1273 +               fib_select_default(&key, &res);
1274  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1275 -       if (res.fi->fib_nhs > 1 && key.oif == 0)
1276 +       if (res.fi->fib_nhs > 1)
1277                 fib_select_multipath(&key, &res);
1278 -       else
1279  #endif
1280 -       if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
1281 -               fib_select_default(&key, &res);
1282  
1283         if (!key.src)
1284                 key.src = FIB_RES_PREFSRC(res);
1285 @@ -2001,7 +2040,9 @@ make_route:
1286         rth->key.tos    = tos;
1287         rth->key.src    = oldkey->src;
1288         rth->key.iif    = 0;
1289 +       rth->key.lsrc   = 0;
1290         rth->key.oif    = oldkey->oif;
1291 +       rth->key.gw     = oldkey->gw;
1292  #ifdef CONFIG_IP_ROUTE_FWMARK
1293         rth->key.fwmark = oldkey->fwmark;
1294  #endif
1295 @@ -2080,6 +2121,7 @@ int ip_route_output_key(struct rtable **
1296                     rth->key.src == key->src &&
1297                     rth->key.iif == 0 &&
1298                     rth->key.oif == key->oif &&
1299 +                   rth->key.gw == key->gw &&
1300  #ifdef CONFIG_IP_ROUTE_FWMARK
1301                     rth->key.fwmark == key->fwmark &&
1302  #endif
1303 Index: linux-2.4.35.4/net/netsyms.c
1304 ===================================================================
1305 --- linux-2.4.35.4.orig/net/netsyms.c
1306 +++ linux-2.4.35.4/net/netsyms.c
1307 @@ -260,6 +260,7 @@ EXPORT_SYMBOL(inet_register_protosw);
1308  EXPORT_SYMBOL(inet_unregister_protosw);
1309  EXPORT_SYMBOL(ip_route_output_key);
1310  EXPORT_SYMBOL(ip_route_input);
1311 +EXPORT_SYMBOL(ip_route_input_lookup);
1312  EXPORT_SYMBOL(icmp_send);
1313  EXPORT_SYMBOL(icmp_statistics);
1314  EXPORT_SYMBOL(icmp_err_convert);