xref: /openbsd-src/usr.sbin/bgpd/rde_attr.c (revision e386eeb169001ba40fb5933f7e7f4e432772e268)
1*e386eeb1Sclaudio /*	$OpenBSD: rde_attr.c,v 1.135 2024/09/10 09:38:45 claudio Exp $ */
268f72004Sclaudio 
368f72004Sclaudio /*
468f72004Sclaudio  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
5280f24a4Sphessler  * Copyright (c) 2016 Job Snijders <job@instituut.net>
6280f24a4Sphessler  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
768f72004Sclaudio  *
868f72004Sclaudio  * Permission to use, copy, modify, and distribute this software for any
968f72004Sclaudio  * purpose with or without fee is hereby granted, provided that the above
1068f72004Sclaudio  * copyright notice and this permission notice appear in all copies.
1168f72004Sclaudio  *
1268f72004Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1368f72004Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1468f72004Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1568f72004Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1668f72004Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1768f72004Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1868f72004Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1968f72004Sclaudio  */
2068f72004Sclaudio 
2168f72004Sclaudio #include <sys/queue.h>
2268f72004Sclaudio 
235bdfc2adSclaudio #include <endian.h>
24b2cd1366Sguenther #include <limits.h>
2568f72004Sclaudio #include <stdlib.h>
2668f72004Sclaudio #include <string.h>
2768f72004Sclaudio 
2868f72004Sclaudio #include "bgpd.h"
2968f72004Sclaudio #include "rde.h"
305e3f6f95Sbenno #include "log.h"
3168f72004Sclaudio 
3268f72004Sclaudio int
3339386878Sclaudio attr_writebuf(struct ibuf *buf, uint8_t flags, uint8_t type, void *data,
3439386878Sclaudio     uint16_t data_len)
358a72043eSclaudio {
368a72043eSclaudio 	u_char	hdr[4];
378a72043eSclaudio 
38caea8f61Sclaudio 	flags &= ~ATTR_DEFMASK;
398a72043eSclaudio 	if (data_len > 255) {
408a72043eSclaudio 		flags |= ATTR_EXTLEN;
418a72043eSclaudio 		hdr[2] = (data_len >> 8) & 0xff;
428a72043eSclaudio 		hdr[3] = data_len & 0xff;
438a72043eSclaudio 	} else {
448a72043eSclaudio 		hdr[2] = data_len & 0xff;
458a72043eSclaudio 	}
468a72043eSclaudio 
478a72043eSclaudio 	hdr[0] = flags;
488a72043eSclaudio 	hdr[1] = type;
498a72043eSclaudio 
50e39620e5Snicm 	if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
518a72043eSclaudio 		return (-1);
528cd4606cSclaudio 	if (data != NULL && ibuf_add(buf, data, data_len) == -1)
538a72043eSclaudio 		return (-1);
548a72043eSclaudio 	return (0);
558a72043eSclaudio }
568a72043eSclaudio 
5755e823c7Sclaudio /* optional attribute specific functions */
581f826a12Sclaudio struct attr	*attr_alloc(uint8_t, uint8_t, void *, uint16_t);
591f826a12Sclaudio struct attr	*attr_lookup(uint8_t, uint8_t, void *, uint16_t);
6055e823c7Sclaudio void		 attr_put(struct attr *);
6155e823c7Sclaudio 
621f826a12Sclaudio static inline int	 attr_diff(struct attr *, struct attr *);
6355e823c7Sclaudio 
641f826a12Sclaudio RB_HEAD(attr_tree, attr)	attrtable = RB_INITIALIZER(&attr);
651f826a12Sclaudio RB_GENERATE_STATIC(attr_tree, attr, entry, attr_diff);
667e8b30f9Stedu 
6755e823c7Sclaudio 
6855e823c7Sclaudio void
6955e823c7Sclaudio attr_shutdown(void)
7055e823c7Sclaudio {
711f826a12Sclaudio 	if (!RB_EMPTY(&attrtable))
721f826a12Sclaudio 		log_warnx("%s: free non-free attr table", __func__);
734670f09dSclaudio }
744670f09dSclaudio 
75e22cf8c8Sclaudio int
7639386878Sclaudio attr_optadd(struct rde_aspath *asp, uint8_t flags, uint8_t type,
7739386878Sclaudio     void *data, uint16_t len)
7868f72004Sclaudio {
7939386878Sclaudio 	uint8_t		 l;
8055e823c7Sclaudio 	struct attr	*a, *t;
8188a24b5dShenning 	void		*p;
8268f72004Sclaudio 
8327e1f569Sclaudio 	/* known optional attributes were validated previously */
840422f938Sclaudio 	if ((a = attr_lookup(flags, type, data, len)) == NULL)
8555e823c7Sclaudio 		a = attr_alloc(flags, type, data, len);
8655e823c7Sclaudio 
8755e823c7Sclaudio 	/* attribute allowed only once */
8855e823c7Sclaudio 	for (l = 0; l < asp->others_len; l++) {
8955e823c7Sclaudio 		if (asp->others[l] == NULL)
9055e823c7Sclaudio 			break;
91f1a84a52Sclaudio 		if (type == asp->others[l]->type) {
92f1a84a52Sclaudio 			if (a->refcnt == 0)
93f1a84a52Sclaudio 				attr_put(a);
9455e823c7Sclaudio 			return (-1);
9555e823c7Sclaudio 		}
96f1a84a52Sclaudio 	}
9755e823c7Sclaudio 
9855e823c7Sclaudio 	/* add attribute to the table but first bump refcnt */
9955e823c7Sclaudio 	a->refcnt++;
10055e823c7Sclaudio 	rdemem.attr_refs++;
10155e823c7Sclaudio 
10255e823c7Sclaudio 	for (l = 0; l < asp->others_len; l++) {
10355e823c7Sclaudio 		if (asp->others[l] == NULL) {
10455e823c7Sclaudio 			asp->others[l] = a;
10555e823c7Sclaudio 			return (0);
10655e823c7Sclaudio 		}
10755e823c7Sclaudio 		/* list is sorted */
10855e823c7Sclaudio 		if (a->type < asp->others[l]->type) {
10955e823c7Sclaudio 			t = asp->others[l];
11055e823c7Sclaudio 			asp->others[l] = a;
11155e823c7Sclaudio 			a = t;
11255e823c7Sclaudio 		}
11355e823c7Sclaudio 	}
11455e823c7Sclaudio 
11555e823c7Sclaudio 	/* no empty slot found, need to realloc */
116fc7c6d34Sclaudio 	if (asp->others_len == UCHAR_MAX)
117fc7c6d34Sclaudio 		fatalx("attr_optadd: others_len overflow");
118fc7c6d34Sclaudio 
11955e823c7Sclaudio 	asp->others_len++;
120b795643eSderaadt 	if ((p = reallocarray(asp->others,
121b795643eSderaadt 	    asp->others_len, sizeof(struct attr *))) == NULL)
12267fd830bSclaudio 		fatal("%s", __func__);
12388a24b5dShenning 	asp->others = p;
12455e823c7Sclaudio 
12555e823c7Sclaudio 	/* l stores the size of others before resize */
12655e823c7Sclaudio 	asp->others[l] = a;
12755e823c7Sclaudio 	return (0);
12855e823c7Sclaudio }
12955e823c7Sclaudio 
13055e823c7Sclaudio struct attr *
13139386878Sclaudio attr_optget(const struct rde_aspath *asp, uint8_t type)
13255e823c7Sclaudio {
13339386878Sclaudio 	uint8_t l;
13455e823c7Sclaudio 
13555e823c7Sclaudio 	for (l = 0; l < asp->others_len; l++) {
13655e823c7Sclaudio 		if (asp->others[l] == NULL)
13755e823c7Sclaudio 			break;
13855e823c7Sclaudio 		if (type == asp->others[l]->type)
13955e823c7Sclaudio 			return (asp->others[l]);
14055e823c7Sclaudio 		if (type < asp->others[l]->type)
14155e823c7Sclaudio 			break;
14255e823c7Sclaudio 	}
14355e823c7Sclaudio 	return (NULL);
14455e823c7Sclaudio }
14555e823c7Sclaudio 
14655e823c7Sclaudio void
1475d2e648fSclaudio attr_copy(struct rde_aspath *t, const struct rde_aspath *s)
14855e823c7Sclaudio {
14939386878Sclaudio 	uint8_t l;
15055e823c7Sclaudio 
15155e823c7Sclaudio 	if (t->others != NULL)
15255e823c7Sclaudio 		attr_freeall(t);
15355e823c7Sclaudio 
15490b77beaSclaudio 	t->others_len = s->others_len;
15590b77beaSclaudio 	if (t->others_len == 0) {
15690b77beaSclaudio 		t->others = NULL;
15790b77beaSclaudio 		return;
15890b77beaSclaudio 	}
15990b77beaSclaudio 
16055e823c7Sclaudio 	if ((t->others = calloc(s->others_len, sizeof(struct attr *))) == 0)
16167fd830bSclaudio 		fatal("%s", __func__);
16255e823c7Sclaudio 
16355e823c7Sclaudio 	for (l = 0; l < t->others_len; l++) {
16455e823c7Sclaudio 		if (s->others[l] == NULL)
16555e823c7Sclaudio 			break;
16655e823c7Sclaudio 		s->others[l]->refcnt++;
16755e823c7Sclaudio 		rdemem.attr_refs++;
16855e823c7Sclaudio 		t->others[l] = s->others[l];
16955e823c7Sclaudio 	}
17055e823c7Sclaudio }
17155e823c7Sclaudio 
1721f826a12Sclaudio static inline int
17355e823c7Sclaudio attr_diff(struct attr *oa, struct attr *ob)
17455e823c7Sclaudio {
17555e823c7Sclaudio 	int	r;
17655e823c7Sclaudio 
1777e5c8c52Sclaudio 	if (ob == NULL)
1787e5c8c52Sclaudio 		return (1);
1797e5c8c52Sclaudio 	if (oa == NULL)
1807e5c8c52Sclaudio 		return (-1);
1810422f938Sclaudio 	if (oa->flags > ob->flags)
1820422f938Sclaudio 		return (1);
1830422f938Sclaudio 	if (oa->flags < ob->flags)
1840422f938Sclaudio 		return (-1);
18555e823c7Sclaudio 	if (oa->type > ob->type)
18655e823c7Sclaudio 		return (1);
18755e823c7Sclaudio 	if (oa->type < ob->type)
18855e823c7Sclaudio 		return (-1);
18955e823c7Sclaudio 	if (oa->len > ob->len)
19055e823c7Sclaudio 		return (1);
19155e823c7Sclaudio 	if (oa->len < ob->len)
19255e823c7Sclaudio 		return (-1);
19355e823c7Sclaudio 	r = memcmp(oa->data, ob->data, oa->len);
19455e823c7Sclaudio 	if (r > 0)
19555e823c7Sclaudio 		return (1);
19655e823c7Sclaudio 	if (r < 0)
19755e823c7Sclaudio 		return (-1);
1981f826a12Sclaudio 	return (0);
19955e823c7Sclaudio }
20055e823c7Sclaudio 
20155e823c7Sclaudio int
20255e823c7Sclaudio attr_compare(struct rde_aspath *a, struct rde_aspath *b)
20355e823c7Sclaudio {
20439386878Sclaudio 	uint8_t l, min;
20555e823c7Sclaudio 
20655e823c7Sclaudio 	min = a->others_len < b->others_len ? a->others_len : b->others_len;
20755e823c7Sclaudio 	for (l = 0; l < min; l++)
20855e823c7Sclaudio 		if (a->others[l] != b->others[l])
20955e823c7Sclaudio 			return (attr_diff(a->others[l], b->others[l]));
21055e823c7Sclaudio 
21155e823c7Sclaudio 	if (a->others_len < b->others_len) {
21255e823c7Sclaudio 		for (; l < b->others_len; l++)
21355e823c7Sclaudio 			if (b->others[l] != NULL)
21455e823c7Sclaudio 				return (-1);
2159b79c7ebSclaudio 	} else if (a->others_len > b->others_len) {
21655e823c7Sclaudio 		for (; l < a->others_len; l++)
21755e823c7Sclaudio 			if (a->others[l] != NULL)
21855e823c7Sclaudio 				return (1);
21955e823c7Sclaudio 	}
22055e823c7Sclaudio 
22155e823c7Sclaudio 	return (0);
22255e823c7Sclaudio }
22355e823c7Sclaudio 
22455e823c7Sclaudio void
225ec8297f3Sclaudio attr_free(struct rde_aspath *asp, struct attr *attr)
226ec8297f3Sclaudio {
22739386878Sclaudio 	uint8_t l;
228ec8297f3Sclaudio 
229ec8297f3Sclaudio 	for (l = 0; l < asp->others_len; l++)
230ec8297f3Sclaudio 		if (asp->others[l] == attr) {
231ec8297f3Sclaudio 			attr_put(asp->others[l]);
2327e5c8c52Sclaudio 			for (++l; l < asp->others_len; l++)
2337e5c8c52Sclaudio 				asp->others[l - 1] = asp->others[l];
2347e5c8c52Sclaudio 			asp->others[asp->others_len - 1] = NULL;
235ec8297f3Sclaudio 			return;
236ec8297f3Sclaudio 		}
237ec8297f3Sclaudio 
2387e5c8c52Sclaudio 	/* no realloc() because the slot may be reused soon */
239ec8297f3Sclaudio }
240ec8297f3Sclaudio 
241ec8297f3Sclaudio void
24255e823c7Sclaudio attr_freeall(struct rde_aspath *asp)
24355e823c7Sclaudio {
24439386878Sclaudio 	uint8_t l;
24555e823c7Sclaudio 
24655e823c7Sclaudio 	for (l = 0; l < asp->others_len; l++)
24755e823c7Sclaudio 		attr_put(asp->others[l]);
24855e823c7Sclaudio 
24955e823c7Sclaudio 	free(asp->others);
25055e823c7Sclaudio 	asp->others = NULL;
25155e823c7Sclaudio 	asp->others_len = 0;
25255e823c7Sclaudio }
25355e823c7Sclaudio 
25455e823c7Sclaudio struct attr *
2551f826a12Sclaudio attr_alloc(uint8_t flags, uint8_t type, void *data, uint16_t len)
25655e823c7Sclaudio {
25755e823c7Sclaudio 	struct attr	*a;
25855e823c7Sclaudio 
25968f72004Sclaudio 	a = calloc(1, sizeof(struct attr));
26068f72004Sclaudio 	if (a == NULL)
26167fd830bSclaudio 		fatal("%s", __func__);
2626b5f6ff8Sclaudio 	rdemem.attr_cnt++;
263af6b2e43Sclaudio 
264caea8f61Sclaudio 	flags &= ~ATTR_DEFMASK;	/* normalize mask */
26568f72004Sclaudio 	a->flags = flags;
26668f72004Sclaudio 	a->type = type;
26768f72004Sclaudio 	a->len = len;
26868f72004Sclaudio 	if (len != 0) {
26955e823c7Sclaudio 		if ((a->data = malloc(len)) == NULL)
27067fd830bSclaudio 			fatal("%s", __func__);
271af6b2e43Sclaudio 
272fc4470d5Sclaudio 		rdemem.attr_dcnt++;
2736b5f6ff8Sclaudio 		rdemem.attr_data += len;
27468f72004Sclaudio 		memcpy(a->data, data, len);
275e22cf8c8Sclaudio 	} else
276e22cf8c8Sclaudio 		a->data = NULL;
277e22cf8c8Sclaudio 
2781f826a12Sclaudio 	if (RB_INSERT(attr_tree, &attrtable, a) != NULL)
2791f826a12Sclaudio 		fatalx("corrupted attr tree");
28055e823c7Sclaudio 
28155e823c7Sclaudio 	return (a);
28268f72004Sclaudio }
28368f72004Sclaudio 
2840df2230cSclaudio struct attr *
2851f826a12Sclaudio attr_lookup(uint8_t flags, uint8_t type, void *data, uint16_t len)
2860df2230cSclaudio {
2871f826a12Sclaudio 	struct attr		needle;
2880df2230cSclaudio 
289caea8f61Sclaudio 	flags &= ~ATTR_DEFMASK;	/* normalize mask */
2907e8b30f9Stedu 
2911f826a12Sclaudio 	needle.flags = flags;
2921f826a12Sclaudio 	needle.type = type;
2931f826a12Sclaudio 	needle.len = len;
2941f826a12Sclaudio 	needle.data = data;
2951f826a12Sclaudio 	return RB_FIND(attr_tree, &attrtable, &needle);
2960df2230cSclaudio }
2970df2230cSclaudio 
29868f72004Sclaudio void
29955e823c7Sclaudio attr_put(struct attr *a)
300af6b2e43Sclaudio {
30155e823c7Sclaudio 	if (a == NULL)
30255e823c7Sclaudio 		return;
303af6b2e43Sclaudio 
30455e823c7Sclaudio 	rdemem.attr_refs--;
30555e823c7Sclaudio 	if (--a->refcnt > 0)
30655e823c7Sclaudio 		/* somebody still holds a reference */
30755e823c7Sclaudio 		return;
308af6b2e43Sclaudio 
30955e823c7Sclaudio 	/* unlink */
3101f826a12Sclaudio 	RB_REMOVE(attr_tree, &attrtable, a);
31168f72004Sclaudio 
312fc4470d5Sclaudio 	if (a->len != 0)
313fc4470d5Sclaudio 		rdemem.attr_dcnt--;
3146b5f6ff8Sclaudio 	rdemem.attr_data -= a->len;
3156b5f6ff8Sclaudio 	rdemem.attr_cnt--;
31668f72004Sclaudio 	free(a->data);
31768f72004Sclaudio 	free(a);
31868f72004Sclaudio }
31968f72004Sclaudio 
32068f72004Sclaudio /* aspath specific functions */
32168f72004Sclaudio 
32239386878Sclaudio static uint16_t aspath_count(const void *, uint16_t);
32339386878Sclaudio static uint32_t aspath_extract_origin(const void *, uint16_t);
32439386878Sclaudio static uint16_t aspath_countlength(struct aspath *, uint16_t, int);
32539386878Sclaudio static void	 aspath_countcopy(struct aspath *, uint16_t, uint8_t *,
32639386878Sclaudio 		    uint16_t, int);
32768f72004Sclaudio 
3283487a040Sclaudio int
3293487a040Sclaudio aspath_compare(struct aspath *a1, struct aspath *a2)
33068f72004Sclaudio {
3313487a040Sclaudio 	int r;
332b33564f7Sclaudio 
3333487a040Sclaudio 	if (a1->len > a2->len)
3343487a040Sclaudio 		return (1);
3353487a040Sclaudio 	if (a1->len < a2->len)
3363487a040Sclaudio 		return (-1);
3373487a040Sclaudio 	r = memcmp(a1->data, a2->data, a1->len);
3383487a040Sclaudio 	if (r > 0)
3393487a040Sclaudio 		return (1);
3403487a040Sclaudio 	if (r < 0)
3413487a040Sclaudio 		return (-1);
3423487a040Sclaudio 	return (0);
3434670f09dSclaudio }
3444670f09dSclaudio 
345b33564f7Sclaudio struct aspath *
34639386878Sclaudio aspath_get(void *data, uint16_t len)
347b33564f7Sclaudio {
34868f72004Sclaudio 	struct aspath		*aspath;
34968f72004Sclaudio 
35068f72004Sclaudio 	aspath = malloc(ASPATH_HEADER_SIZE + len);
35168f72004Sclaudio 	if (aspath == NULL)
3523487a040Sclaudio 		fatal("%s", __func__);
353b33564f7Sclaudio 
3546b5f6ff8Sclaudio 	rdemem.aspath_cnt++;
3556b5f6ff8Sclaudio 	rdemem.aspath_size += ASPATH_HEADER_SIZE + len;
3566b5f6ff8Sclaudio 
357b33564f7Sclaudio 	aspath->len = len;
358b33564f7Sclaudio 	aspath->ascnt = aspath_count(data, len);
359a34ea928Sclaudio 	aspath->source_as = aspath_extract_origin(data, len);
360*e386eeb1Sclaudio 	if (len != 0)
36168f72004Sclaudio 		memcpy(aspath->data, data, len);
36268f72004Sclaudio 
3633487a040Sclaudio 	return (aspath);
364b33564f7Sclaudio }
3653487a040Sclaudio 
3663487a040Sclaudio struct aspath *
3673487a040Sclaudio aspath_copy(struct aspath *a)
3683487a040Sclaudio {
3693487a040Sclaudio 	struct aspath		*aspath;
3703487a040Sclaudio 
3713487a040Sclaudio 	aspath = malloc(ASPATH_HEADER_SIZE + a->len);
3723487a040Sclaudio 	if (aspath == NULL)
3733487a040Sclaudio 		fatal("%s", __func__);
3743487a040Sclaudio 
3753487a040Sclaudio 	rdemem.aspath_cnt++;
3763487a040Sclaudio 	rdemem.aspath_size += ASPATH_HEADER_SIZE + a->len;
3773487a040Sclaudio 
3783487a040Sclaudio 	memcpy(aspath, a,  ASPATH_HEADER_SIZE + a->len);
37968f72004Sclaudio 
380ba0c695bSclaudio 	return (aspath);
38168f72004Sclaudio }
38268f72004Sclaudio 
38368f72004Sclaudio void
384b33564f7Sclaudio aspath_put(struct aspath *aspath)
38568f72004Sclaudio {
386b33564f7Sclaudio 	if (aspath == NULL)
387b33564f7Sclaudio 		return;
388b33564f7Sclaudio 
3896b5f6ff8Sclaudio 	rdemem.aspath_cnt--;
3906b5f6ff8Sclaudio 	rdemem.aspath_size -= ASPATH_HEADER_SIZE + aspath->len;
39168f72004Sclaudio 	free(aspath);
39268f72004Sclaudio }
39368f72004Sclaudio 
39429328a94Sclaudio /*
39529328a94Sclaudio  * convert a 4 byte aspath to a 2 byte one.
39629328a94Sclaudio  */
3970c88bf70Sclaudio u_char *
39839386878Sclaudio aspath_deflate(u_char *data, uint16_t *len, int *flagnew)
3990c88bf70Sclaudio {
400*e386eeb1Sclaudio 	uint8_t		*seg, *nseg, *ndata = NULL;
40139386878Sclaudio 	uint32_t	 as;
4020c88bf70Sclaudio 	int		 i;
40339386878Sclaudio 	uint16_t	 seg_size, olen, nlen;
40439386878Sclaudio 	uint8_t		 seg_len;
4050c88bf70Sclaudio 
4060c88bf70Sclaudio 	/* first calculate the length of the aspath */
4070c88bf70Sclaudio 	nlen = 0;
4080c88bf70Sclaudio 	seg = data;
4090c88bf70Sclaudio 	olen = *len;
4100c88bf70Sclaudio 	for (; olen > 0; olen -= seg_size, seg += seg_size) {
4110c88bf70Sclaudio 		seg_len = seg[1];
41239386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
41339386878Sclaudio 		nlen += 2 + sizeof(uint16_t) * seg_len;
4140c88bf70Sclaudio 
4150c88bf70Sclaudio 		if (seg_size > olen)
4166f1dba6eSclaudio 			fatalx("%s: would overflow", __func__);
4170c88bf70Sclaudio 	}
4180c88bf70Sclaudio 
419*e386eeb1Sclaudio 	if (nlen == 0)
420*e386eeb1Sclaudio 		goto done;
421*e386eeb1Sclaudio 
4220c88bf70Sclaudio 	if ((ndata = malloc(nlen)) == NULL)
42367fd830bSclaudio 		fatal("%s", __func__);
4240c88bf70Sclaudio 
4250c88bf70Sclaudio 	/* then copy the aspath */
4260c88bf70Sclaudio 	seg = data;
4270c88bf70Sclaudio 	olen = *len;
4280c88bf70Sclaudio 	for (nseg = ndata; seg < data + olen; seg += seg_size) {
4290c88bf70Sclaudio 		*nseg++ = seg[0];
4300c88bf70Sclaudio 		*nseg++ = seg_len = seg[1];
43139386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
4320c88bf70Sclaudio 
4330c88bf70Sclaudio 		for (i = 0; i < seg_len; i++) {
4340c88bf70Sclaudio 			as = aspath_extract(seg, i);
4350c88bf70Sclaudio 			if (as > USHRT_MAX) {
4360c88bf70Sclaudio 				as = AS_TRANS;
4370c88bf70Sclaudio 				*flagnew = 1;
4380c88bf70Sclaudio 			}
4390c88bf70Sclaudio 			*nseg++ = (as >> 8) & 0xff;
4400c88bf70Sclaudio 			*nseg++ = as & 0xff;
4410c88bf70Sclaudio 		}
4420c88bf70Sclaudio 	}
4430c88bf70Sclaudio 
444*e386eeb1Sclaudio  done:
4450c88bf70Sclaudio 	*len = nlen;
4460c88bf70Sclaudio 	return (ndata);
4470c88bf70Sclaudio }
4480c88bf70Sclaudio 
4490c88bf70Sclaudio void
4500c88bf70Sclaudio aspath_merge(struct rde_aspath *a, struct attr *attr)
4510c88bf70Sclaudio {
45239386878Sclaudio 	uint8_t		*np;
45339386878Sclaudio 	uint16_t	 ascnt, diff, nlen, difflen;
4540c88bf70Sclaudio 	int		 hroom = 0;
4550c88bf70Sclaudio 
4560c88bf70Sclaudio 	ascnt = aspath_count(attr->data, attr->len);
4570c88bf70Sclaudio 	if (ascnt > a->aspath->ascnt) {
4585beb19c6Ssthen 		/* ASPATH is shorter then AS4_PATH no way to merge */
4590c88bf70Sclaudio 		attr_free(a, attr);
4600c88bf70Sclaudio 		return;
4610c88bf70Sclaudio 	}
4620c88bf70Sclaudio 
4630c88bf70Sclaudio 	diff = a->aspath->ascnt - ascnt;
464fd203cf3Sclaudio 	if (diff && attr->len > 2 && attr->data[0] == AS_SEQUENCE)
4650c88bf70Sclaudio 		hroom = attr->data[1];
4660c88bf70Sclaudio 	difflen = aspath_countlength(a->aspath, diff, hroom);
4670c88bf70Sclaudio 	nlen = attr->len + difflen;
4680c88bf70Sclaudio 
4690c88bf70Sclaudio 	if ((np = malloc(nlen)) == NULL)
47067fd830bSclaudio 		fatal("%s", __func__);
4710c88bf70Sclaudio 
4720c88bf70Sclaudio 	/* copy head from old aspath */
4730c88bf70Sclaudio 	aspath_countcopy(a->aspath, diff, np, difflen, hroom);
4740c88bf70Sclaudio 
4750c88bf70Sclaudio 	/* copy tail from new aspath */
4760c88bf70Sclaudio 	if (hroom > 0)
4770c88bf70Sclaudio 		memcpy(np + nlen - attr->len + 2, attr->data + 2,
4780c88bf70Sclaudio 		    attr->len - 2);
4790c88bf70Sclaudio 	else
4800c88bf70Sclaudio 		memcpy(np + nlen - attr->len, attr->data, attr->len);
4810c88bf70Sclaudio 
4820c88bf70Sclaudio 	aspath_put(a->aspath);
4830c88bf70Sclaudio 	a->aspath = aspath_get(np, nlen);
4840c88bf70Sclaudio 	free(np);
4850c88bf70Sclaudio 	attr_free(a, attr);
4860c88bf70Sclaudio }
4870c88bf70Sclaudio 
48839386878Sclaudio uint32_t
489a34ea928Sclaudio aspath_neighbor(struct aspath *aspath)
490a34ea928Sclaudio {
491a3d44d86Sclaudio 	/*
492a3d44d86Sclaudio 	 * Empty aspath is OK -- internal AS route.
493a3d44d86Sclaudio 	 * Additionally the RFC specifies that if the path starts with an
494a3d44d86Sclaudio 	 * AS_SET the neighbor AS is also the local AS.
495a3d44d86Sclaudio 	 */
496a3d44d86Sclaudio 	if (aspath->len == 0 ||
497a3d44d86Sclaudio 	    aspath->data[0] != AS_SEQUENCE)
498a34ea928Sclaudio 		return (rde_local_as());
499a34ea928Sclaudio 	return (aspath_extract(aspath->data, 0));
500a34ea928Sclaudio }
501a34ea928Sclaudio 
50239386878Sclaudio static uint16_t
50339386878Sclaudio aspath_count(const void *data, uint16_t len)
50468f72004Sclaudio {
50539386878Sclaudio 	const uint8_t	*seg;
50639386878Sclaudio 	uint16_t	 cnt, seg_size;
50739386878Sclaudio 	uint8_t		 seg_type, seg_len;
50868f72004Sclaudio 
50968f72004Sclaudio 	cnt = 0;
510b33564f7Sclaudio 	seg = data;
511b33564f7Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
51268f72004Sclaudio 		seg_type = seg[0];
51368f72004Sclaudio 		seg_len = seg[1];
51439386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
51568f72004Sclaudio 
51668f72004Sclaudio 		if (seg_type == AS_SET)
51768f72004Sclaudio 			cnt += 1;
51868f72004Sclaudio 		else
51968f72004Sclaudio 			cnt += seg_len;
520b33564f7Sclaudio 
521b33564f7Sclaudio 		if (seg_size > len)
5226f1dba6eSclaudio 			fatalx("%s: would overflow", __func__);
52368f72004Sclaudio 	}
524ba0c695bSclaudio 	return (cnt);
52568f72004Sclaudio }
52668f72004Sclaudio 
527a34ea928Sclaudio /*
528a34ea928Sclaudio  * The origin AS number derived from a Route as follows:
529a34ea928Sclaudio  * o  the rightmost AS in the final segment of the AS_PATH attribute
530a34ea928Sclaudio  *    in the Route if that segment is of type AS_SEQUENCE, or
531a34ea928Sclaudio  * o  the BGP speaker's own AS number if that segment is of type
532a34ea928Sclaudio  *    AS_CONFED_SEQUENCE or AS_CONFED_SET or if the AS_PATH is empty,
533a34ea928Sclaudio  * o  the distinguished value "NONE" if the final segment of the
534a34ea928Sclaudio  *    AS_PATH attribute is of any other type.
535a34ea928Sclaudio  */
53639386878Sclaudio static uint32_t
53739386878Sclaudio aspath_extract_origin(const void *data, uint16_t len)
538a34ea928Sclaudio {
53939386878Sclaudio 	const uint8_t	*seg;
54039386878Sclaudio 	uint32_t	 as = AS_NONE;
54139386878Sclaudio 	uint16_t	 seg_size;
54239386878Sclaudio 	uint8_t		 seg_len;
543a34ea928Sclaudio 
544a34ea928Sclaudio 	/* AS_PATH is empty */
545a34ea928Sclaudio 	if (len == 0)
546a34ea928Sclaudio 		return (rde_local_as());
547a34ea928Sclaudio 
548a34ea928Sclaudio 	seg = data;
549a34ea928Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
550a34ea928Sclaudio 		seg_len = seg[1];
55139386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
552a34ea928Sclaudio 
553a34ea928Sclaudio 		if (len == seg_size && seg[0] == AS_SEQUENCE) {
554a34ea928Sclaudio 			as = aspath_extract(seg, seg_len - 1);
555a34ea928Sclaudio 		}
556a34ea928Sclaudio 		if (seg_size > len)
557a34ea928Sclaudio 			fatalx("%s: would overflow", __func__);
558a34ea928Sclaudio 	}
559a34ea928Sclaudio 	return (as);
560a34ea928Sclaudio }
561a34ea928Sclaudio 
56239386878Sclaudio static uint16_t
56339386878Sclaudio aspath_countlength(struct aspath *aspath, uint16_t cnt, int headcnt)
5640c88bf70Sclaudio {
56539386878Sclaudio 	const uint8_t	*seg;
56639386878Sclaudio 	uint16_t	 seg_size, len, clen;
56739386878Sclaudio 	uint8_t		 seg_type = 0, seg_len = 0;
5680c88bf70Sclaudio 
5690c88bf70Sclaudio 	seg = aspath->data;
5700c88bf70Sclaudio 	clen = 0;
5710c88bf70Sclaudio 	for (len = aspath->len; len > 0 && cnt > 0;
5720c88bf70Sclaudio 	    len -= seg_size, seg += seg_size) {
5730c88bf70Sclaudio 		seg_type = seg[0];
5740c88bf70Sclaudio 		seg_len = seg[1];
57539386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
5760c88bf70Sclaudio 
5770c88bf70Sclaudio 		if (seg_type == AS_SET)
5780c88bf70Sclaudio 			cnt -= 1;
5790c88bf70Sclaudio 		else if (seg_len > cnt) {
5800c88bf70Sclaudio 			seg_len = cnt;
58139386878Sclaudio 			clen += 2 + sizeof(uint32_t) * cnt;
5820c88bf70Sclaudio 			break;
5830c88bf70Sclaudio 		} else
5840c88bf70Sclaudio 			cnt -= seg_len;
5850c88bf70Sclaudio 
5860c88bf70Sclaudio 		clen += seg_size;
5870c88bf70Sclaudio 
5880c88bf70Sclaudio 		if (seg_size > len)
5896f1dba6eSclaudio 			fatalx("%s: would overflow", __func__);
5900c88bf70Sclaudio 	}
5910c88bf70Sclaudio 	if (headcnt > 0 && seg_type == AS_SEQUENCE && headcnt + seg_len < 256)
5920c88bf70Sclaudio 		/* no need for additional header from the new aspath. */
5930c88bf70Sclaudio 		clen -= 2;
5940c88bf70Sclaudio 
5950c88bf70Sclaudio 	return (clen);
5960c88bf70Sclaudio }
5970c88bf70Sclaudio 
59813409241Sclaudio static void
59939386878Sclaudio aspath_countcopy(struct aspath *aspath, uint16_t cnt, uint8_t *buf,
60039386878Sclaudio     uint16_t size, int headcnt)
6010c88bf70Sclaudio {
60239386878Sclaudio 	const uint8_t	*seg;
60339386878Sclaudio 	uint16_t	 seg_size, len;
60439386878Sclaudio 	uint8_t		 seg_type, seg_len;
6050c88bf70Sclaudio 
6060c88bf70Sclaudio 	if (headcnt > 0)
6070c88bf70Sclaudio 		/*
6080c88bf70Sclaudio 		 * additional room because we steal the segment header
6090c88bf70Sclaudio 		 * from the other aspath
6100c88bf70Sclaudio 		 */
6110c88bf70Sclaudio 		size += 2;
6120c88bf70Sclaudio 	seg = aspath->data;
6130c88bf70Sclaudio 	for (len = aspath->len; len > 0 && cnt > 0;
6140c88bf70Sclaudio 	    len -= seg_size, seg += seg_size) {
6150c88bf70Sclaudio 		seg_type = seg[0];
6160c88bf70Sclaudio 		seg_len = seg[1];
61739386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
6180c88bf70Sclaudio 
6190c88bf70Sclaudio 		if (seg_type == AS_SET)
6200c88bf70Sclaudio 			cnt -= 1;
6210c88bf70Sclaudio 		else if (seg_len > cnt) {
6220c88bf70Sclaudio 			seg_len = cnt + headcnt;
62339386878Sclaudio 			seg_size = 2 + sizeof(uint32_t) * cnt;
6240c88bf70Sclaudio 			cnt = 0;
6250c88bf70Sclaudio 		} else {
6260c88bf70Sclaudio 			cnt -= seg_len;
6270c88bf70Sclaudio 			if (cnt == 0)
6280c88bf70Sclaudio 				seg_len += headcnt;
6290c88bf70Sclaudio 		}
6300c88bf70Sclaudio 
6310c88bf70Sclaudio 		memcpy(buf, seg, seg_size);
6320c88bf70Sclaudio 		buf[0] = seg_type;
6330c88bf70Sclaudio 		buf[1] = seg_len;
6340c88bf70Sclaudio 		buf += seg_size;
6350c88bf70Sclaudio 		if (size < seg_size)
6366f1dba6eSclaudio 			fatalx("%s: would overflow", __func__);
6370c88bf70Sclaudio 		size -= seg_size;
6380c88bf70Sclaudio 	}
6390c88bf70Sclaudio }
6400c88bf70Sclaudio 
6411384e26cSclaudio int
64239386878Sclaudio aspath_loopfree(struct aspath *aspath, uint32_t myAS)
6431384e26cSclaudio {
64439386878Sclaudio 	uint8_t		*seg;
64539386878Sclaudio 	uint16_t	 len, seg_size;
64639386878Sclaudio 	uint8_t		 i, seg_len;
6471384e26cSclaudio 
6481384e26cSclaudio 	seg = aspath->data;
649b33564f7Sclaudio 	for (len = aspath->len; len > 0; len -= seg_size, seg += seg_size) {
6501384e26cSclaudio 		seg_len = seg[1];
65139386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
6521384e26cSclaudio 
6531384e26cSclaudio 		for (i = 0; i < seg_len; i++) {
6541384e26cSclaudio 			if (myAS == aspath_extract(seg, i))
655ba0c695bSclaudio 				return (0);
6561384e26cSclaudio 		}
657b33564f7Sclaudio 
658b33564f7Sclaudio 		if (seg_size > len)
6596f1dba6eSclaudio 			fatalx("%s: would overflow", __func__);
6601384e26cSclaudio 	}
661ba0c695bSclaudio 	return (1);
6621384e26cSclaudio }
6631384e26cSclaudio 
664a34ea928Sclaudio static int
66539386878Sclaudio as_compare(struct filter_as *f, uint32_t as, uint32_t neighas)
666a34ea928Sclaudio {
66739386878Sclaudio 	uint32_t match;
668a34ea928Sclaudio 
669a34ea928Sclaudio 	if (f->flags & AS_FLAG_AS_SET_NAME)	/* should not happen */
670a34ea928Sclaudio 		return (0);
671a34ea928Sclaudio 	if (f->flags & AS_FLAG_AS_SET)
672a34ea928Sclaudio 		return (as_set_match(f->aset, as));
673a34ea928Sclaudio 
674a34ea928Sclaudio 	if (f->flags & AS_FLAG_NEIGHBORAS)
675a34ea928Sclaudio 		match = neighas;
676a34ea928Sclaudio 	else
677a34ea928Sclaudio 		match = f->as_min;
678a34ea928Sclaudio 
679a34ea928Sclaudio 	switch (f->op) {
680a34ea928Sclaudio 	case OP_NONE:
681a34ea928Sclaudio 	case OP_EQ:
682a34ea928Sclaudio 		if (as == match)
683a34ea928Sclaudio 			return (1);
684a34ea928Sclaudio 		break;
685a34ea928Sclaudio 	case OP_NE:
686a34ea928Sclaudio 		if (as != match)
687a34ea928Sclaudio 			return (1);
688a34ea928Sclaudio 		break;
689a34ea928Sclaudio 	case OP_RANGE:
690a34ea928Sclaudio 		if (as >= f->as_min && as <= f->as_max)
691a34ea928Sclaudio 			return (1);
692a34ea928Sclaudio 		break;
693a34ea928Sclaudio 	case OP_XRANGE:
694a34ea928Sclaudio 		if (as < f->as_min || as > f->as_max)
695a34ea928Sclaudio 			return (1);
696a34ea928Sclaudio 		break;
697a34ea928Sclaudio 	}
698a34ea928Sclaudio 	return (0);
699a34ea928Sclaudio }
700a34ea928Sclaudio 
701a34ea928Sclaudio /* we need to be able to search more than one as */
702a34ea928Sclaudio int
70339386878Sclaudio aspath_match(struct aspath *aspath, struct filter_as *f, uint32_t neighas)
704a34ea928Sclaudio {
70539386878Sclaudio 	const uint8_t	*seg;
706a34ea928Sclaudio 	int		 final;
70739386878Sclaudio 	uint16_t	 len, seg_size;
70839386878Sclaudio 	uint8_t		 i, seg_len;
70939386878Sclaudio 	uint32_t	 as = AS_NONE;
710a34ea928Sclaudio 
711a34ea928Sclaudio 	if (f->type == AS_EMPTY) {
712a34ea928Sclaudio 		if (aspath_length(aspath) == 0)
713a34ea928Sclaudio 			return (1);
714a34ea928Sclaudio 		else
715a34ea928Sclaudio 			return (0);
716a34ea928Sclaudio 	}
717a34ea928Sclaudio 
718a34ea928Sclaudio 	/* just check the leftmost AS */
719a34ea928Sclaudio 	if (f->type == AS_PEER) {
720a34ea928Sclaudio 		as = aspath_neighbor(aspath);
721a34ea928Sclaudio 		if (as_compare(f, as, neighas))
722a34ea928Sclaudio 			return (1);
723a34ea928Sclaudio 		else
724a34ea928Sclaudio 			return (0);
725a34ea928Sclaudio 	}
726a34ea928Sclaudio 
727a34ea928Sclaudio 	seg = aspath->data;
728a34ea928Sclaudio 	len = aspath->len;
729a34ea928Sclaudio 	for (; len >= 6; len -= seg_size, seg += seg_size) {
730a34ea928Sclaudio 		seg_len = seg[1];
73139386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
732a34ea928Sclaudio 
733a34ea928Sclaudio 		final = (len == seg_size);
734a34ea928Sclaudio 
735a34ea928Sclaudio 		if (f->type == AS_SOURCE) {
736a34ea928Sclaudio 			/*
737a34ea928Sclaudio 			 * Just extract the rightmost AS
738a34ea928Sclaudio 			 * but if that segment is an AS_SET then the rightmost
739a34ea928Sclaudio 			 * AS of a previous AS_SEQUENCE segment should be used.
740a34ea928Sclaudio 			 * Because of that just look at AS_SEQUENCE segments.
741a34ea928Sclaudio 			 */
742a34ea928Sclaudio 			if (seg[0] == AS_SEQUENCE)
743a34ea928Sclaudio 				as = aspath_extract(seg, seg_len - 1);
744a34ea928Sclaudio 			/* not yet in the final segment */
745a34ea928Sclaudio 			if (!final)
746a34ea928Sclaudio 				continue;
747a34ea928Sclaudio 			if (as_compare(f, as, neighas))
748a34ea928Sclaudio 				return (1);
749a34ea928Sclaudio 			else
750a34ea928Sclaudio 				return (0);
751a34ea928Sclaudio 		}
752a34ea928Sclaudio 		/* AS_TRANSIT or AS_ALL */
753a34ea928Sclaudio 		for (i = 0; i < seg_len; i++) {
754a34ea928Sclaudio 			/*
755a34ea928Sclaudio 			 * the source (rightmost) AS is excluded from
756a34ea928Sclaudio 			 * AS_TRANSIT matches.
757a34ea928Sclaudio 			 */
758a34ea928Sclaudio 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
759a34ea928Sclaudio 				return (0);
760a34ea928Sclaudio 			as = aspath_extract(seg, i);
761a34ea928Sclaudio 			if (as_compare(f, as, neighas))
762a34ea928Sclaudio 				return (1);
763a34ea928Sclaudio 		}
764d7a2dcd7Sclaudio 
765d7a2dcd7Sclaudio 		if (seg_size > len)
766d7a2dcd7Sclaudio 			fatalx("%s: would overflow", __func__);
767a34ea928Sclaudio 	}
768a34ea928Sclaudio 	return (0);
769a34ea928Sclaudio }
770a34ea928Sclaudio 
771b33564f7Sclaudio /*
772b33564f7Sclaudio  * Returns a new prepended aspath. Old needs to be freed by caller.
773b33564f7Sclaudio  */
7740c88bf70Sclaudio u_char *
77539386878Sclaudio aspath_prepend(struct aspath *asp, uint32_t as, int quantum, uint16_t *len)
776b33564f7Sclaudio {
777b33564f7Sclaudio 	u_char		*p;
7780c88bf70Sclaudio 	int		 l, overflow = 0, shift = 0, size, wpos = 0;
77939386878Sclaudio 	uint8_t		 type;
780b33564f7Sclaudio 
781b33564f7Sclaudio 	/* lunatic prepends are blocked in the parser and limited */
782b33564f7Sclaudio 
783b33564f7Sclaudio 	/* first calculate new size */
784b33564f7Sclaudio 	if (asp->len > 0) {
785b33564f7Sclaudio 		if (asp->len < 2)
78610004ee3Sclaudio 			fatalx("aspath_prepend: bad aspath length");
787b33564f7Sclaudio 		type = asp->data[0];
788b33564f7Sclaudio 		size = asp->data[1];
789b33564f7Sclaudio 	} else {
790b33564f7Sclaudio 		/* empty as path */
791b33564f7Sclaudio 		type = AS_SET;
792b33564f7Sclaudio 		size = 0;
793b33564f7Sclaudio 	}
794b33564f7Sclaudio 
795df364eccSclaudio 	if (quantum > 255)
796df364eccSclaudio 		fatalx("aspath_prepend: preposterous prepend");
797b33564f7Sclaudio 	if (quantum == 0) {
7980c88bf70Sclaudio 		/* no change needed but return a copy */
799*e386eeb1Sclaudio 		if (asp->len == 0) {
800*e386eeb1Sclaudio 			*len = 0;
801*e386eeb1Sclaudio 			return (NULL);
802*e386eeb1Sclaudio 		}
8030c88bf70Sclaudio 		p = malloc(asp->len);
8040c88bf70Sclaudio 		if (p == NULL)
80567fd830bSclaudio 			fatal("%s", __func__);
8060c88bf70Sclaudio 		memcpy(p, asp->data, asp->len);
8070c88bf70Sclaudio 		*len = asp->len;
8080c88bf70Sclaudio 		return (p);
809b33564f7Sclaudio 	} else if (type == AS_SET || size + quantum > 255) {
810b33564f7Sclaudio 		/* need to attach a new AS_SEQUENCE */
81139386878Sclaudio 		l = 2 + quantum * sizeof(uint32_t) + asp->len;
812df364eccSclaudio 		if (type == AS_SET)
813df364eccSclaudio 			overflow = quantum;
814df364eccSclaudio 		else
815df364eccSclaudio 			overflow = size + quantum - 255;
816b33564f7Sclaudio 	} else
81739386878Sclaudio 		l = quantum * sizeof(uint32_t) + asp->len;
818b33564f7Sclaudio 
819b33564f7Sclaudio 	quantum -= overflow;
820b33564f7Sclaudio 
8210c88bf70Sclaudio 	p = malloc(l);
822b33564f7Sclaudio 	if (p == NULL)
82367fd830bSclaudio 		fatal("%s", __func__);
824b33564f7Sclaudio 
825b33564f7Sclaudio 	/* first prepends */
8260c88bf70Sclaudio 	as = htonl(as);
827b33564f7Sclaudio 	if (overflow > 0) {
828b33564f7Sclaudio 		p[wpos++] = AS_SEQUENCE;
829b33564f7Sclaudio 		p[wpos++] = overflow;
830b33564f7Sclaudio 
831b33564f7Sclaudio 		for (; overflow > 0; overflow--) {
83239386878Sclaudio 			memcpy(p + wpos, &as, sizeof(uint32_t));
83339386878Sclaudio 			wpos += sizeof(uint32_t);
834b33564f7Sclaudio 		}
835b33564f7Sclaudio 	}
836b33564f7Sclaudio 	if (quantum > 0) {
837b33564f7Sclaudio 		shift = 2;
838b33564f7Sclaudio 		p[wpos++] = AS_SEQUENCE;
839b33564f7Sclaudio 		p[wpos++] = quantum + size;
840b33564f7Sclaudio 
841b33564f7Sclaudio 		for (; quantum > 0; quantum--) {
84239386878Sclaudio 			memcpy(p + wpos, &as, sizeof(uint32_t));
84339386878Sclaudio 			wpos += sizeof(uint32_t);
844b33564f7Sclaudio 		}
845b33564f7Sclaudio 	}
846*e386eeb1Sclaudio 	if (asp->len > shift)
847b33564f7Sclaudio 		memcpy(p + wpos, asp->data + shift, asp->len - shift);
848b33564f7Sclaudio 
8490c88bf70Sclaudio 	*len = l;
8500c88bf70Sclaudio 	return (p);
85168f72004Sclaudio }
85268f72004Sclaudio 
853d7a2dcd7Sclaudio /*
854d7a2dcd7Sclaudio  * Returns a new aspath where neighbor_as is replaced by local_as.
855d7a2dcd7Sclaudio  */
856d7a2dcd7Sclaudio u_char *
85739386878Sclaudio aspath_override(struct aspath *asp, uint32_t neighbor_as, uint32_t local_as,
85839386878Sclaudio     uint16_t *len)
859d7a2dcd7Sclaudio {
860d7a2dcd7Sclaudio 	u_char		*p, *seg, *nseg;
86139386878Sclaudio 	uint32_t	 as;
86239386878Sclaudio 	uint16_t	 l, seg_size;
86339386878Sclaudio 	uint8_t		 i, seg_len, seg_type;
864d7a2dcd7Sclaudio 
865*e386eeb1Sclaudio 	if (asp->len == 0) {
866*e386eeb1Sclaudio 		*len = 0;
867*e386eeb1Sclaudio 		return (NULL);
868*e386eeb1Sclaudio 	}
869*e386eeb1Sclaudio 
870d7a2dcd7Sclaudio 	p = malloc(asp->len);
871d7a2dcd7Sclaudio 	if (p == NULL)
87267fd830bSclaudio 		fatal("%s", __func__);
873d7a2dcd7Sclaudio 
874d7a2dcd7Sclaudio 	seg = asp->data;
875d7a2dcd7Sclaudio 	nseg = p;
876d7a2dcd7Sclaudio 	for (l = asp->len; l > 0; l -= seg_size, seg += seg_size) {
877d7a2dcd7Sclaudio 		*nseg++ = seg_type = seg[0];
878d7a2dcd7Sclaudio 		*nseg++ = seg_len = seg[1];
87939386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
880d7a2dcd7Sclaudio 
881d7a2dcd7Sclaudio 		for (i = 0; i < seg_len; i++) {
882d7a2dcd7Sclaudio 			as = aspath_extract(seg, i);
883d7a2dcd7Sclaudio 			if (as == neighbor_as)
884d7a2dcd7Sclaudio 				as = local_as;
885d7a2dcd7Sclaudio 			as = htonl(as);
886d7a2dcd7Sclaudio 			memcpy(nseg, &as, sizeof(as));
887d7a2dcd7Sclaudio 			nseg += sizeof(as);
888d7a2dcd7Sclaudio 		}
889d7a2dcd7Sclaudio 
890d7a2dcd7Sclaudio 		if (seg_size > l)
891d7a2dcd7Sclaudio 			fatalx("%s: would overflow", __func__);
892d7a2dcd7Sclaudio 	}
893d7a2dcd7Sclaudio 
894d7a2dcd7Sclaudio 	*len = asp->len;
895d7a2dcd7Sclaudio 	return (p);
896d7a2dcd7Sclaudio }
897d7a2dcd7Sclaudio 
8984a044d31Sclaudio int
8994a044d31Sclaudio aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen)
9004a044d31Sclaudio {
90139386878Sclaudio 	uint8_t		*seg;
90239386878Sclaudio 	uint32_t	 as, lastas = 0;
9034a044d31Sclaudio 	u_int		 count = 0;
90439386878Sclaudio 	uint16_t	 len, seg_size;
90539386878Sclaudio 	uint8_t		 i, seg_len, seg_type;
9064a044d31Sclaudio 
9074a044d31Sclaudio 	if (type == ASLEN_MAX) {
9084a044d31Sclaudio 		if (aslen < aspath_count(a->data, a->len))
9094a044d31Sclaudio 			return (1);
9104a044d31Sclaudio 		else
9114a044d31Sclaudio 			return (0);
9124a044d31Sclaudio 	}
9134a044d31Sclaudio 
9144a044d31Sclaudio 	/* type == ASLEN_SEQ */
9154a044d31Sclaudio 	seg = a->data;
9164a044d31Sclaudio 	for (len = a->len; len > 0; len -= seg_size, seg += seg_size) {
917bce5f8adSclaudio 		seg_type = seg[0];
9184a044d31Sclaudio 		seg_len = seg[1];
91939386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
9204a044d31Sclaudio 
9214a044d31Sclaudio 		for (i = 0; i < seg_len; i++) {
9224a044d31Sclaudio 			as = aspath_extract(seg, i);
9234a044d31Sclaudio 			if (as == lastas) {
9244a044d31Sclaudio 				if (aslen < ++count)
9254a044d31Sclaudio 					return (1);
926bce5f8adSclaudio 			} else if (seg_type == AS_SET) {
927bce5f8adSclaudio 				/* AS path 3 { 4 3 7 } 3 will have count = 3 */
928bce5f8adSclaudio 				continue;
9294a044d31Sclaudio 			} else
9304a044d31Sclaudio 				count = 1;
9314a044d31Sclaudio 			lastas = as;
9324a044d31Sclaudio 		}
933d7a2dcd7Sclaudio 
934d7a2dcd7Sclaudio 		if (seg_size > len)
935d7a2dcd7Sclaudio 			fatalx("%s: would overflow", __func__);
9364a044d31Sclaudio 	}
9374a044d31Sclaudio 	return (0);
9384a044d31Sclaudio }
939