jamal wrote:
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 64d3938..c8a98ca 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -860,57 +860,70 @@ EXPORT_SYMBOL(xfrm_policy_flush);
>  int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, 
> void*),
>                    void *data)
>  {
> -     struct xfrm_policy *pol;
>       struct hlist_node *entry;
> -     int dir, count, error;
> +     int dir = 0, last_dir = 0, count = 0, error = -ENOENT;
> +     struct xfrm_policy *pol = NULL, *send_pol = NULL, *last_pol = NULL;
>  
>       read_lock_bh(&xfrm_policy_lock);
> -     count = 0;
> +
>       for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
>               struct hlist_head *table = xfrm_policy_bydst[dir].table;
>               int i;
>  
>               hlist_for_each_entry(pol, entry,
>                                    &xfrm_policy_inexact[dir], bydst) {
> -                     if (pol->type == type)
> -                             count++;
> -             }
> -             for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
> -                     hlist_for_each_entry(pol, entry, table + i, bydst) {
> -                             if (pol->type == type)
> -                                     count++;
> +                     if (count && send_pol && send_pol != last_pol) {
> +                             error = func(send_pol, dir % XFRM_POLICY_MAX, 
> count, data);
> +                             if (error)
> +                                     goto out;
> +                             send_pol = NULL;
>                       }
> -             }
> -     }
> -
> -     if (count == 0) {
> -             error = -ENOENT;
> -             goto out;
> -     }
> -
> -     for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
> -             struct hlist_head *table = xfrm_policy_bydst[dir].table;
> -             int i;
>  
> -             hlist_for_each_entry(pol, entry,
> -                                  &xfrm_policy_inexact[dir], bydst) {
>                       if (pol->type != type)
>                               continue;
> -                     error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
> -                     if (error)
> -                             goto out;
> +
> +                     if (!count) {
> +                             last_pol = send_pol = pol;
> +                     } else {
> +                             send_pol = last_pol;
> +                             last_pol = pol;
> +                     }
> +
> +                     last_dir = dir;
> +                     count++;
>               }
> +
>               for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
>                       hlist_for_each_entry(pol, entry, table + i, bydst) {
> +                             if (count && send_pol && send_pol != last_pol) {
> +                                     error = func(send_pol, dir % 
> XFRM_POLICY_MAX, count, data);
> +                                     send_pol = NULL;
> +                                     if (error)
> +                                             goto out;
> +                             }
>                               if (pol->type != type)
>                                       continue;
> -                             error = func(pol, dir % XFRM_POLICY_MAX, 
> --count, data);
> -                             if (error)
> -                                     goto out;
> +                             if (!count) {
> +                                     last_pol = send_pol = pol;
> +                             } else {
> +                                     send_pol = last_pol;
> +                                     last_pol = pol;
> +                             }
> +                             last_dir = dir;
> +                             count++;
>                       }
>               }
>       }
> -     error = 0;
> +
> +     if (send_pol && send_pol != last_pol) {
> +             error = func(send_pol, last_dir % XFRM_POLICY_MAX, count, data);
> +     }
> +
> +     if (count) {
> +             BUG_TRAP(last_pol == NULL);
> +             error = func(send_pol, last_dir % XFRM_POLICY_MAX, 0, data);
> +     }
> +
>  out:
>       read_unlock_bh(&xfrm_policy_lock);
>       return error;


A few cases that will behave incorrectly:

- two policies in xfrm_policy_inexact with the same direction:
  after the first iteration we have last_pol = send_pol = first policy
  and no messages sent, after the second iteration we have
  send_pol = first policy, last_pol = second policy and still no
  messages sent. Since send_pol && send_pol != last_pol, the
  second to last block will send send_pol with last_dir, since
  count > 0 the last block will send send_pol again. So we get
  two times the first policy and zero times the second one.

- same case as above, but policies in opposite directions. The
  first policy will again be sent twice, but with last_dir, which
  is the direction of the second policy.

- three policies in xfrm_policy_inexact, two with similar direction,
  one with opposite direction. The first two iterations look similar
  and no policies are dumped, during the third iteration we have
  count && send_pol && send_pol != last_pol. So send_pol (the
  first policy) is sent, but with direction dir, which is at that
  time the opposite direction of the policy.


I guess its easy to construct more cases. In general I don't see
how remebering only the last direction can work since two policies
with potentially different directions are remembered. Within the
loop you always use dir, which also look wrong.

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to