[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 02706) IPv6 state transition error



Hello,

I faced some errors in state transition and the processing,
when the IPv6 packet below is received in the USAGI snap
kernel-2.6-s20031208.

------------------------------------------------------------------------
1. Neighbor Advertisement
===========================+=========+===================
Neighbor Advertisement     |Current  |New State
-----------+-+-+-+---------+    State+--------+----------
Destination|r|s|o|TLLA     |         |expected|result(NG)
===========+=+=+=+=========+=========+========+==========
Unicast     0 0 0 different REACHABLE STALE    REACHABLE
-----------+-+-+-+---------+---------+--------+----------
Unicast     0 1 0 different REACHABLE STALE    REACHABLE
-----------+-+-+-+---------+---------+--------+----------
Multicast   0 0 0 different REACHABLE STALE    REACHABLE
===========+=+=+=+=========+=========+========+==========
Unicast     0 0 0 none      PROBE     PROBE    STALE
-----------+-+-+-+---------+---------+--------+----------
Unicast     0 0 1 none      PROBE     PROBE    STALE
-----------+-+-+-+---------+---------+--------+----------
Unicast     0 0 0 same      PROBE     PROBE    STALE
-----------+-+-+-+---------+---------+--------+----------
Unicast     0 0 1 same      PROBE     PROBE    STALE
-----------+-+-+-+---------+---------+--------+----------
Multicast   0 0 0 same      PROBE     PROBE    STALE
-----------+-+-+-+---------+---------+--------+----------
Multicast   0 0 1 same      PROBE     PROBE    STALE
===========+=+=+=+=========+=========+========+==========
  Abbreviations
    r : Router flag   s : Solicited flag   o : Override flag
    TLLA : Target Link-Layer Address option
  Meanings of the column descriptions
    exist/none     : presence of Target Link-Layer Address option
    same/different : the link-layer address included in Target
                     Link-Layer Address option differs from that
                     in the target's Neighbor Cache entry

According to RFC2461:
  7.2.5. Receipt of Neighbor Advertisements
  .....
    If the target's Neighbor Cache entry is in any state other than
    INCOMPLETE when the advertisement is received, processing becomes
    quite a bit more complex. If the Override flag is clear and the
    supplied link-layer address differs from that in the cache, then one
    of two actions takes place: if the state of the entry is REACHABLE,
    set it to STALE, but do not update the entry in any other way;
    otherwise, the received advertisement should be ignored and MUST NOT
    update the cache. If the Override flag is set, both the Override
    flag is clear and the supplied link-layer address is the same as that
    in the cache, or no Target Link-layer address option was supplied,
    the received advertisement MUST update the Neighbor Cache entry as
    follows:
  .....
     - If the Solicited flag is set, the state of the entry MUST be set
       to REACHABLE. If the Solicited flag is zero and the link-layer
       address was updated with a different address the state MUST be set
       to STALE. Otherwise, the entry's state remains unchanged.
------------------------------------------------------------------------
------------------------------------------------------------------------
2. Neighbor Solicitation
=====================+=======+===================
Neighbor Solicitation|Current|New State
------------+--------+  State+--------+----------
Destination |SLLA    |       |expected|result(NG)
============+========+=======+========+==========
Unicast      none     PROBE   PROBE    STALE
------------+--------+-------+--------+----------
Unicast      same     PROBE   PROBE    STALE
------------+--------+-------+--------+----------
Multicast    same     PROBE   PROBE    STALE
============+========+=======+========+==========
  Abbreviations
    SLLA : Source Link-Layer Address option
  Meanings of the column descriptions
    exist/none     : presence of Source Link-Layer Address option
    same/different : the link-layer address included in Source
                     Link-Layer Address option differs from that
                     in the target's Neighbor Cache entry

According to RFC2461:
  7.2.3. Receipt of Neighbor Solicitations
  .....
    If the Target Address is tentative, the Neighbor Solicitation should
    be processed as described in [ADDRCONF]. Otherwise, the following
    description applies. If the Source Address is not the unspecified
    address and, on link layers that have addresses, the solicitation
    includes a Source Link-Layer Address option, then the recipient
    SHOULD create or update the Neighbor Cache entry for the IP Source
    Address of the solicitation. If an entry does not already exist, the
    node SHOULD create a new one and set its reachability state to STALE
    as specified in Section 7.3.3. If an entry already exists, and the
    cached link-layer address differs from the one in the received Source
    Link-Layer option, the cached address should be replaced by the
    received address and the entry's reachability state MUST be set to
    STALE.
