--- bgpd/rde.c.orig	2007-01-11 15:02:39.000000000 +1000
+++ bgpd/rde.c	2007-01-11 16:32:45.000000000 +1000
@@ -626,6 +631,10 @@
 {
 	struct rde_peer		*peer;
 	struct rde_aspath	*asp = NULL, *fasp;
+	struct attr	        *a;
+        struct attr             *b;
+        struct attr              tmp;
+        struct aspath           *new_aspath;
 	u_char			*p, *mpp = NULL;
 	int			 pos = 0;
 	u_int16_t		 afi, len, mplen;
@@ -633,6 +642,7 @@
 	u_int16_t		 attrpath_len;
 	u_int16_t		 nlri_len;
 	u_int8_t		 prefixlen, safi, subtype;
+        u_int32_t                aggregator_as;
 	struct bgpd_addr	 prefix;
 	struct mpattr		 mpa;
 
@@ -668,31 +678,88 @@
 
 	if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
 		/* parse path attributes */
+	        /* allocate an empty path structure */
 		asp = path_get();
+                /* len is the length of the attribute set in bytes */
 		while (len > 0) {
-			if ((pos = rde_attr_parse(p, len, peer, asp,
-			    &mpa)) < 0) {
+
+			if ((pos = rde_attr_parse(p, len, peer, asp, &mpa)) < 0) {
 				path_put(asp);
+				/****/
+				fprintf(stderr,"Attribute parse error\n") ;
+/***/
+
 				return (-1);
 			}
 			p += pos;
 			len -= pos;
 		}
 
+                /* perform an AGGREGATOR substitution */
+                /* first check that NEW_AGGREGATOR attribute was present */
+         	if ((a = attr_optget(asp, ATTR_NEW_AGGREGATOR)) != NULL) {
+                  /* second, check that an AGGREGATOR attribute was present */
+           	  if ((b = attr_optget(asp, ATTR_AGGREGATOR)) != NULL) {
+                    /* then check that we are on a 2 byte to 4 byte boundary */
+                    /* and the AGGREGATOR is AS_TRANS */
+                    if (!(peer->capa_received.as_4bytes)) {
+                      aggregator_as = as_extract(b->data,4) ;
+                      if (aggregator_as == AS_TRANS) {
+                        memcpy(b->data,a->data,4) ;
+                        /* now re-hash the aggregator attribute by releasing it and re-adding it*/
+                        tmp.flags = b->flags ;
+	   	        tmp.type = b->flags ;
+		        tmp.len = b->len ;
+                        tmp.data = malloc(tmp.len) ;
+                        memcpy(tmp.data,b->data,tmp.len) ;
+                        attr_free(asp,b) ;
+                        attr_optadd(asp,tmp.flags,tmp.type,tmp.data,tmp.len) ;
+                        free(tmp.data) ;
+		        }
+		      }
+		    }
+                  /* now remove the NEW_AGGREGATOR attribute */
+		  attr_free(asp,a) ;
+		  }
+
+                /* attempt a PATH substitution */
+                /* first check that NEW_PATH attribute was present */
+         	if ((a = attr_optget(asp, ATTR_NEW_ASPATH)) != NULL) {
+                  /* then check that we are on a 2 byte to 4 byte boundary */
+                  if (!(peer->capa_received.as_4bytes)) {
+                    if ((new_aspath = aspath_translate(asp->aspath,a->data,a->len)) == NULL) {
+				rde_update_err(peer, ERR_UPDATE, ERR_UPD_NEWASPATH,
+				    NULL, 0);
+				path_put(asp);
+				return (-1);
+                      }
+                    aspath_put(asp->aspath) ;
+                    asp->aspath = new_aspath;
+		    }
+                  /* now remove the NEW_AS_PATH attribute */
+		  attr_free(asp,a) ;
+		  }
+
+
 		/* check for missing but necessary attributes */
-		if ((subtype = rde_attr_missing(asp, peer->conf.ebgp,
-		    nlri_len))) {
+		if ((subtype = rde_attr_missing(asp, peer->conf.ebgp, nlri_len))) {
 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
 			    &subtype, sizeof(u_int8_t));
 			path_put(asp);
+			/***/
+			fprintf(stderr,"Missing well known attributes\n");
+			/***/
 			return (-1);
 		}
 
 		/* enforce remote AS if requested */
 		if (asp->flags & F_ATTR_ASPATH &&
 		    peer->conf.enforce_as == ENFORCE_AS_ON)
-			if (peer->conf.remote_as !=
-			    aspath_neighbor(asp->aspath)) {
+		  if (peer->conf.remote_as != aspath_neighbor(asp->aspath,4)) {
+		    /***/
+		    fprintf(stderr,"Remote AS is not equal to aspath neighbor AS\n") ;
+                    fprintf(stderr,"configured remote AS is %u, Neighbor is %u\n",peer->conf.remote_as,aspath_neighbor(asp->aspath,4)) ;
+		    /***/
 				rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
 				    NULL, 0);
 				path_put(asp);
@@ -820,7 +887,10 @@
 	p += 2 + attrpath_len;
 
 	/* aspath needs to be loop free nota bene this is not a hard error */
-	if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as)) {
+	if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as,4)) {
+	  /****/
+	  fprintf(stderr,"LOOP in AS PATH\n");
+/***/
 		path_put(asp);
 		return (0);
 	}
