--- ./bgpd/rde.c.dist	Wed Jan 10 08:56:48 2007
+++ ./bgpd/rde.c	Wed Jan 10 21:47:37 2007
@@ -682,6 +682,10 @@
 	u_int8_t		 prefixlen, safi, subtype;
 	struct bgpd_addr	 prefix;
 	struct mpattr		 mpa;
+        struct attr             *a, *b;
+        struct attr              tmp;
+        struct aspath           *new_aspath;
+        u_int32_t                aggregator_as;
 
 	peer = peer_get(imsg->hdr.peerid);
 	if (peer == NULL)	/* unknown peer, cannot happen */
@@ -726,6 +730,54 @@
 			len -= pos;
 		}
 
+ 		/* +4-Byte AS:   perform a NEW_AGGREGATOR -> AGGREGATOR substitution */
+                /* 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) {
+  					        /* Then copy over NEW value */
+                                                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) ;
+                }
+ 
+ 		/* +4-Byte AS:   perform a NEW_ASPATH -> ASPATH substitution */
+                /* 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))) {
@@ -739,7 +791,7 @@
 		if (asp->flags & F_ATTR_ASPATH &&
 		    peer->conf.enforce_as == ENFORCE_AS_ON)
 			if (peer->conf.remote_as !=
-			    aspath_neighbor(asp->aspath)) {
+			    aspath_neighbor(asp->aspath,4)) {
 				rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
 				    NULL, 0);
 				path_put(asp);
@@ -867,7 +919,7 @@
 	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)) {
 		path_put(asp);
 		return (0);
 	}
@@ -1071,6 +1123,8 @@
 	u_int8_t	 flags;
 	u_int8_t	 type;
 	u_int8_t	 tmp8;
+        u_char          *new_p;
+        u_int16_t        new_attr_len;
 
 	if (len < 3) {
 bad_len:
@@ -1125,7 +1179,7 @@
 	case ATTR_ASPATH:
 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
 			goto bad_flags;
-		if (aspath_verify(p, attr_len) != 0) {
+                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);
@@ -1133,9 +1187,35 @@
 		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 ;
+                if (!(peer->capa_received.as_4bytes)) {
+                        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:
+                /* 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;
@@ -1196,10 +1276,36 @@
 			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;
+		/* convert this to a 4 byte AS */
+                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)
@@ -1664,7 +1770,7 @@
 	for (i = 0; i <= pathtable.path_hashmask; i++) {
 		LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) {
 			if (!aspath_match(asp->aspath, req->as.type,
-			    req->as.as))
+					  req->as.as, 4))
 				continue;
 			/* match found */
 			LIST_FOREACH(p, &asp->prefix_h, path_l)
@@ -2081,7 +2187,7 @@
 /*
  * generic helper function
  */
-u_int16_t
+u_int32_t
 rde_local_as(void)
 {
 	return (conf->as);
@@ -2424,7 +2530,7 @@
 	struct rde_peer		*p;
 
 	asp = path_get();
-	asp->aspath = aspath_get(NULL, 0);
+	asp->aspath = aspath_get(NULL, 0, 4);
 	asp->origin = ORIGIN_IGP;
 	asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
 	    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