------------------------------------------------------------------------
------------------------------------------------------------------------
3. Router Advertisement
====================+=======+===================
Router Advertisement|Current|New State
--------------------+  State|
Source Link-Layer   |       +--------+----------
     Address option |       |expected|result(NG)
====================+=======+========+==========
none                 PROBE   PROBE    STALE
--------------------+-------+--------+----------
same                 PROBE   PROBE    STALE
====================+=======+========+==========
  Meanings of the column descriptions
    exist/none     : presence of Source Link-Layer Address option
    same/different : the link-layer address included in Source
                     Link-Layer Address option differs from that
                     in the target's Neighbor Cache entry

According to RFC2461:
  6.3.4. Processing Received Router Advertisements
  .....
    After extracting information from the fixed part of the Router
    Advertisement message, the advertisement is scanned for valid
    options. If the advertisement contains a Source Link-Layer Address
    option the link-layer address SHOULD be recorded in the Neighbor
    Cache entry for the router (creating an entry if necessary) and the
    IsRouter flag in the Neighbor Cache entry MUST be set to TRUE. If no
    Source Link-Layer Address is included, but a corresponding Neighbor
    Cache entry exists, its IsRouter flag MUST be set to TRUE. The
    IsRouter flag is used by Neighbor Unreachability Detection to
    determine when a router changes to being a host (i.e., no longer
    capable of forwarding packets). If a Neighbor Cache entry is created
    for the router its reachability state MUST be set to STALE as
    specified in Section 7.3.3. If a cache entry already exists and is
    updated with a different link-layer address the reachability state
    MUST also be set to STALE.
------------------------------------------------------------------------
------------------------------------------------------------------------
4. Router Solicitation
===================+==========+===================+====================
Router Solicitation|Current   |New State          |link-layer address
-------------------+     State|                   |        in the cache
Source Link-Layer  |          +--------+----------+---------+----------
    Address option |          |expected|result(NG)|expected |result(NG)
===================+==========+========+==========+=========+==========
exist               NONCE      STALE    NONCE      unchanged unchanged
===================+==========+========+==========+=========+==========
exist               INCOMPLETE STALE    INCOMPLETE unchanged unchanged
===================+==========+========+==========+=========+==========
different           REACHABLE  STALE    REACHABLE  updated   unchanged
===================+==========+========+==========+=========+==========
different           STALE      STALE    STALE      updated   unchanged
===================+==========+========+==========+=========+==========
different           PROBE      STALE    PROBE      updated   unchanged
===================+==========+========+==========+=========+==========
  Meanings of the column descriptions
    exist/none     : presence of Source Link-Layer Address option
    same/different : the link-layer address included in Source
                     Link-Layer Address option differs from that
                     in the target's Neighbor Cache entry

According to RFC2461:
  6.2.6.  Processing Router Solicitations
  .....
    Router Solicitations in which the Source Address is the unspecified
    address MUST NOT update the router's Neighbor Cache; solicitations
    with a proper source address update the Neighbor Cache as follows. If
    the router already has a Neighbor Cache entry for the solicitation's
    sender, the solicitation contains a Source Link-Layer Address option,
    and the received link-layer address differs from that already in the
    cache, the link-layer address SHOULD be updated in the appropriate
    Neighbor Cache entry, and its reachability state MUST also be set to
    STALE.  If there is no existing Neighbor Cache entry for the
    solicitation's sender, the router creates one, installs the link-
    layer address and sets its reachability state to STALE as specified
    in Section 7.3.3.  Whether or not a Source Link-Layer Address option
    is provided, if a Neighbor Cache entry for the solicitation's sender
    exists (or is created) the entry's IsRouter flag MUST be set to
    FALSE.
------------------------------------------------------------------------
------------------------------------------------------------------------
5. Redirect
================================+=======+===================
Redirect Option                 |Current|New state
------+-------------------------+  State+--------+----------
TLLA  |Redirected header option |       |expected|result(NG)
======+=========================+=======+========+==========
none   none                      PROBE   PROBE    STALE
------+-------------------------+-------+--------+----------
same   none                      PROBE   PROBE    STALE
======+=========================+=======+========+==========
  Abbreviations
    TLLA : Target Link-Layer Address option
  Meanings of the column descriptions
    exist/none     : presence of Target Link-Layer Address option
    same/different : the link-layer address included in Target
                     Link-Layer Address option differs from that
                     in the target's Neighbor Cache entry

