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