typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
uint8_t tlv_len, struct stream *s,
struct sbuf *log, void *dest, int indent);
-typedef int (*pack_item_func)(struct isis_item *item, struct stream *s);
+typedef int (*pack_item_func)(struct isis_item *item, struct stream *s,
+ size_t *min_length);
typedef void (*free_item_func)(struct isis_item *i);
typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
struct sbuf *log, void *dest, int indent);
}
static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
- struct stream *s)
+ struct stream *s, size_t *min_len)
{
uint8_t size;
- if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE)
+ if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) {
+ *min_len = ISIS_SUBTLV_MAX_SIZE;
return 1;
+ }
if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
XFREE(MTYPE_ISIS_SUBTLV, i);
}
-static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
+static int pack_item_prefix_sid(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
- if (STREAM_WRITEABLE(s) < size)
+ if (STREAM_WRITEABLE(s) < size) {
+ *min_len = size;
return 1;
+ }
stream_putc(s, sid->flags);
stream_putc(s, sid->algorithm);
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_area_address(struct isis_item *i, struct stream *s)
+static int pack_item_area_address(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_area_address *addr = (struct isis_area_address *)i;
- if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len)
+ if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len) {
+ *min_len = (unsigned)1 + addr->len;
return 1;
+ }
stream_putc(s, addr->len);
stream_put(s, addr->addr, addr->len);
return 0;
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s)
+static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
- if (STREAM_WRITEABLE(s) < 11)
+ if (STREAM_WRITEABLE(s) < 11) {
+ *min_len = 11;
return 1;
+ }
stream_putc(s, r->metric);
stream_putc(s, 0x80); /* delay metric - unsupported */
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s)
+static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
- if (STREAM_WRITEABLE(s) < 6)
+ if (STREAM_WRITEABLE(s) < 6) {
+ *min_len = 6;
return 1;
+ }
stream_put(s, n->mac, 6);
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_lsp_entry(struct isis_item *i, struct stream *s)
+static int pack_item_lsp_entry(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
- if (STREAM_WRITEABLE(s) < 16)
+ if (STREAM_WRITEABLE(s) < 16) {
+ *min_len = 16;
return 1;
+ }
stream_putw(s, e->rem_lifetime);
stream_put(s, e->id, 8);
XFREE(MTYPE_ISIS_TLV, item);
}
-static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
+static int pack_item_extended_reach(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_extended_reach *r = (struct isis_extended_reach *)i;
size_t len;
size_t len_pos;
- if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE)
+ if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) {
+ *min_len = 11 + ISIS_SUBTLV_MAX_SIZE;
return 1;
+ }
stream_put(s, r->id, sizeof(r->id));
stream_put3(s, r->metric);
/* Real length will be adjust after adding subTLVs */
stream_putc(s, 11);
if (r->subtlvs)
- pack_item_ext_subtlvs(r->subtlvs, s);
+ pack_item_ext_subtlvs(r->subtlvs, s, min_len);
/* Adjust length */
len = stream_get_endp(s) - len_pos - 1;
stream_putc_at(s, len_pos, len);
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s)
+static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
- if (STREAM_WRITEABLE(s) < 12)
+ if (STREAM_WRITEABLE(s) < 12) {
+ *min_len = 12;
return 1;
+ }
stream_putc(s, r->metric);
stream_putc(s, 0x80); /* delay metric - unsupported */
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_ipv4_address(struct isis_item *i, struct stream *s)
+static int pack_item_ipv4_address(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
- if (STREAM_WRITEABLE(s) < 4)
+ if (STREAM_WRITEABLE(s) < 4) {
+ *min_len = 4;
return 1;
+ }
stream_put(s, &a->addr, 4);
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_ipv6_address(struct isis_item *i, struct stream *s)
+static int pack_item_ipv6_address(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
- if (STREAM_WRITEABLE(s) < 16)
+ if (STREAM_WRITEABLE(s) < 16) {
+ *min_len = 16;
return 1;
+ }
stream_put(s, &a->addr, 16);
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_mt_router_info(struct isis_item *i, struct stream *s)
+static int pack_item_mt_router_info(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
- if (STREAM_WRITEABLE(s) < 2)
+ if (STREAM_WRITEABLE(s) < 2) {
+ *min_len = 2;
return 1;
+ }
uint16_t entry = info->mtid;
XFREE(MTYPE_ISIS_TLV, item);
}
-static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
+static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
uint8_t control;
- if (STREAM_WRITEABLE(s) < 5)
+ if (STREAM_WRITEABLE(s) < 5) {
+ *min_len = 5;
return 1;
+ }
stream_putl(s, r->metric);
control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
stream_putc(s, control);
- if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
+ if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) {
+ *min_len = 5 + (unsigned)PSIZE(r->prefix.prefixlen);
return 1;
+ }
stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
if (r->subtlvs)
XFREE(MTYPE_ISIS_TLV, item);
}
-static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
+static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
uint8_t control;
- if (STREAM_WRITEABLE(s) < 6)
+ if (STREAM_WRITEABLE(s) < 6 + (unsigned)PSIZE(r->prefix.prefixlen)) {
+ *min_len = 6 + (unsigned)PSIZE(r->prefix.prefixlen);
return 1;
+ }
stream_putl(s, r->metric);
control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
stream_putc(s, control);
stream_putc(s, r->prefix.prefixlen);
- if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
- return 1;
stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
if (r->subtlvs)
XFREE(MTYPE_ISIS_TLV, i);
}
-static int pack_item_auth(struct isis_item *i, struct stream *s)
+static int pack_item_auth(struct isis_item *i, struct stream *s,
+ size_t *min_len)
{
struct isis_auth *auth = (struct isis_auth *)i;
- if (STREAM_WRITEABLE(s) < 1)
+ if (STREAM_WRITEABLE(s) < 1) {
+ *min_len = 1;
return 1;
+ }
stream_putc(s, auth->type);
switch (auth->type) {
case ISIS_PASSWD_TYPE_CLEARTXT:
- if (STREAM_WRITEABLE(s) < auth->length)
+ if (STREAM_WRITEABLE(s) < auth->length) {
+ *min_len = 1 + auth->length;
return 1;
+ }
stream_put(s, auth->passwd, auth->length);
break;
case ISIS_PASSWD_TYPE_HMAC_MD5:
- if (STREAM_WRITEABLE(s) < 16)
+ if (STREAM_WRITEABLE(s) < 16) {
+ *min_len = 1 + 16;
return 1;
+ }
auth->offset = stream_get_endp(s);
stream_put(s, NULL, 16);
break;
}
static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
- struct isis_item *i, struct stream *s,
+ struct isis_item *i, struct stream *s, size_t *min_len,
struct isis_tlvs **fragment_tlvs,
const struct pack_order_entry *pe, uint16_t mtid)
{
const struct tlv_ops *ops = tlv_table[context][type];
if (ops && ops->pack_item) {
- return ops->pack_item(i, s);
+ return ops->pack_item(i, s, min_len);
}
assert(!"Unknown item tlv type!");
size_t len_pos, last_len, len;
struct isis_item *item = NULL;
int rv;
+ size_t min_len = 0;
if (!items->head)
return 0;
last_len = len = 0;
for (item = item ? item : items->head; item; item = item->next) {
- rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
+ rv = pack_item(context, type, item, s, &min_len, fragment_tlvs,
+ pe, mtid);
if (rv)
goto too_long;
if (!fragment_tlvs)
return 1;
stream_reset(s);
+ if (STREAM_WRITEABLE(s) < min_len)
+ return 1;
*fragment_tlvs = new_fragment(new_fragment_arg);
goto top;
}