According to RFC2461:
  8.3. Host Specification
  .....
    If the redirect contains a Target Link-Layer Address option the host
    either creates or updates the Neighbor Cache entry for the target.
    In both cases the cached link-layer address is copied from the Target
    Link-Layer Address option. If a Neighbor Cache entry is created for
    the target its reachability state MUST be set to STALE as specified
    in Section 7.3.3. If a cache entry already existed and it is updated
    with a different link-layer address, its reachability state MUST also
    be set to STALE. If the link-layer address is the same as that
    already in the cache, the cache entry's state remains unchanged.
------------------------------------------------------------------------

I made a patch and fixed the problem.

------------------------------------------------------------------------
diff -Nuar linux26.orig/include/net/neighbour.h linux26/include/net/neighbour.h
--- linux26.orig/include/net/neighbour.h	2003-08-23 17:02:16.000000000 +0900
+++ linux26/include/net/neighbour.h	2003-12-18 15:46:39.000000000 +0900
@@ -170,6 +170,14 @@
 	struct pneigh_entry	*phash_buckets[PNEIGH_HASHMASK+1];
 };

+#define NEIGH_UPDATE_TYPE_ADMIN		0
+#define NEIGH_UPDATE_TYPE_ARP		1
+#define NEIGH_UPDATE_TYPE_IP6NS		2
+#define NEIGH_UPDATE_TYPE_IP6NA		3
+#define NEIGH_UPDATE_TYPE_IP6RS		4
+#define NEIGH_UPDATE_TYPE_IP6RA		5
+#define NEIGH_UPDATE_TYPE_IP6REDIRECT	6
+
 extern void			neigh_table_init(struct neigh_table *tbl);
 extern int			neigh_table_clear(struct neigh_table *tbl);
 extern struct neighbour *	neigh_lookup(struct neigh_table *tbl,
diff -Nuar linux26.orig/net/core/neighbour.c linux26/net/core/neighbour.c
--- linux26.orig/net/core/neighbour.c	2003-11-11 05:07:19.000000000 +0900
+++ linux26/net/core/neighbour.c	2003-12-18 15:46:39.000000000 +0900
@@ -848,8 +848,6 @@
 		if (old & NUD_VALID) {
 			if (!memcmp(lladdr, neigh->ha, dev->addr_len))
 				lladdr = neigh->ha;
-			else if (!override)
-				goto out;
 		}
 	} else {
 		/* No address is supplied; if we know something,
@@ -861,28 +859,86 @@
 		lladdr = neigh->ha;
 	}

-	neigh_sync(neigh);
-	old = neigh->nud_state;
-	if (new & NUD_CONNECTED)
-		neigh->confirmed = jiffies;
-	neigh->updated = jiffies;
-
 	/* If entry was valid and address is not changed,
 	   do not change entry state, if new one is STALE.
 	 */
 	err = 0;
-	if ((old & NUD_VALID) && lladdr == neigh->ha &&
-	    (new == old || (new == NUD_STALE && (old & NUD_CONNECTED))))
-		goto out;
+	if (old&NUD_VALID) {
+		if (lladdr != neigh->ha && !override) {
+			switch(arp) {
+			case NEIGH_UPDATE_TYPE_IP6NA:
+				if (old&NUD_CONNECTED) {
+					new = NUD_STALE;
+					lladdr = neigh->ha;
+					break;
+				}
+				/*NOBREAK*/
+			case NEIGH_UPDATE_TYPE_ADMIN:
+			case NEIGH_UPDATE_TYPE_ARP:
+			default:
+				goto out;
+			}
+		} else {
+			switch(arp) {
+			case NEIGH_UPDATE_TYPE_IP6NS:
+			case NEIGH_UPDATE_TYPE_IP6NA:
+			case NEIGH_UPDATE_TYPE_IP6RS:
+			case NEIGH_UPDATE_TYPE_IP6RA:
+			case NEIGH_UPDATE_TYPE_IP6REDIRECT:
+				if (new == NUD_STALE) {
+					if (lladdr == neigh->ha) {
+						new = old;
+					}
+				}
+				break;
+			case NEIGH_UPDATE_TYPE_ADMIN:
+			case NEIGH_UPDATE_TYPE_ARP:
+			default:
+				if (new == old) {
+					lladdr = neigh->ha;
+				} else if (lladdr == neigh->ha &&
+					   new == NUD_STALE &&
+					   (old&NUD_CONNECTED)) {
+					new = old;
+				}
+			}
+		}
+	}
+
+	if (new != old) {
+		if (new&NUD_IN_TIMER) {
+			unsigned long next = jiffies;
+			switch(new) {
+			case NUD_REACHABLE:
+				next += neigh->parms->reachable_time;
+				break;
+			default:
+				/*XXX*/
+			}
+			if (old&NUD_IN_TIMER) {
+				mod_timer(&neigh->timer, next);
+			} else {
+				neigh_hold(neigh);
+				neigh->timer.expires = next;
+				add_timer(&neigh->timer);
+			}
+		} else {
+			neigh_del_timer(neigh);
+		}
+		neigh->nud_state = new;
+	}
+
+	if (new != old || lladdr != neigh->ha) {
+		if (new&NUD_CONNECTED)
+			neigh->confirmed = jiffies;
+		else
+			neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1);
+	}

