Annotation of embedaddon/quagga/isisd/isis_tlv.c, revision 1.1.1.3
1.1 misho 1: /*
2: * IS-IS Rout(e)ing protocol - isis_tlv.c
3: * IS-IS TLV related routines
4: *
5: * Copyright (C) 2001,2002 Sampo Saaristo
6: * Tampere University of Technology
7: * Institute of Communications Engineering
8: *
9: * This program is free software; you can redistribute it and/or modify it
10: * under the terms of the GNU General Public Licenseas published by the Free
11: * Software Foundation; either version 2 of the License, or (at your option)
12: * any later version.
13: *
14: * This program is distributed in the hope that it will be useful,but WITHOUT
15: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17: * more details.
18:
19: * You should have received a copy of the GNU General Public License along
20: * with this program; if not, write to the Free Software Foundation, Inc.,
21: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22: */
23:
24: #include <zebra.h>
25:
26: #include "log.h"
27: #include "linklist.h"
28: #include "stream.h"
29: #include "memory.h"
30: #include "prefix.h"
31: #include "vty.h"
32: #include "if.h"
33:
34: #include "isisd/dict.h"
35: #include "isisd/isis_constants.h"
36: #include "isisd/isis_common.h"
37: #include "isisd/isis_flags.h"
38: #include "isisd/isis_circuit.h"
39: #include "isisd/isis_tlv.h"
40: #include "isisd/isisd.h"
41: #include "isisd/isis_dynhn.h"
42: #include "isisd/isis_misc.h"
43: #include "isisd/isis_pdu.h"
44: #include "isisd/isis_lsp.h"
45:
46: void
47: free_tlv (void *val)
48: {
49: XFREE (MTYPE_ISIS_TLV, val);
50:
51: return;
52: }
53:
54: /*
55: * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
56: * is only a caution to avoid memory leaks
57: */
58: void
59: free_tlvs (struct tlvs *tlvs)
60: {
61: if (tlvs->area_addrs)
62: list_delete (tlvs->area_addrs);
63: if (tlvs->is_neighs)
64: list_delete (tlvs->is_neighs);
65: if (tlvs->te_is_neighs)
66: list_delete (tlvs->te_is_neighs);
67: if (tlvs->es_neighs)
68: list_delete (tlvs->es_neighs);
69: if (tlvs->lsp_entries)
70: list_delete (tlvs->lsp_entries);
71: if (tlvs->prefix_neighs)
72: list_delete (tlvs->prefix_neighs);
1.1.1.2 misho 73: if (tlvs->lan_neighs)
74: list_delete (tlvs->lan_neighs);
1.1 misho 75: if (tlvs->ipv4_addrs)
76: list_delete (tlvs->ipv4_addrs);
77: if (tlvs->ipv4_int_reachs)
78: list_delete (tlvs->ipv4_int_reachs);
79: if (tlvs->ipv4_ext_reachs)
80: list_delete (tlvs->ipv4_ext_reachs);
81: if (tlvs->te_ipv4_reachs)
82: list_delete (tlvs->te_ipv4_reachs);
83: #ifdef HAVE_IPV6
84: if (tlvs->ipv6_addrs)
85: list_delete (tlvs->ipv6_addrs);
86: if (tlvs->ipv6_reachs)
87: list_delete (tlvs->ipv6_reachs);
88: #endif /* HAVE_IPV6 */
1.1.1.2 misho 89:
90: memset (tlvs, 0, sizeof (struct tlvs));
91:
1.1 misho 92: return;
93: }
94:
95: /*
96: * Parses the tlvs found in the variant length part of the PDU.
97: * Caller tells with flags in "expected" which TLV's it is interested in.
98: */
99: int
100: parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
1.1.1.2 misho 101: u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
1.1 misho 102: {
103: u_char type, length;
104: struct lan_neigh *lan_nei;
105: struct area_addr *area_addr;
106: struct is_neigh *is_nei;
107: struct te_is_neigh *te_is_nei;
108: struct es_neigh *es_nei;
109: struct lsp_entry *lsp_entry;
110: struct in_addr *ipv4_addr;
111: struct ipv4_reachability *ipv4_reach;
112: struct te_ipv4_reachability *te_ipv4_reach;
113: #ifdef HAVE_IPV6
114: struct in6_addr *ipv6_addr;
115: struct ipv6_reachability *ipv6_reach;
116: int prefix_octets;
117: #endif /* HAVE_IPV6 */
118: u_char virtual;
119: int value_len, retval = ISIS_OK;
1.1.1.3 ! misho 120: u_char *start = stream, *pnt = stream, *endpnt;
1.1 misho 121:
122: *found = 0;
123: memset (tlvs, 0, sizeof (struct tlvs));
124:
125: while (pnt < stream + size - 2)
126: {
127: type = *pnt;
128: length = *(pnt + 1);
129: pnt += 2;
130: value_len = 0;
131: if (pnt + length > stream + size)
132: {
133: zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
134: "boundaries", areatag, type, length);
135: retval = ISIS_WARNING;
136: break;
137: }
138: switch (type)
139: {
140: case AREA_ADDRESSES:
141: /* +-------+-------+-------+-------+-------+-------+-------+-------+
142: * | Address Length |
143: * +-------+-------+-------+-------+-------+-------+-------+-------+
144: * | Area Address |
145: * +-------+-------+-------+-------+-------+-------+-------+-------+
146: * : :
147: */
148: *found |= TLVFLAG_AREA_ADDRS;
149: #ifdef EXTREME_TLV_DEBUG
150: zlog_debug ("TLV Area Adresses len %d", length);
151: #endif /* EXTREME_TLV_DEBUG */
152: if (*expected & TLVFLAG_AREA_ADDRS)
153: {
154: while (length > value_len)
155: {
156: area_addr = (struct area_addr *) pnt;
157: value_len += area_addr->addr_len + 1;
158: pnt += area_addr->addr_len + 1;
159: if (!tlvs->area_addrs)
160: tlvs->area_addrs = list_new ();
161: listnode_add (tlvs->area_addrs, area_addr);
162: }
163: }
164: else
165: {
166: pnt += length;
167: }
168: break;
169:
170: case IS_NEIGHBOURS:
171: *found |= TLVFLAG_IS_NEIGHS;
172: #ifdef EXTREME_TLV_DEBUG
173: zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
174: areatag, length);
175: #endif /* EXTREME_TLV_DEBUG */
176: if (TLVFLAG_IS_NEIGHS & *expected)
177: {
178: /* +-------+-------+-------+-------+-------+-------+-------+-------+
179: * | Virtual Flag |
180: * +-------+-------+-------+-------+-------+-------+-------+-------+
181: */
182: virtual = *pnt; /* FIXME: what is the use for this? */
183: pnt++;
184: value_len++;
185: /* +-------+-------+-------+-------+-------+-------+-------+-------+
186: * | 0 | I/E | Default Metric |
187: * +-------+-------+-------+-------+-------+-------+-------+-------+
188: * | S | I/E | Delay Metric |
189: * +-------+-------+-------+-------+-------+-------+-------+-------+
190: * | S | I/E | Expense Metric |
191: * +-------+-------+-------+-------+-------+-------+-------+-------+
192: * | S | I/E | Error Metric |
193: * +-------+-------+-------+-------+-------+-------+-------+-------+
194: * | Neighbour ID |
195: * +---------------------------------------------------------------+
196: * : :
197: */
198: while (length > value_len)
199: {
200: is_nei = (struct is_neigh *) pnt;
201: value_len += 4 + ISIS_SYS_ID_LEN + 1;
202: pnt += 4 + ISIS_SYS_ID_LEN + 1;
203: if (!tlvs->is_neighs)
204: tlvs->is_neighs = list_new ();
205: listnode_add (tlvs->is_neighs, is_nei);
206: }
207: }
208: else
209: {
210: pnt += length;
211: }
212: break;
213:
214: case TE_IS_NEIGHBOURS:
215: /* +-------+-------+-------+-------+-------+-------+-------+-------+
216: * | Neighbour ID | 7
217: * +---------------------------------------------------------------+
218: * | TE Metric | 3
219: * +---------------------------------------------------------------+
220: * | SubTLVs Length | 1
221: * +---------------------------------------------------------------+
222: * : :
223: */
224: *found |= TLVFLAG_TE_IS_NEIGHS;
225: #ifdef EXTREME_TLV_DEBUG
226: zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
227: areatag, length);
228: #endif /* EXTREME_TLV_DEBUG */
229: if (TLVFLAG_TE_IS_NEIGHS & *expected)
230: {
231: while (length > value_len)
232: {
233: te_is_nei = (struct te_is_neigh *) pnt;
234: value_len += 11;
235: pnt += 11;
236: /* FIXME - subtlvs are handled here, for now we skip */
237: value_len += te_is_nei->sub_tlvs_length;
238: pnt += te_is_nei->sub_tlvs_length;
239:
240: if (!tlvs->te_is_neighs)
241: tlvs->te_is_neighs = list_new ();
242: listnode_add (tlvs->te_is_neighs, te_is_nei);
243: }
244: }
245: else
246: {
247: pnt += length;
248: }
249: break;
250:
251: case ES_NEIGHBOURS:
252: /* +-------+-------+-------+-------+-------+-------+-------+-------+
253: * | 0 | I/E | Default Metric |
254: * +-------+-------+-------+-------+-------+-------+-------+-------+
255: * | S | I/E | Delay Metric |
256: * +-------+-------+-------+-------+-------+-------+-------+-------+
257: * | S | I/E | Expense Metric |
258: * +-------+-------+-------+-------+-------+-------+-------+-------+
259: * | S | I/E | Error Metric |
260: * +-------+-------+-------+-------+-------+-------+-------+-------+
261: * | Neighbour ID |
262: * +---------------------------------------------------------------+
263: * | Neighbour ID |
264: * +---------------------------------------------------------------+
265: * : :
266: */
267: #ifdef EXTREME_TLV_DEBUG
268: zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
269: areatag, length);
270: #endif /* EXTREME_TLV_DEBUG */
271: *found |= TLVFLAG_ES_NEIGHS;
272: if (*expected & TLVFLAG_ES_NEIGHS)
273: {
274: es_nei = (struct es_neigh *) pnt;
275: value_len += 4;
276: pnt += 4;
277: while (length > value_len)
278: {
279: /* FIXME FIXME FIXME - add to the list */
280: /* sys_id->id = pnt; */
281: value_len += ISIS_SYS_ID_LEN;
282: pnt += ISIS_SYS_ID_LEN;
283: /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
284: }
285: if (!tlvs->es_neighs)
286: tlvs->es_neighs = list_new ();
287: listnode_add (tlvs->es_neighs, es_nei);
288: }
289: else
290: {
291: pnt += length;
292: }
293: break;
294:
295: case LAN_NEIGHBOURS:
296: /* +-------+-------+-------+-------+-------+-------+-------+-------+
297: * | LAN Address |
298: * +-------+-------+-------+-------+-------+-------+-------+-------+
299: * : :
300: */
301: *found |= TLVFLAG_LAN_NEIGHS;
302: #ifdef EXTREME_TLV_DEBUG
303: zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
304: areatag, length);
305: #endif /* EXTREME_TLV_DEBUG */
306: if (TLVFLAG_LAN_NEIGHS & *expected)
307: {
308: while (length > value_len)
309: {
310: lan_nei = (struct lan_neigh *) pnt;
311: if (!tlvs->lan_neighs)
312: tlvs->lan_neighs = list_new ();
313: listnode_add (tlvs->lan_neighs, lan_nei);
314: value_len += ETH_ALEN;
315: pnt += ETH_ALEN;
316: }
317: }
318: else
319: {
320: pnt += length;
321: }
322: break;
323:
324: case PADDING:
325: #ifdef EXTREME_TLV_DEBUG
326: zlog_debug ("TLV padding %d", length);
327: #endif /* EXTREME_TLV_DEBUG */
328: pnt += length;
329: break;
330:
331: case LSP_ENTRIES:
332: /* +-------+-------+-------+-------+-------+-------+-------+-------+
333: * | Remaining Lifetime | 2
334: * +-------+-------+-------+-------+-------+-------+-------+-------+
335: * | LSP ID | id+2
336: * +-------+-------+-------+-------+-------+-------+-------+-------+
337: * | LSP Sequence Number | 4
338: * +-------+-------+-------+-------+-------+-------+-------+-------+
339: * | Checksum | 2
340: * +-------+-------+-------+-------+-------+-------+-------+-------+
341: */
342: #ifdef EXTREME_TLV_DEBUG
343: zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
344: #endif /* EXTREME_TLV_DEBUG */
345: *found |= TLVFLAG_LSP_ENTRIES;
346: if (TLVFLAG_LSP_ENTRIES & *expected)
347: {
348: while (length > value_len)
349: {
350: lsp_entry = (struct lsp_entry *) pnt;
351: value_len += 10 + ISIS_SYS_ID_LEN;
352: pnt += 10 + ISIS_SYS_ID_LEN;
353: if (!tlvs->lsp_entries)
354: tlvs->lsp_entries = list_new ();
355: listnode_add (tlvs->lsp_entries, lsp_entry);
356: }
357: }
358: else
359: {
360: pnt += length;
361: }
362: break;
363:
364: case CHECKSUM:
365: /* +-------+-------+-------+-------+-------+-------+-------+-------+
366: * | 16 bit fletcher CHECKSUM |
367: * +-------+-------+-------+-------+-------+-------+-------+-------+
368: * : :
369: */
370: *found |= TLVFLAG_CHECKSUM;
371: #ifdef EXTREME_TLV_DEBUG
372: zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
373: #endif /* EXTREME_TLV_DEBUG */
374: if (*expected & TLVFLAG_CHECKSUM)
375: {
376: tlvs->checksum = (struct checksum *) pnt;
377: }
378: pnt += length;
379: break;
380:
381: case PROTOCOLS_SUPPORTED:
382: /* +-------+-------+-------+-------+-------+-------+-------+-------+
383: * | NLPID |
384: * +-------+-------+-------+-------+-------+-------+-------+-------+
385: * : :
386: */
387: *found |= TLVFLAG_NLPID;
388: #ifdef EXTREME_TLV_DEBUG
389: zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
390: areatag, length);
391: #endif /* EXTREME_TLV_DEBUG */
392: if (*expected & TLVFLAG_NLPID)
393: {
394: tlvs->nlpids = (struct nlpids *) (pnt - 1);
395: }
396: pnt += length;
397: break;
398:
399: case IPV4_ADDR:
400: /* +-------+-------+-------+-------+-------+-------+-------+-------+
401: * + IP version 4 address + 4
402: * +-------+-------+-------+-------+-------+-------+-------+-------+
403: * : :
404: */
405: *found |= TLVFLAG_IPV4_ADDR;
406: #ifdef EXTREME_TLV_DEBUG
407: zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
408: areatag, length);
409: #endif /* EXTREME_TLV_DEBUG */
410: if (*expected & TLVFLAG_IPV4_ADDR)
411: {
412: while (length > value_len)
413: {
414: ipv4_addr = (struct in_addr *) pnt;
415: #ifdef EXTREME_TLV_DEBUG
416: zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
417: inet_ntoa (*ipv4_addr), pnt);
418: #endif /* EXTREME_TLV_DEBUG */
419: if (!tlvs->ipv4_addrs)
420: tlvs->ipv4_addrs = list_new ();
421: listnode_add (tlvs->ipv4_addrs, ipv4_addr);
422: value_len += 4;
423: pnt += 4;
424: }
425: }
426: else
427: {
428: pnt += length;
429: }
430: break;
431:
432: case AUTH_INFO:
433: *found |= TLVFLAG_AUTH_INFO;
434: #ifdef EXTREME_TLV_DEBUG
435: zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
436: areatag);
437: #endif
438: if (*expected & TLVFLAG_AUTH_INFO)
439: {
440: tlvs->auth_info.type = *pnt;
1.1.1.2 misho 441: if (length == 0)
442: {
443: zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
444: "incorrect.", areatag, type, length);
445: return ISIS_WARNING;
446: }
447: --length;
448: tlvs->auth_info.len = length;
1.1 misho 449: pnt++;
1.1.1.2 misho 450: memcpy (tlvs->auth_info.passwd, pnt, length);
451: /* Return the authentication tlv pos for later computation
452: * of MD5 (RFC 5304, 2)
453: */
454: if (auth_tlv_offset)
455: *auth_tlv_offset += (pnt - start - 3);
456: pnt += length;
1.1 misho 457: }
458: else
459: {
460: pnt += length;
461: }
462: break;
463:
464: case DYNAMIC_HOSTNAME:
465: *found |= TLVFLAG_DYN_HOSTNAME;
466: #ifdef EXTREME_TLV_DEBUG
467: zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
468: areatag, length);
469: #endif /* EXTREME_TLV_DEBUG */
470: if (*expected & TLVFLAG_DYN_HOSTNAME)
471: {
472: /* the length is also included in the pointed struct */
473: tlvs->hostname = (struct hostname *) (pnt - 1);
474: }
475: pnt += length;
476: break;
477:
478: case TE_ROUTER_ID:
479: /* +---------------------------------------------------------------+
480: * + Router ID + 4
481: * +---------------------------------------------------------------+
482: */
483: *found |= TLVFLAG_TE_ROUTER_ID;
484: #ifdef EXTREME_TLV_DEBUG
485: zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
486: #endif /* EXTREME_TLV_DEBUG */
487: if (*expected & TLVFLAG_TE_ROUTER_ID)
488: tlvs->router_id = (struct te_router_id *) (pnt);
489: pnt += length;
490: break;
491:
492: case IPV4_INT_REACHABILITY:
493: /* +-------+-------+-------+-------+-------+-------+-------+-------+
494: * | 0 | I/E | Default Metric | 1
495: * +-------+-------+-------+-------+-------+-------+-------+-------+
496: * | S | I/E | Delay Metric | 1
497: * +-------+-------+-------+-------+-------+-------+-------+-------+
498: * | S | I/E | Expense Metric | 1
499: * +-------+-------+-------+-------+-------+-------+-------+-------+
500: * | S | I/E | Error Metric | 1
501: * +-------+-------+-------+-------+-------+-------+-------+-------+
502: * | ip address | 4
503: * +---------------------------------------------------------------+
504: * | address mask | 4
505: * +---------------------------------------------------------------+
506: * : :
507: */
508: *found |= TLVFLAG_IPV4_INT_REACHABILITY;
509: #ifdef EXTREME_TLV_DEBUG
510: zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
511: areatag, length);
512: #endif /* EXTREME_TLV_DEBUG */
513: if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
514: {
515: while (length > value_len)
516: {
517: ipv4_reach = (struct ipv4_reachability *) pnt;
518: if (!tlvs->ipv4_int_reachs)
519: tlvs->ipv4_int_reachs = list_new ();
520: listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
521: value_len += 12;
522: pnt += 12;
523: }
524: }
525: else
526: {
527: pnt += length;
528: }
529: break;
530:
531: case IPV4_EXT_REACHABILITY:
532: /* +-------+-------+-------+-------+-------+-------+-------+-------+
533: * | 0 | I/E | Default Metric | 1
534: * +-------+-------+-------+-------+-------+-------+-------+-------+
535: * | S | I/E | Delay Metric | 1
536: * +-------+-------+-------+-------+-------+-------+-------+-------+
537: * | S | I/E | Expense Metric | 1
538: * +-------+-------+-------+-------+-------+-------+-------+-------+
539: * | S | I/E | Error Metric | 1
540: * +-------+-------+-------+-------+-------+-------+-------+-------+
541: * | ip address | 4
542: * +---------------------------------------------------------------+
543: * | address mask | 4
544: * +---------------------------------------------------------------+
545: * : :
546: */
547: *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
548: #ifdef EXTREME_TLV_DEBUG
549: zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
550: areatag, length);
551: #endif /* EXTREME_TLV_DEBUG */
552: if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
553: {
554: while (length > value_len)
555: {
556: ipv4_reach = (struct ipv4_reachability *) pnt;
557: if (!tlvs->ipv4_ext_reachs)
558: tlvs->ipv4_ext_reachs = list_new ();
559: listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
560: value_len += 12;
561: pnt += 12;
562: }
563: }
564: else
565: {
566: pnt += length;
567: }
568: break;
569:
570: case TE_IPV4_REACHABILITY:
571: /* +-------+-------+-------+-------+-------+-------+-------+-------+
572: * | TE Metric | 4
573: * +-------+-------+-------+-------+-------+-------+-------+-------+
574: * | U/D | sTLV? | Prefix Mask Len | 1
575: * +-------+-------+-------+-------+-------+-------+-------+-------+
576: * | Prefix | 0-4
577: * +---------------------------------------------------------------+
578: * | sub tlvs |
579: * +---------------------------------------------------------------+
580: * : :
581: */
582: *found |= TLVFLAG_TE_IPV4_REACHABILITY;
583: #ifdef EXTREME_TLV_DEBUG
584: zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
585: areatag, length);
586: #endif /* EXTREME_TLV_DEBUG */
1.1.1.3 ! misho 587: endpnt = pnt + length;
1.1 misho 588: if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
589: {
590: while (length > value_len)
591: {
592: te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
1.1.1.3 ! misho 593: if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
! 594: {
! 595: zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
! 596: "ability prefix length %d", areatag,
! 597: te_ipv4_reach->control & 0x3F);
! 598: retval = ISIS_WARNING;
! 599: break;
! 600: }
1.1 misho 601: if (!tlvs->te_ipv4_reachs)
602: tlvs->te_ipv4_reachs = list_new ();
603: listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
604: /* this trickery is permitable since no subtlvs are defined */
605: value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
606: ((((te_ipv4_reach->control & 0x3F) -
607: 1) >> 3) + 1) : 0);
608: pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
609: ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
610: }
611: }
1.1.1.3 ! misho 612:
! 613: pnt = endpnt;
1.1 misho 614: break;
615:
616: #ifdef HAVE_IPV6
617: case IPV6_ADDR:
618: /* +-------+-------+-------+-------+-------+-------+-------+-------+
619: * + IP version 6 address + 16
620: * +-------+-------+-------+-------+-------+-------+-------+-------+
621: * : :
622: */
623: *found |= TLVFLAG_IPV6_ADDR;
624: #ifdef EXTREME_TLV_DEBUG
625: zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
626: areatag, length);
627: #endif /* EXTREME_TLV_DEBUG */
628: if (*expected & TLVFLAG_IPV6_ADDR)
629: {
630: while (length > value_len)
631: {
632: ipv6_addr = (struct in6_addr *) pnt;
633: if (!tlvs->ipv6_addrs)
634: tlvs->ipv6_addrs = list_new ();
635: listnode_add (tlvs->ipv6_addrs, ipv6_addr);
636: value_len += 16;
637: pnt += 16;
638: }
639: }
640: else
641: {
642: pnt += length;
643: }
644: break;
645:
646: case IPV6_REACHABILITY:
647: /* +-------+-------+-------+-------+-------+-------+-------+-------+
648: * | Default Metric | 4
649: * +-------+-------+-------+-------+-------+-------+-------+-------+
650: * | Control Informantion |
651: * +---------------------------------------------------------------+
652: * | IPv6 Prefix Length |--+
653: * +---------------------------------------------------------------+ |
654: * | IPv6 Prefix |<-+
655: * +---------------------------------------------------------------+
656: */
657: *found |= TLVFLAG_IPV6_REACHABILITY;
1.1.1.3 ! misho 658: endpnt = pnt + length;
! 659:
1.1 misho 660: if (*expected & TLVFLAG_IPV6_REACHABILITY)
661: {
662: while (length > value_len)
663: {
664: ipv6_reach = (struct ipv6_reachability *) pnt;
1.1.1.3 ! misho 665: if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
! 666: {
! 667: zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
! 668: "ability prefix length %d", areatag,
! 669: ipv6_reach->prefix_len);
! 670: retval = ISIS_WARNING;
! 671: break;
! 672: }
! 673:
1.1 misho 674: prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
675: value_len += prefix_octets + 6;
676: pnt += prefix_octets + 6;
677: /* FIXME: sub-tlvs */
678: if (!tlvs->ipv6_reachs)
679: tlvs->ipv6_reachs = list_new ();
680: listnode_add (tlvs->ipv6_reachs, ipv6_reach);
681: }
682: }
1.1.1.3 ! misho 683:
! 684: pnt = endpnt;
1.1 misho 685: break;
686: #endif /* HAVE_IPV6 */
687:
688: case WAY3_HELLO:
689: /* +---------------------------------------------------------------+
690: * | Adjacency state | 1
691: * +---------------------------------------------------------------+
692: * | Extended Local Circuit ID | 4
693: * +---------------------------------------------------------------+
694: * | Neighbor System ID (If known) | 0-8
695: * (probably 6)
696: * +---------------------------------------------------------------+
697: * | Neighbor Local Circuit ID (If known) | 4
698: * +---------------------------------------------------------------+
699: */
700: *found |= TLVFLAG_3WAY_HELLO;
701: if (*expected & TLVFLAG_3WAY_HELLO)
702: {
703: while (length > value_len)
704: {
705: /* FIXME: make this work */
706: /* Adjacency State (one octet):
707: 0 = Up
708: 1 = Initializing
709: 2 = Down
710: Extended Local Circuit ID (four octets)
711: Neighbor System ID if known (zero to eight octets)
712: Neighbor Extended Local Circuit ID (four octets, if Neighbor
713: System ID is present) */
714: pnt += length;
1.1.1.3 ! misho 715: value_len += length;
1.1 misho 716: }
717: }
718: else
719: {
720: pnt += length;
721: }
722:
723: break;
724: case GRACEFUL_RESTART:
725: /* +-------+-------+-------+-------+-------+-------+-------+-------+
726: * | Reserved | SA | RA | RR | 1
727: * +-------+-------+-------+-------+-------+-------+-------+-------+
728: * | Remaining Time | 2
729: * +---------------------------------------------------------------+
730: * | Restarting Neighbor ID (If known) | 0-8
731: * +---------------------------------------------------------------+
732: */
733: *found |= TLVFLAG_GRACEFUL_RESTART;
734: if (*expected & TLVFLAG_GRACEFUL_RESTART)
735: {
736: /* FIXME: make this work */
737: }
738: pnt += length;
739: break;
740:
741: default:
742: zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
743: areatag, type, length);
744:
745: retval = ISIS_WARNING;
746: pnt += length;
747: break;
748: }
749: }
750:
751: return retval;
752: }
753:
754: int
755: add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
756: {
1.1.1.2 misho 757: if ((stream_get_size (stream) - stream_get_endp (stream)) <
758: (((unsigned)len) + 2))
1.1 misho 759: {
1.1.1.2 misho 760: zlog_warn ("No room for TLV of type %d "
761: "(total size %d available %d required %d)",
762: tag, (int)stream_get_size (stream),
763: (int)(stream_get_size (stream) - stream_get_endp (stream)),
764: len+2);
1.1 misho 765: return ISIS_WARNING;
766: }
767:
768: stream_putc (stream, tag); /* TAG */
769: stream_putc (stream, len); /* LENGTH */
770: stream_put (stream, value, (int) len); /* VALUE */
771:
772: #ifdef EXTREME_DEBUG
773: zlog_debug ("Added TLV %d len %d", tag, len);
774: #endif /* EXTREME DEBUG */
775: return ISIS_OK;
776: }
777:
778: int
779: tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
780: {
781: struct listnode *node;
782: struct area_addr *area_addr;
783:
784: u_char value[255];
785: u_char *pos = value;
786:
787: for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
788: {
789: if (pos - value + area_addr->addr_len > 255)
790: goto err;
791: *pos = area_addr->addr_len;
792: pos++;
793: memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
794: pos += area_addr->addr_len;
795: }
796:
797: return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
798:
799: err:
800: zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
801: return ISIS_WARNING;
802: }
803:
804: int
805: tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
806: {
807: struct listnode *node;
808: struct is_neigh *is_neigh;
809: u_char value[255];
810: u_char *pos = value;
811: int retval;
812:
813: *pos = 0; /*is_neigh->virtual; */
814: pos++;
815:
816: for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
817: {
818: if (pos - value + IS_NEIGHBOURS_LEN > 255)
819: {
820: retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
821: if (retval != ISIS_OK)
822: return retval;
823: pos = value;
824: }
825: *pos = is_neigh->metrics.metric_default;
826: pos++;
827: *pos = is_neigh->metrics.metric_delay;
828: pos++;
829: *pos = is_neigh->metrics.metric_expense;
830: pos++;
831: *pos = is_neigh->metrics.metric_error;
832: pos++;
833: memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
834: pos += ISIS_SYS_ID_LEN + 1;
835: }
836:
837: return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
838: }
839:
840: int
841: tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
842: {
843: struct listnode *node;
844: struct te_is_neigh *te_is_neigh;
845: u_char value[255];
846: u_char *pos = value;
847: int retval;
848:
849: for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
850: {
851: /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
852: if (pos - value + IS_NEIGHBOURS_LEN > 255)
853: {
854: retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
855: if (retval != ISIS_OK)
856: return retval;
857: pos = value;
858: }
859:
860: memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
861: pos += ISIS_SYS_ID_LEN + 1;
862: memcpy (pos, te_is_neigh->te_metric, 3);
863: pos += 3;
864: /* Sub TLVs length. */
865: *pos = 0;
866: pos++;
867: }
868:
869: return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
870: }
871:
872: int
873: tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
874: {
875: struct listnode *node;
876: u_char *snpa;
877: u_char value[255];
878: u_char *pos = value;
879: int retval;
880:
881: for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
882: {
883: if (pos - value + ETH_ALEN > 255)
884: {
885: retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
886: if (retval != ISIS_OK)
887: return retval;
888: pos = value;
889: }
890: memcpy (pos, snpa, ETH_ALEN);
891: pos += ETH_ALEN;
892: }
893:
894: return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
895: }
896:
897: int
898: tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
899: {
900: return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
901: }
902:
903: int
1.1.1.2 misho 904: tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
1.1 misho 905: struct stream *stream)
906: {
907: u_char value[255];
908: u_char *pos = value;
1.1.1.2 misho 909: *pos++ = auth_type;
1.1 misho 910: memcpy (pos, auth_value, auth_len);
911:
912: return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
913: }
914:
915: int
916: tlv_add_checksum (struct checksum *checksum, struct stream *stream)
917: {
918: u_char value[255];
919: u_char *pos = value;
920: return add_tlv (CHECKSUM, pos - value, value, stream);
921: }
922:
923: int
924: tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
925: {
926: struct listnode *node;
927: struct prefix_ipv4 *ipv4;
928: u_char value[255];
929: u_char *pos = value;
930: int retval;
931:
932: for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
933: {
934: if (pos - value + IPV4_MAX_BYTELEN > 255)
935: {
1.1.1.3 ! misho 936: /* RFC 1195 s4.2: only one tuple of 63 allowed. */
! 937: zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
! 938: break;
1.1 misho 939: }
940: *(u_int32_t *) pos = ipv4->prefix.s_addr;
941: pos += IPV4_MAX_BYTELEN;
942: }
943:
944: return add_tlv (IPV4_ADDR, pos - value, value, stream);
945: }
946:
947: /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
948: * (in case of LSP) or TE router ID TLV. */
949: int
950: tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
951: {
952: u_char value[255];
953: u_char *pos = value;
954:
955: memcpy (pos, addr, IPV4_MAX_BYTELEN);
956: pos += IPV4_MAX_BYTELEN;
957:
958: return add_tlv (tag, pos - value, value, stream);
959: }
960:
961: int
962: tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
963: {
964: return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
965: stream);
966: }
967:
968: int
969: tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
970: {
971: struct listnode *node;
972: struct isis_lsp *lsp;
973: u_char value[255];
974: u_char *pos = value;
975: int retval;
976:
977: for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
978: {
979: if (pos - value + LSP_ENTRIES_LEN > 255)
980: {
981: retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
982: if (retval != ISIS_OK)
983: return retval;
984: pos = value;
985: }
986: *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
987: pos += 2;
988: memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
989: pos += ISIS_SYS_ID_LEN + 2;
990: *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
991: pos += 4;
992: *((u_int16_t *) pos) = lsp->lsp_header->checksum;
993: pos += 2;
994: }
995:
996: return add_tlv (LSP_ENTRIES, pos - value, value, stream);
997: }
998:
999: int
1000: tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
1001: {
1002: struct listnode *node;
1003: struct ipv4_reachability *reach;
1004: u_char value[255];
1005: u_char *pos = value;
1006: int retval;
1007:
1008: for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
1009: {
1010: if (pos - value + IPV4_REACH_LEN > 255)
1011: {
1012: retval =
1013: add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1014: if (retval != ISIS_OK)
1015: return retval;
1016: pos = value;
1017: }
1018: *pos = reach->metrics.metric_default;
1019: pos++;
1020: *pos = reach->metrics.metric_delay;
1021: pos++;
1022: *pos = reach->metrics.metric_expense;
1023: pos++;
1024: *pos = reach->metrics.metric_error;
1025: pos++;
1026: *(u_int32_t *) pos = reach->prefix.s_addr;
1027: pos += IPV4_MAX_BYTELEN;
1028: *(u_int32_t *) pos = reach->mask.s_addr;
1029: pos += IPV4_MAX_BYTELEN;
1030: }
1031:
1032: return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1033: }
1034:
1035: int
1036: tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1037: {
1038: struct listnode *node;
1039: struct te_ipv4_reachability *te_reach;
1040: u_char value[255];
1041: u_char *pos = value;
1042: u_char prefix_size;
1043: int retval;
1044:
1045: for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
1046: {
1047: prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1048:
1049: if (pos - value + (5 + prefix_size) > 255)
1050: {
1051: retval =
1.1.1.2 misho 1052: add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1.1 misho 1053: if (retval != ISIS_OK)
1054: return retval;
1055: pos = value;
1056: }
1057: *(u_int32_t *) pos = te_reach->te_metric;
1058: pos += 4;
1059: *pos = te_reach->control;
1060: pos++;
1061: memcpy (pos, &te_reach->prefix_start, prefix_size);
1062: pos += prefix_size;
1063: }
1064:
1065: return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1066: }
1067:
1068: #ifdef HAVE_IPV6
1069: int
1070: tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1071: {
1072: struct listnode *node;
1073: struct prefix_ipv6 *ipv6;
1074: u_char value[255];
1075: u_char *pos = value;
1076: int retval;
1077:
1078: for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
1079: {
1080: if (pos - value + IPV6_MAX_BYTELEN > 255)
1081: {
1082: retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1083: if (retval != ISIS_OK)
1084: return retval;
1085: pos = value;
1086: }
1087: memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1088: pos += IPV6_MAX_BYTELEN;
1089: }
1090:
1091: return add_tlv (IPV6_ADDR, pos - value, value, stream);
1092: }
1093:
1094: int
1095: tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1096: {
1097: struct listnode *node;
1098: struct ipv6_reachability *ip6reach;
1099: u_char value[255];
1100: u_char *pos = value;
1101: int retval, prefix_octets;
1102:
1103: for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
1104: {
1105: if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1106: {
1107: retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1108: if (retval != ISIS_OK)
1109: return retval;
1110: pos = value;
1111: }
1112: *(uint32_t *) pos = ip6reach->metric;
1113: pos += 4;
1114: *pos = ip6reach->control_info;
1115: pos++;
1116: prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1117: *pos = ip6reach->prefix_len;
1118: pos++;
1119: memcpy (pos, ip6reach->prefix, prefix_octets);
1120: pos += prefix_octets;
1121: }
1122:
1123: return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1124: }
1125: #endif /* HAVE_IPV6 */
1126:
1127: int
1128: tlv_add_padding (struct stream *stream)
1129: {
1130: int fullpads, i, left;
1131:
1132: /*
1133: * How many times can we add full padding ?
1134: */
1.1.1.2 misho 1135: fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
1.1 misho 1136: for (i = 0; i < fullpads; i++)
1137: {
1138: if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1139: goto err;
1140: if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1141: goto err;
1142: stream_put (stream, NULL, 255); /* zero padding */
1143: }
1144:
1.1.1.2 misho 1145: left = stream_get_size (stream) - stream_get_endp (stream);
1.1 misho 1146:
1147: if (left < 2)
1148: return ISIS_OK;
1149:
1150: if (left == 2)
1151: {
1152: stream_putc (stream, PADDING);
1153: stream_putc (stream, 0);
1154: return ISIS_OK;
1155: }
1156:
1157: stream_putc (stream, PADDING);
1158: stream_putc (stream, left - 2);
1159: stream_put (stream, NULL, left-2);
1160:
1161: return ISIS_OK;
1162:
1163: err:
1164: zlog_warn ("tlv_add_padding(): no room for tlv");
1165: return ISIS_WARNING;
1166: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>