attr_copy(&fattrs, &attrs);
fasp = path_copy(asp);
rde_update_dispatch(struct imsg *imsg){	struct rde_peer		*peer;	u_char			*p, *emsg, *mpp;	int			 pos;	u_int16_t		 afi, len, mplen;	u_int16_t		 withdrawn_len;	u_int16_t		 attrpath_len;	u_int16_t		 nlri_len, size;	u_int8_t		 prefixlen, safi, subtype;	struct bgpd_addr	 prefix;	struct attr_flags	 attrs, fattrs;	struct attr		*mpattr;	peer = peer_get(imsg->hdr.peerid);	if (peer == NULL)	/* unknown peer, cannot happen */		return (-1);	if (peer->state != PEER_UP)		return (-1);	/* peer is not yet up, cannot happen */	p = imsg->data;	memcpy(&len, p, 2);	withdrawn_len = ntohs(len);	p += 2;	if (imsg->hdr.len < IMSG_HEADER_SIZE + 2 + withdrawn_len + 2) {		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);		return (-1);	}	p += withdrawn_len;	memcpy(&len, p, 2);	attrpath_len = len = ntohs(len);	p += 2;	if (imsg->hdr.len <	    IMSG_HEADER_SIZE + 2 + withdrawn_len + 2 + attrpath_len) {		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);		return (-1);	}	if (attrpath_len != 0) { /* 0 = no NLRI information in this message */		/* parse path attributes */		attr_init(&attrs);		while (len > 0) {			if ((pos = attr_parse(p, len, &attrs,			    peer->conf.ebgp, peer->conf.enforce_as,			    peer->conf.remote_as)) < 0) {				emsg = attr_error(p, len, &attrs,				    &subtype, &size);				rde_update_err(peer, ERR_UPDATE, subtype,				    emsg, size);				attr_free(&attrs);				return (-1);			}			p += pos;			len -= pos;		}		/* check for missing but necessary attributes */		if ((subtype = attr_missing(&attrs, peer->conf.ebgp)) != 0) {			rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,			    &subtype, sizeof(u_int8_t));			attr_free(&attrs);			return (-1);		}		if (rde_reflector(peer, &attrs) != 1) {			attr_free(&attrs);			return (0);		}	}	p = imsg->data;	len = withdrawn_len;	p += 2;	/* withdraw prefix */	while (len > 0) {		if ((pos = rde_update_get_prefix(p, len, &prefix,		    &prefixlen)) == -1) {			/*			 * the rfc does not mention what we should do in			 * this case. Let's do the same as in the NLRI case.			 */			log_peer_warnx(&peer->conf, "bad withdraw prefix");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,			    NULL, 0);			if (attrpath_len != 0)				attr_free(&attrs);			return (-1);		}		if (prefixlen > 32) {			log_peer_warnx(&peer->conf, "bad withdraw prefix");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,			    NULL, 0);			if (attrpath_len != 0)				attr_free(&attrs);			return (-1);		}		p += pos;		len -= pos;		/* input filter */		if (rde_filter(peer, NULL, &prefix, prefixlen,		    DIR_IN) == ACTION_DENY)			continue;		rde_update_log("withdraw", peer, NULL, &prefix, prefixlen);		prefix_remove(peer, &prefix, prefixlen);	}	/* withdraw MP_UNREACH_NRLI if available */	if (attrpath_len != 0 &&	    (mpattr = attr_optget(&attrs, ATTR_MP_UNREACH_NLRI)) != NULL) {		mpp = mpattr->data;		mplen = mpattr->len;		memcpy(&afi, mpp, 2);		mpp += 2;		mplen -= 2;		afi = ntohs(afi);		safi = *mpp++;		mplen--;		switch (afi) {		case AFI_IPv6:			while (mplen > 0) {				if ((pos = rde_update_get_prefix6(mpp, mplen,				    &prefix, &prefixlen)) == -1) {					log_peer_warnx(&peer->conf,					    "bad IPv6 withdraw prefix");					rde_update_err(peer, ERR_UPDATE,					    ERR_UPD_OPTATTR,					    mpattr->data, mpattr->len);					attr_free(&attrs);					return (-1);				}				if (prefixlen > 128) {					log_peer_warnx(&peer->conf,					    "bad IPv6 withdraw prefix");					rde_update_err(peer, ERR_UPDATE,					    ERR_UPD_OPTATTR,					    mpattr->data, mpattr->len);					attr_free(&attrs);					return (-1);				}				mpp += pos;				mplen -= pos;				/* input filter */				if (rde_filter(peer, NULL, &prefix, prefixlen,				    DIR_IN) == ACTION_DENY)					continue;				rde_update_log("withdraw", peer, NULL,				    &prefix, prefixlen);				prefix_remove(peer, &prefix, prefixlen);			}		default:			fatalx("unsupported multipath AF");		}	}	if (attrpath_len == 0) /* 0 = no NLRI information in this message */		return (0);	/* shift to NLRI information */	p += 2 + attrpath_len;	nlri_len =	    imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;	/* aspath needs to be loop free nota bene this is not a hard error */	if (peer->conf.ebgp && !aspath_loopfree(attrs.aspath, conf->as)) {		attr_free(&attrs);		return (0);	}	/* apply default overrides */	rde_apply_set(&attrs, &peer->conf.attrset);	/* parse nlri prefix */	while (nlri_len > 0) {		if ((pos = rde_update_get_prefix(p, nlri_len, &prefix,		    &prefixlen)) == -1) {			log_peer_warnx(&peer->conf, "bad nlri prefix");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,			    NULL, 0);			attr_free(&attrs);			return (-1);		}		if (prefixlen > 32) {			log_peer_warnx(&peer->conf, "bad nlri prefix");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,			    NULL, 0);			attr_free(&attrs);			return (-1);		}		p += pos;		nlri_len -= pos;		/*		 * We need to copy attrs before calling the filter because		 * the filter may change the attributes.		 */		attr_copy(&fattrs, &attrs);		/* input filter */		if (rde_filter(peer, &fattrs, &prefix, prefixlen,		    DIR_IN) == ACTION_DENY) {			attr_free(&fattrs);			continue;		}		/* max prefix checker */		if (peer->conf.max_prefix &&		    peer->prefix_cnt >= peer->conf.max_prefix) {			log_peer_warnx(&peer->conf, "prefix limit reached");			rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX,			    NULL, 0);			attr_free(&attrs);			attr_free(&fattrs);			return (-1);		}		rde_update_log("update", peer, &fattrs, &prefix, prefixlen);		path_update(peer, &fattrs, &prefix, prefixlen);	}	/* add MP_REACH_NLRI if available */	if ((mpattr = attr_optget(&attrs, ATTR_MP_REACH_NLRI)) != NULL) {		mpp = mpattr->data;		mplen = mpattr->len;		memcpy(&afi, mpp, 2);		mpp += 2;		mplen -= 2;		afi = ntohs(afi);		safi = *mpp++;		mplen--;		if ((pos = attr_mp_nexthop_check(mpp, mplen, afi)) == -1) {			log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,			    mpattr->data, mpattr->len);			attr_free(&attrs);			return (-1);		}		mpp += pos;		mplen -= pos;		if (*p++ != NULL) {			/* XXX this is ugly */			log_peer_warnx(&peer->conf, "SNPA are not supported");			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,			    mpattr->data, mpattr->len);			attr_free(&attrs);			return (-1);		}		switch (afi) {		case AFI_IPv6:			while (mplen > 0) {				if ((pos = rde_update_get_prefix6(mpp, mplen,				    &prefix, &prefixlen)) == -1) {					log_peer_warnx(&peer->conf,					    "bad IPv6 nlri prefix");					rde_update_err(peer, ERR_UPDATE,					    ERR_UPD_OPTATTR,					    mpattr->data, mpattr->len);					attr_free(&attrs);					return (-1);				}				if (prefixlen > 128) {					rde_update_err(peer, ERR_UPDATE,					    ERR_UPD_OPTATTR,					    mpattr->data, mpattr->len);					attr_free(&attrs);					return (-1);				}				mpp += pos;				mplen -= pos;				attr_copy(&fattrs, &attrs);				/* input filter */				if (rde_filter(peer, &fattrs, &prefix,				    prefixlen, DIR_IN) == ACTION_DENY) {					attr_free(&fattrs);					continue;				}				/* XXX IPv4 and IPv6 together */				/* max prefix checker */				if (peer->conf.max_prefix &&				    peer->prefix_cnt >= peer->conf.max_prefix) {					log_peer_warnx(&peer->conf,					    "prefix limit reached");					rde_update_err(peer, ERR_CEASE,					    ERR_CEASE_MAX_PREFIX, NULL, 0);					attr_free(&attrs);					attr_free(&fattrs);					return (-1);				}				rde_update_log("update", peer, &fattrs,				    &prefix, prefixlen);				path_update(peer, &fattrs, &prefix, prefixlen);			}		default:			fatalx("unsupported AF");		}	}	/* need to free allocated attribute memory that is no longer used */	attr_free(&attrs);	return (0);}