@@ -1012,19 +1082,26 @@
 #define CHECK_FLAGS(s, t, m)	\
 	(((s) & ~(ATTR_EXTLEN | (m))) == (t))
 
+/* parse update attribute set */
 int
 rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
     struct rde_aspath *a, struct mpattr *mpa)
 {
 	struct bgpd_addr nexthop;
 	u_char		*op = p;
+        u_char          *new_p;
 	u_int32_t	 tmp32;
 	u_int16_t	 attr_len;
+        u_int16_t        new_attr_len;
 	u_int16_t	 plen = 0;
 	u_int8_t	 flags;
 	u_int8_t	 type;
 	u_int8_t	 tmp8;
 
+	/****/
+	fprintf(stderr,"rde_attr_parse - parse update\n") ;
+	/****/
+
 	if (len < 3) {
 bad_len:
 		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLEN, op, len);
@@ -1050,6 +1127,9 @@
 	/* adjust len to the actual attribute size including header */
 	len = plen + attr_len;
 
+/*****/
+	fprintf(stderr,"UPDATE: attribute: flags = %x, length=%u  attr = %u\n",flags, attr_len,type) ;
+/*****/
 	switch (type) {
 	case ATTR_UNDEF:
 		rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNSPECIFIC, NULL, 0);
@@ -1076,9 +1156,16 @@
 		a->flags |= F_ATTR_ORIGIN;
 		break;
 	case ATTR_ASPATH:
+	  /****/
+	  fprintf(stderr,"AS Path\n") ;
+          /****/
+
 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
 			goto bad_flags;
-		if (aspath_verify(p, attr_len) != 0) {
+		/****/
+                fprintf(stderr,"Received ASPATH, 4byte = %u\n",peer->capa_received.as_4bytes);
+                /****/
+		if (aspath_verify(p, attr_len, peer->capa_received.as_4bytes) < 0) {
 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
 			    NULL, 0);
 			return (-1);
@@ -1086,9 +1173,51 @@
 		if (a->flags & F_ATTR_ASPATH)
 			goto bad_list;
 		a->flags |= F_ATTR_ASPATH;
-		a->aspath = aspath_get(p, attr_len);
+                new_p = p ;
+                new_attr_len = attr_len ;
+	  /****/
+		fprintf(stderr,"peer 4byte? = %d\n",peer->capa_received.as_4bytes) ;
+          /****/
+                if (!(peer->capa_received.as_4bytes)) {
+	  /****/
+		  fprintf(stderr,"inflate the as path to 4bytes\n") ;
+          /****/
+
+                  if (!(new_p = aspath_inflate(p,attr_len,&new_attr_len))) 
+                    return(-1) ;
+                }     
+		a->aspath = aspath_get(new_p, new_attr_len,4);
+                if (!(peer->capa_received.as_4bytes)) {
+                  free(new_p) ;
+                }     
 		plen += attr_len;
 		break;
+	case ATTR_NEW_ASPATH:
+		/****/
+                fprintf(stderr,"Received NEW_ASPATH, 4byte = %u\n",peer->capa_received.as_4bytes);
+                /****/
+
+   	        /* should only receive this attr from 2 byte as (old) bgp peers */
+      	        if (peer->capa_received.as_4bytes)
+		        goto bad_flags ;
+
+		if (attr_len <= 4)
+			goto bad_len;
+
+   	        /* flag setting is optional (0x80) and transitive (0x40) */
+		if (!(flags & (ATTR_OPTIONAL | ATTR_TRANSITIVE)))
+			goto bad_flags;
+
+		if (aspath_verify(p, attr_len, 1) < 0) {
+			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NEWASPATH,
+			    NULL, 0);
+			return (-1);
+		}
+
+                /* store this attribute and perform path sustitution at the end of the
+                   attribute parse block */
+		goto optattr;
+
 	case ATTR_NEXTHOP:
 		if (attr_len != 4)
 			goto bad_len;
@@ -1149,10 +1278,35 @@
 			goto bad_flags;
 		goto optattr;
 	case ATTR_AGGREGATOR:
-		if (attr_len != 6)
+   	        if ((peer->capa_received.as_4bytes) && (attr_len != 8))
+			goto bad_len;
+   	        if ((!(peer->capa_received.as_4bytes)) && (attr_len != 6))
 			goto bad_len;
 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
 			goto bad_flags;
+                if (peer->capa_received.as_4bytes)
+ 		  goto optattr;
+                new_attr_len = attr_len + 2 ;
+                if ((new_p = malloc(new_attr_len)) == NULL)
+		  fatal("rde_attr_parse") ;
+                new_p[0] = 0; 
+                new_p[1] = 0 ;
+		memcpy(&new_p[2],p,6);
+		if (attr_optadd(a, flags, type, new_p, new_attr_len) == -1) {
+		  rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST,NULL, 0);
+		  return (-1);
+		}
+                free(new_p) ;
+		plen += attr_len;
+		break;
+	case ATTR_NEW_AGGREGATOR:
+   	        /* should only receive this attr from 2 byte as (old) bgp peers */
+      	        if (peer->capa_received.as_4bytes)
+		        goto bad_flags ;
+		if (attr_len != 8)
+			goto bad_len;
+		if (!(flags & (ATTR_OPTIONAL | ATTR_TRANSITIVE)))
+			goto bad_flags;
 		goto optattr;
 	case ATTR_COMMUNITIES:
 		if ((attr_len & 0x3) != 0)
@@ -1527,7 +1681,7 @@
 
 	for (i = 0; i <= pathtable.path_hashmask; i++) {
 		LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) {
-			if (!aspath_match(asp->aspath, a->type, a->as))
+		  if (!aspath_match(asp->aspath, a->type, a->as,4))
 				continue;
 			/* match found */
 			LIST_FOREACH(p, &asp->prefix_h, path_l)
@@ -1957,7 +2111,7 @@
 /*
  * generic helper function
  */
-u_int16_t
+u_int32_t
 rde_local_as(void)
 {
 	return (conf->as);
@@ -2261,7 +2415,7 @@
 	struct rde_peer		*p;
 
 	asp = path_get();
-	asp->aspath = aspath_get(NULL, 0);
+	asp->aspath = aspath_get(NULL, 0,3);
 	asp->origin = ORIGIN_IGP;
 	asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
 	    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