-	neigh_del_timer(neigh);
-	neigh->nud_state = new;
 	if (lladdr != neigh->ha) {
+		neigh->updated = jiffies;
 		memcpy(&neigh->ha, lladdr, dev->addr_len);
 		neigh_update_hhs(neigh);
-		if (!(new & NUD_CONNECTED))
-			neigh->confirmed = jiffies -
-				      (neigh->parms->base_reachable_time << 1);
 #ifdef CONFIG_ARPD
 		notify = 1;
 #endif
diff -Nuar linux26.orig/net/ipv6/ndisc.c linux26/net/ipv6/ndisc.c
--- linux26.orig/net/ipv6/ndisc.c	2003-10-30 14:49:30.000000000 +0900
+++ linux26/net/ipv6/ndisc.c	2003-12-18 15:46:39.000000000 +0900
@@ -813,7 +813,12 @@
 			 *	for the source address
 			 */

-			neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+			neigh = __neigh_lookup(&nd_tbl, saddr, dev,
+					       lladdr || !dev->addr_len);
+			if (neigh) {
+				neigh_update(neigh, lladdr, NUD_STALE,
+					     1, NEIGH_UPDATE_TYPE_IP6NS);
+			}

 			if (neigh || !dev->hard_header) {
 				ndisc_send_na(dev, neigh, saddr, &ifp->addr,
@@ -856,7 +861,12 @@
 			 *   for the source address
 			 */

-			neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
+			neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev,
+					       lladdr || !dev->addr_len);
+			if (neigh) {
+				neigh_update(neigh, lladdr, NUD_STALE,
+					     1, NEIGH_UPDATE_TYPE_IP6NS);
+			}

 			if (neigh || !dev->hard_header) {
 				ndisc_send_na(dev, neigh, saddr,
@@ -886,7 +896,12 @@
 					nd_tbl.stats.rcv_probes_ucast++;
 					
 				if (addr_type & IPV6_ADDR_UNICAST) {
-					neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+					neigh = __neigh_lookup(&nd_tbl, saddr, dev,
+							       lladdr || !dev->addr_len);
+					if (neigh) {
+						neigh_update(neigh, lladdr, NUD_STALE,
+							     1, NEIGH_UPDATE_TYPE_IP6NS);
+					}

 					if (neigh) {
 						ndisc_send_na(dev, neigh, saddr, &msg->target,
@@ -994,7 +1009,7 @@

 		neigh_update(neigh, lladdr,
 			     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
-			     msg->icmph.icmp6_override, 1);
+			     msg->icmph.icmp6_override, NEIGH_UPDATE_TYPE_IP6NA);
 		neigh_release(neigh);
 	}
 }
@@ -1164,7 +1179,8 @@
 				goto out;
 			}
 		}
-		neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
+		neigh_update(neigh, lladdr, NUD_STALE, 1,
+			     NEIGH_UPDATE_TYPE_IP6RA);
 	}

 	if (ndopts.nd_opts_pi) {
@@ -1297,7 +1313,8 @@
 	if (neigh) {
 		if (neigh->nud_state&NUD_VALID) {
 			if (!rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link))
-				neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
+				neigh_update(neigh, lladdr, NUD_STALE, 1,
+					     NEIGH_UPDATE_TYPE_IP6REDIRECT);
 		} else
 			__neigh_event_send(neigh, NULL);
 		neigh_release(neigh);
------------------------------------------------------------------------

Regards,
Hiroaki Kago