Annotation of embedaddon/quagga/isisd/isis_pdu.c, revision 1.1.1.4
1.1 misho 1: /*
2: * IS-IS Rout(e)ing protocol - isis_pdu.c
3: * PDU processing
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 "memory.h"
27: #include "thread.h"
28: #include "linklist.h"
29: #include "log.h"
30: #include "stream.h"
31: #include "vty.h"
32: #include "hash.h"
33: #include "prefix.h"
34: #include "if.h"
35: #include "checksum.h"
1.1.1.2 misho 36: #include "md5.h"
1.1 misho 37:
38: #include "isisd/dict.h"
39: #include "isisd/include-netbsd/iso.h"
40: #include "isisd/isis_constants.h"
41: #include "isisd/isis_common.h"
1.1.1.2 misho 42: #include "isisd/isis_flags.h"
1.1 misho 43: #include "isisd/isis_adjacency.h"
44: #include "isisd/isis_circuit.h"
45: #include "isisd/isis_network.h"
46: #include "isisd/isis_misc.h"
47: #include "isisd/isis_dr.h"
48: #include "isisd/isis_tlv.h"
49: #include "isisd/isisd.h"
50: #include "isisd/isis_dynhn.h"
51: #include "isisd/isis_lsp.h"
52: #include "isisd/isis_pdu.h"
53: #include "isisd/iso_checksum.h"
54: #include "isisd/isis_csm.h"
55: #include "isisd/isis_events.h"
56:
57: #define ISIS_MINIMUM_FIXED_HDR_LEN 15
58: #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
59:
60: #ifndef PNBBY
61: #define PNBBY 8
62: #endif /* PNBBY */
63:
64: /* Utility mask array. */
1.1.1.4 ! misho 65: static const u_char maskbit[] = {
1.1 misho 66: 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
67: };
68:
69: /*
70: * HELPER FUNCS
71: */
72:
73: /*
74: * Compares two sets of area addresses
75: */
76: static int
77: area_match (struct list *left, struct list *right)
78: {
79: struct area_addr *addr1, *addr2;
80: struct listnode *node1, *node2;
81:
82: for (ALL_LIST_ELEMENTS_RO (left, node1, addr1))
83: {
84: for (ALL_LIST_ELEMENTS_RO (right, node2, addr2))
85: {
86: if (addr1->addr_len == addr2->addr_len &&
87: !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len))
88: return 1; /* match */
89: }
90: }
91:
92: return 0; /* mismatch */
93: }
94:
95: /*
96: * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
97: * param ip1 the IS interface ip address structure
98: * param ip2 the IIH's ip address
99: * return 0 the IIH's IP is not in the IS's subnetwork
100: * 1 the IIH's IP is in the IS's subnetwork
101: */
102: static int
103: ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
104: {
105: u_char *addr1, *addr2;
106: int shift, offset, offsetloop;
107: int len;
108:
109: addr1 = (u_char *) & ip1->prefix.s_addr;
110: addr2 = (u_char *) & ip2->s_addr;
111: len = ip1->prefixlen;
112:
113: shift = len % PNBBY;
114: offsetloop = offset = len / PNBBY;
115:
116: while (offsetloop--)
117: if (addr1[offsetloop] != addr2[offsetloop])
118: return 0;
119:
120: if (shift)
121: if (maskbit[shift] & (addr1[offset] ^ addr2[offset]))
122: return 0;
123:
124: return 1; /* match */
125: }
126:
127: /*
128: * Compares two set of ip addresses
129: * param left the local interface's ip addresses
130: * param right the iih interface's ip address
131: * return 0 no match;
132: * 1 match;
133: */
134: static int
135: ip_match (struct list *left, struct list *right)
136: {
137: struct prefix_ipv4 *ip1;
138: struct in_addr *ip2;
139: struct listnode *node1, *node2;
140:
141: if ((left == NULL) || (right == NULL))
142: return 0;
143:
144: for (ALL_LIST_ELEMENTS_RO (left, node1, ip1))
145: {
146: for (ALL_LIST_ELEMENTS_RO (right, node2, ip2))
147: {
148: if (ip_same_subnet (ip1, ip2))
149: {
150: return 1; /* match */
151: }
152: }
153:
154: }
155: return 0;
156: }
157:
158: /*
159: * Checks whether we should accept a PDU of given level
160: */
161: static int
162: accept_level (int level, int circuit_t)
163: {
164: int retval = ((circuit_t & level) == level); /* simple approach */
165:
166: return retval;
167: }
168:
1.1.1.2 misho 169: /*
170: * Verify authentication information
171: * Support cleartext and HMAC MD5 authentication
172: */
173: static int
174: authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
175: struct stream *stream, uint32_t auth_tlv_offset)
1.1 misho 176: {
1.1.1.2 misho 177: unsigned char digest[ISIS_AUTH_MD5_SIZE];
178:
179: /* Auth fail () - passwd type mismatch */
180: if (local->type != remote->type)
181: return ISIS_ERROR;
182:
183: switch (local->type)
184: {
185: /* No authentication required */
186: case ISIS_PASSWD_TYPE_UNUSED:
187: break;
188:
189: /* Cleartext (ISO 10589) */
190: case ISIS_PASSWD_TYPE_CLEARTXT:
191: /* Auth fail () - passwd len mismatch */
192: if (remote->len != local->len)
193: return ISIS_ERROR;
194: return memcmp (local->passwd, remote->passwd, local->len);
195:
196: /* HMAC MD5 (RFC 3567) */
197: case ISIS_PASSWD_TYPE_HMAC_MD5:
198: /* Auth fail () - passwd len mismatch */
199: if (remote->len != ISIS_AUTH_MD5_SIZE)
200: return ISIS_ERROR;
201: /* Set the authentication value to 0 before the check */
202: memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
203: ISIS_AUTH_MD5_SIZE);
204: /* Compute the digest */
205: hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
206: (unsigned char *) &(local->passwd), local->len,
1.1.1.4 ! misho 207: (unsigned char *) &digest);
1.1.1.2 misho 208: /* Copy back the authentication value after the check */
209: memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
210: remote->passwd, ISIS_AUTH_MD5_SIZE);
211: return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
212:
213: default:
214: zlog_err ("Unsupported authentication type");
215: return ISIS_ERROR;
216: }
217:
218: /* Authentication pass when no authentication is configured */
219: return ISIS_OK;
220: }
221:
222: static int
223: lsp_authentication_check (struct stream *stream, struct isis_area *area,
224: int level, struct isis_passwd *passwd)
225: {
226: struct isis_link_state_hdr *hdr;
227: uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
228: uint16_t checksum, rem_lifetime, pdu_len;
229: struct tlvs tlvs;
230: int retval = ISIS_OK;
231:
232: hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
233: pdu_len = ntohs (hdr->pdu_len);
234: expected |= TLVFLAG_AUTH_INFO;
235: auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
236: retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
237: pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
238: &expected, &found, &tlvs, &auth_tlv_offset);
239:
240: if (retval != ISIS_OK)
241: {
242: zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
243: "cksum 0x%04x, lifetime %us, len %u",
244: area->area_tag, level, rawlspid_print (hdr->lsp_id),
245: ntohl (hdr->seq_num), ntohs (hdr->checksum),
246: ntohs (hdr->rem_lifetime), pdu_len);
247: if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
248: (isis->debugs & DEBUG_PACKET_DUMP))
249: zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
250: return retval;
251: }
252:
253: if (!(found & TLVFLAG_AUTH_INFO))
1.1 misho 254: {
1.1.1.2 misho 255: zlog_err ("No authentication tlv in LSP");
256: return ISIS_ERROR;
1.1 misho 257: }
1.1.1.2 misho 258:
259: if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
260: tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
1.1 misho 261: {
1.1.1.2 misho 262: zlog_err ("Unknown authentication type in LSP");
263: return ISIS_ERROR;
1.1 misho 264: }
1.1.1.2 misho 265:
266: /*
267: * RFC 5304 set checksum and remaining lifetime to zero before
268: * verification and reset to old values after verification.
269: */
270: checksum = hdr->checksum;
271: rem_lifetime = hdr->rem_lifetime;
272: hdr->checksum = 0;
273: hdr->rem_lifetime = 0;
274: retval = authentication_check (&tlvs.auth_info, passwd, stream,
275: auth_tlv_offset);
276: hdr->checksum = checksum;
277: hdr->rem_lifetime = rem_lifetime;
278:
279: return retval;
1.1 misho 280: }
281:
282: /*
283: * Processing helper functions
284: */
285: static void
1.1.1.2 misho 286: del_addr (void *val)
287: {
288: XFREE (MTYPE_ISIS_TMP, val);
289: }
290:
291: static void
292: tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
293: {
294: struct listnode *node;
295: struct area_addr *area_addr, *malloced;
296:
297: if (adj->area_addrs)
298: {
299: adj->area_addrs->del = del_addr;
300: list_delete (adj->area_addrs);
301: }
302: adj->area_addrs = list_new ();
303: if (tlvs->area_addrs)
304: {
305: for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
306: {
307: malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
308: memcpy (malloced, area_addr, sizeof (struct area_addr));
309: listnode_add (adj->area_addrs, malloced);
310: }
311: }
312: }
313:
1.1.1.3 misho 314: static int
1.1 misho 315: tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
316: {
317: int i;
318: struct nlpids *tlv_nlpids;
319:
320: if (tlvs->nlpids)
321: {
322:
323: tlv_nlpids = tlvs->nlpids;
1.1.1.3 misho 324: if (tlv_nlpids->count > array_size (adj->nlpids.nlpids))
325: return 1;
1.1 misho 326:
327: adj->nlpids.count = tlv_nlpids->count;
328:
329: for (i = 0; i < tlv_nlpids->count; i++)
330: {
331: adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
332: }
333: }
1.1.1.3 misho 334: return 0;
1.1 misho 335: }
336:
337: static void
338: tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
339: {
340: struct listnode *node;
341: struct in_addr *ipv4_addr, *malloced;
342:
343: if (adj->ipv4_addrs)
344: {
1.1.1.2 misho 345: adj->ipv4_addrs->del = del_addr;
1.1 misho 346: list_delete (adj->ipv4_addrs);
347: }
348: adj->ipv4_addrs = list_new ();
349: if (tlvs->ipv4_addrs)
350: {
351: for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr))
352: {
353: malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
354: memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
355: listnode_add (adj->ipv4_addrs, malloced);
356: }
357: }
358: }
359:
360: #ifdef HAVE_IPV6
361: static void
362: tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
363: {
364: struct listnode *node;
365: struct in6_addr *ipv6_addr, *malloced;
366:
367: if (adj->ipv6_addrs)
368: {
1.1.1.2 misho 369: adj->ipv6_addrs->del = del_addr;
1.1 misho 370: list_delete (adj->ipv6_addrs);
371: }
372: adj->ipv6_addrs = list_new ();
373: if (tlvs->ipv6_addrs)
374: {
375: for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr))
376: {
377: malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
378: memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
379: listnode_add (adj->ipv6_addrs, malloced);
380: }
381: }
382:
383: }
384: #endif /* HAVE_IPV6 */
385:
386: /*
387: * RECEIVE SIDE
388: */
389:
390: /*
391: * Process P2P IIH
392: * ISO - 10589
393: * Section 8.2.5 - Receiving point-to-point IIH PDUs
394: *
395: */
396: static int
397: process_p2p_hello (struct isis_circuit *circuit)
398: {
399: int retval = ISIS_OK;
400: struct isis_p2p_hello_hdr *hdr;
401: struct isis_adjacency *adj;
1.1.1.2 misho 402: u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
403: uint16_t pdu_len;
1.1 misho 404: struct tlvs tlvs;
1.1.1.4 ! misho 405: int v4_usable = 0, v6_usable = 0;
1.1 misho 406:
1.1.1.2 misho 407: if (isis->debugs & DEBUG_ADJ_PACKETS)
408: {
409: zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
410: circuit->area->area_tag, circuit->interface->name,
411: circuit_t2string (circuit->is_type), circuit->circuit_id);
412: if (isis->debugs & DEBUG_PACKET_DUMP)
413: zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
414: stream_get_endp (circuit->rcv_stream));
415: }
416:
417: if (circuit->circ_type != CIRCUIT_T_P2P)
418: {
419: zlog_warn ("p2p hello on non p2p circuit");
420: return ISIS_WARNING;
421: }
422:
1.1 misho 423: if ((stream_get_endp (circuit->rcv_stream) -
424: stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
425: {
426: zlog_warn ("Packet too short");
427: return ISIS_WARNING;
428: }
429:
430: /* 8.2.5.1 PDU acceptance tests */
431:
432: /* 8.2.5.1 a) external domain untrue */
433: /* FIXME: not useful at all? */
434:
435: /* 8.2.5.1 b) ID Length mismatch */
436: /* checked at the handle_pdu */
437:
438: /* 8.2.5.2 IIH PDU Processing */
439:
440: /* 8.2.5.2 a) 1) Maximum Area Addresses */
441: /* Already checked, and can also be ommited */
442:
443: /*
444: * Get the header
445: */
446: hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
1.1.1.2 misho 447: pdu_len = ntohs (hdr->pdu_len);
1.1 misho 448:
1.1.1.3 misho 449: if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) ||
450: pdu_len > ISO_MTU(circuit) ||
1.1.1.2 misho 451: pdu_len > stream_get_endp (circuit->rcv_stream))
1.1 misho 452: {
1.1.1.2 misho 453: zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
454: "invalid pdu length %d",
455: circuit->area->area_tag, circuit->interface->name, pdu_len);
456: return ISIS_WARNING;
1.1 misho 457: }
458:
1.1.1.2 misho 459: /*
460: * Set the stream endp to PDU length, ignoring additional padding
461: * introduced by transport chips.
462: */
463: if (pdu_len < stream_get_endp (circuit->rcv_stream))
464: stream_set_endp (circuit->rcv_stream, pdu_len);
1.1 misho 465:
1.1.1.2 misho 466: stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
1.1 misho 467:
468: /*
469: * Lets get the TLVS now
470: */
471: expected |= TLVFLAG_AREA_ADDRS;
472: expected |= TLVFLAG_AUTH_INFO;
473: expected |= TLVFLAG_NLPID;
474: expected |= TLVFLAG_IPV4_ADDR;
475: expected |= TLVFLAG_IPV6_ADDR;
476:
1.1.1.2 misho 477: auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
1.1 misho 478: retval = parse_tlvs (circuit->area->area_tag,
479: STREAM_PNT (circuit->rcv_stream),
1.1.1.2 misho 480: pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
481: &expected, &found, &tlvs, &auth_tlv_offset);
1.1 misho 482:
483: if (retval > ISIS_WARNING)
484: {
1.1.1.2 misho 485: zlog_warn ("parse_tlvs() failed");
1.1 misho 486: free_tlvs (&tlvs);
487: return retval;
488: };
489:
1.1.1.2 misho 490: if (!(found & TLVFLAG_AREA_ADDRS))
491: {
492: zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
493: free_tlvs (&tlvs);
494: return ISIS_WARNING;
495: }
496:
1.1.1.3 misho 497: if (!(found & TLVFLAG_NLPID))
498: {
499: zlog_warn ("No supported protocols TLV in P2P IS to IS hello");
500: free_tlvs (&tlvs);
501: return ISIS_WARNING;
502: }
503:
1.1 misho 504: /* 8.2.5.1 c) Authentication */
505: if (circuit->passwd.type)
506: {
507: if (!(found & TLVFLAG_AUTH_INFO) ||
1.1.1.2 misho 508: authentication_check (&tlvs.auth_info, &circuit->passwd,
509: circuit->rcv_stream, auth_tlv_offset))
510: {
511: isis_event_auth_failure (circuit->area->area_tag,
512: "P2P hello authentication failure",
513: hdr->source_id);
514: free_tlvs (&tlvs);
515: return ISIS_OK;
516: }
517: }
518:
519: /*
520: * check if it's own interface ip match iih ip addrs
521: */
1.1.1.4 ! misho 522: if (found & TLVFLAG_IPV4_ADDR)
! 523: {
! 524: if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
! 525: v4_usable = 1;
! 526: else
! 527: zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
! 528: "in P2P IIH from %s\n", circuit->interface->name);
! 529: }
! 530: #ifndef HAVE_IPV6
! 531: else /* !(found & TLVFLAG_IPV4_ADDR) */
! 532: zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s "
! 533: "(this isisd has no IPv6)\n", circuit->interface->name);
! 534:
! 535: #else
! 536: if (found & TLVFLAG_IPV6_ADDR)
! 537: {
! 538: /* TBA: check that we have a linklocal ourselves? */
! 539: struct listnode *node;
! 540: struct in6_addr *ip;
! 541: for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip))
! 542: if (IN6_IS_ADDR_LINKLOCAL (ip))
! 543: {
! 544: v6_usable = 1;
! 545: break;
! 546: }
! 547:
! 548: if (!v6_usable)
! 549: zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
! 550: "in P2P IIH from %s\n", circuit->interface->name);
! 551: }
! 552:
! 553: if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
! 554: zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n",
! 555: circuit->interface->name);
! 556: #endif
! 557:
! 558: if (!v6_usable && !v4_usable)
! 559: {
! 560: free_tlvs (&tlvs);
! 561: return ISIS_WARNING;
! 562: }
! 563:
! 564: /*
! 565: * it's own p2p IIH PDU - discard
! 566: */
! 567: if (!memcmp (hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN))
1.1.1.2 misho 568: {
1.1.1.4 ! misho 569: zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded",
! 570: circuit->area->area_tag);
1.1.1.2 misho 571: free_tlvs (&tlvs);
572: return ISIS_WARNING;
573: }
574:
575: /*
576: * My interpertation of the ISO, if no adj exists we will create one for
577: * the circuit
578: */
579: adj = circuit->u.p2p.neighbor;
1.1.1.4 ! misho 580: /* If an adjacency exists, check it is with the source of the hello
! 581: * packets */
! 582: if (adj)
! 583: {
! 584: if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN))
! 585: {
! 586: zlog_debug("hello source and adjacency do not match, set adj down\n");
! 587: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist");
! 588: return 0;
! 589: }
! 590: }
1.1.1.2 misho 591: if (!adj || adj->level != hdr->circuit_t)
592: {
593: if (!adj)
594: {
595: adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
596: if (adj == NULL)
597: return ISIS_ERROR;
598: }
599: else
600: {
601: adj->level = hdr->circuit_t;
602: }
603: circuit->u.p2p.neighbor = adj;
1.1.1.4 ! misho 604: /* Build lsp with the new neighbor entry when a new
! 605: * adjacency is formed. Set adjacency circuit type to
! 606: * IIH PDU header circuit type before lsp is regenerated
! 607: * when an adjacency is up. This will result in the new
! 608: * adjacency entry getting added to the lsp tlv neighbor list.
! 609: */
! 610: adj->circuit_t = hdr->circuit_t;
1.1.1.2 misho 611: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
612: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
1.1 misho 613: }
614:
1.1.1.2 misho 615: /* 8.2.6 Monitoring point-to-point adjacencies */
616: adj->hold_time = ntohs (hdr->hold_time);
617: adj->last_upd = time (NULL);
618:
1.1 misho 619: /* we do this now because the adj may not survive till the end... */
1.1.1.2 misho 620: tlvs_to_adj_area_addrs (&tlvs, adj);
621:
622: /* which protocol are spoken ??? */
1.1.1.3 misho 623: if (tlvs_to_adj_nlpids (&tlvs, adj))
624: {
625: free_tlvs (&tlvs);
626: return ISIS_WARNING;
627: }
1.1 misho 628:
629: /* we need to copy addresses to the adj */
1.1.1.2 misho 630: if (found & TLVFLAG_IPV4_ADDR)
631: tlvs_to_adj_ipv4_addrs (&tlvs, adj);
1.1 misho 632:
633: #ifdef HAVE_IPV6
1.1.1.2 misho 634: if (found & TLVFLAG_IPV6_ADDR)
635: tlvs_to_adj_ipv6_addrs (&tlvs, adj);
1.1 misho 636: #endif /* HAVE_IPV6 */
637:
638: /* lets take care of the expiry */
639: THREAD_TIMER_OFF (adj->t_expire);
640: THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
641: (long) adj->hold_time);
642:
643: /* 8.2.5.2 a) a match was detected */
644: if (area_match (circuit->area->area_addrs, tlvs.area_addrs))
645: {
646: /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
647: if (circuit->area->is_type == IS_LEVEL_1)
648: {
649: switch (hdr->circuit_t)
650: {
651: case IS_LEVEL_1:
652: case IS_LEVEL_1_AND_2:
653: if (adj->adj_state != ISIS_ADJ_UP)
654: {
655: /* (4) adj state up */
656: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
657: /* (5) adj usage level 1 */
658: adj->adj_usage = ISIS_ADJ_LEVEL1;
659: }
660: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
661: {
662: ; /* accept */
663: }
664: break;
665: case IS_LEVEL_2:
666: if (adj->adj_state != ISIS_ADJ_UP)
667: {
668: /* (7) reject - wrong system type event */
669: zlog_warn ("wrongSystemType");
1.1.1.2 misho 670: free_tlvs (&tlvs);
1.1 misho 671: return ISIS_WARNING; /* Reject */
672: }
673: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
674: {
675: /* (6) down - wrong system */
676: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
677: }
678: break;
679: }
680: }
681:
682: /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
683: if (circuit->area->is_type == IS_LEVEL_1_AND_2)
684: {
685: switch (hdr->circuit_t)
686: {
687: case IS_LEVEL_1:
688: if (adj->adj_state != ISIS_ADJ_UP)
689: {
690: /* (6) adj state up */
691: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
692: /* (7) adj usage level 1 */
693: adj->adj_usage = ISIS_ADJ_LEVEL1;
694: }
695: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
696: {
697: ; /* accept */
698: }
699: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
700: (adj->adj_usage == ISIS_ADJ_LEVEL2))
701: {
702: /* (8) down - wrong system */
703: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
704: }
705: break;
706: case IS_LEVEL_2:
707: if (adj->adj_state != ISIS_ADJ_UP)
708: {
709: /* (6) adj state up */
710: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
711: /* (9) adj usage level 2 */
712: adj->adj_usage = ISIS_ADJ_LEVEL2;
713: }
714: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
715: (adj->adj_usage == ISIS_ADJ_LEVEL1AND2))
716: {
717: /* (8) down - wrong system */
718: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
719: }
720: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
721: {
722: ; /* Accept */
723: }
724: break;
725: case IS_LEVEL_1_AND_2:
726: if (adj->adj_state != ISIS_ADJ_UP)
727: {
728: /* (6) adj state up */
729: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
730: /* (10) adj usage level 1 */
731: adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
732: }
733: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
734: (adj->adj_usage == ISIS_ADJ_LEVEL2))
735: {
736: /* (8) down - wrong system */
737: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
738: }
739: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
740: {
741: ; /* Accept */
742: }
743: break;
744: }
745: }
746:
747: /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
748: if (circuit->area->is_type == IS_LEVEL_2)
749: {
750: switch (hdr->circuit_t)
751: {
752: case IS_LEVEL_1:
753: if (adj->adj_state != ISIS_ADJ_UP)
754: {
755: /* (5) reject - wrong system type event */
756: zlog_warn ("wrongSystemType");
1.1.1.2 misho 757: free_tlvs (&tlvs);
1.1 misho 758: return ISIS_WARNING; /* Reject */
759: }
760: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
761: (adj->adj_usage == ISIS_ADJ_LEVEL2))
762: {
763: /* (6) down - wrong system */
764: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
765: }
766: break;
767: case IS_LEVEL_1_AND_2:
768: case IS_LEVEL_2:
769: if (adj->adj_state != ISIS_ADJ_UP)
770: {
771: /* (7) adj state up */
772: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
773: /* (8) adj usage level 2 */
774: adj->adj_usage = ISIS_ADJ_LEVEL2;
775: }
776: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
777: {
778: /* (6) down - wrong system */
779: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
780: }
781: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
782: {
783: ; /* Accept */
784: }
785: break;
786: }
787: }
788: }
789: /* 8.2.5.2 b) if no match was detected */
1.1.1.2 misho 790: else if (listcount (circuit->area->area_addrs) > 0)
1.1 misho 791: {
792: if (circuit->area->is_type == IS_LEVEL_1)
793: {
794: /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
795: if (adj->adj_state != ISIS_ADJ_UP)
796: {
797: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
798: /* 8.2.5.2 b) 2)is_type L1 and adj is up */
799: }
800: else
801: {
802: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
803: "Down - Area Mismatch");
804: }
805: }
806: /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
807: else
808: {
809: switch (hdr->circuit_t)
810: {
811: case IS_LEVEL_1:
812: if (adj->adj_state != ISIS_ADJ_UP)
813: {
814: /* (6) reject - Area Mismatch event */
815: zlog_warn ("AreaMismatch");
1.1.1.2 misho 816: free_tlvs (&tlvs);
1.1 misho 817: return ISIS_WARNING; /* Reject */
818: }
819: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
820: {
821: /* (7) down - area mismatch */
822: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
823:
824: }
825: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
826: (adj->adj_usage == ISIS_ADJ_LEVEL2))
827: {
828: /* (7) down - wrong system */
829: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
830: }
831: break;
832: case IS_LEVEL_1_AND_2:
833: case IS_LEVEL_2:
834: if (adj->adj_state != ISIS_ADJ_UP)
835: {
836: /* (8) adj state up */
837: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
838: /* (9) adj usage level 2 */
839: adj->adj_usage = ISIS_ADJ_LEVEL2;
840: }
841: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
842: {
843: /* (7) down - wrong system */
844: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
845: }
846: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
847: {
848: if (hdr->circuit_t == IS_LEVEL_2)
849: {
850: /* (7) down - wrong system */
851: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
852: "Wrong System");
853: }
854: else
855: {
856: /* (7) down - area mismatch */
857: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
858: "Area Mismatch");
859: }
860: }
861: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
862: {
863: ; /* Accept */
864: }
865: break;
866: }
867: }
868: }
1.1.1.2 misho 869: else
870: {
871: /* down - area mismatch */
872: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
873: }
1.1 misho 874: /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
875: /* FIXME - Missing parts */
876:
877: /* some of my own understanding of the ISO, why the heck does
878: * it not say what should I change the system_type to...
879: */
880: switch (adj->adj_usage)
881: {
882: case ISIS_ADJ_LEVEL1:
883: adj->sys_type = ISIS_SYSTYPE_L1_IS;
884: break;
885: case ISIS_ADJ_LEVEL2:
886: adj->sys_type = ISIS_SYSTYPE_L2_IS;
887: break;
888: case ISIS_ADJ_LEVEL1AND2:
889: adj->sys_type = ISIS_SYSTYPE_L2_IS;
890: break;
891: case ISIS_ADJ_NONE:
892: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
893: break;
894: }
895:
1.1.1.2 misho 896:
897: if (isis->debugs & DEBUG_ADJ_PACKETS)
898: {
899: zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
900: " cir id %02d, length %d",
901: circuit->area->area_tag, circuit->interface->name,
902: circuit_t2string (circuit->is_type),
903: circuit->circuit_id, pdu_len);
904: }
1.1 misho 905:
906: free_tlvs (&tlvs);
907:
908: return retval;
909: }
910:
911: /*
912: * Process IS-IS LAN Level 1/2 Hello PDU
913: */
914: static int
1.1.1.4 ! misho 915: process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
1.1 misho 916: {
917: int retval = ISIS_OK;
918: struct isis_lan_hello_hdr hdr;
919: struct isis_adjacency *adj;
1.1.1.2 misho 920: u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
1.1 misho 921: struct tlvs tlvs;
922: u_char *snpa;
923: struct listnode *node;
1.1.1.4 ! misho 924: int v4_usable = 0, v6_usable = 0;
1.1 misho 925:
1.1.1.2 misho 926: if (isis->debugs & DEBUG_ADJ_PACKETS)
927: {
928: zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
929: "cirID %u",
930: circuit->area->area_tag, level, circuit->interface->name,
931: circuit_t2string (circuit->is_type), circuit->circuit_id);
932: if (isis->debugs & DEBUG_PACKET_DUMP)
933: zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
934: stream_get_endp (circuit->rcv_stream));
935: }
936:
937: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
938: {
939: zlog_warn ("lan hello on non broadcast circuit");
940: return ISIS_WARNING;
941: }
942:
1.1 misho 943: if ((stream_get_endp (circuit->rcv_stream) -
944: stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
945: {
946: zlog_warn ("Packet too short");
947: return ISIS_WARNING;
948: }
949:
950: if (circuit->ext_domain)
951: {
952: zlog_debug ("level %d LAN Hello received over circuit with "
953: "externalDomain = true", level);
954: return ISIS_WARNING;
955: }
956:
1.1.1.2 misho 957: if (!accept_level (level, circuit->is_type))
1.1 misho 958: {
959: if (isis->debugs & DEBUG_ADJ_PACKETS)
960: {
961: zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
962: circuit->area->area_tag, circuit->interface->name);
963: }
964: return ISIS_WARNING;
965: }
966:
967: #if 0
968: /* Cisco's debug message compatability */
969: if (!accept_level (level, circuit->area->is_type))
970: {
971: if (isis->debugs & DEBUG_ADJ_PACKETS)
972: {
973: zlog_debug ("ISIS-Adj (%s): is type mismatch",
974: circuit->area->area_tag);
975: }
976: return ISIS_WARNING;
977: }
978: #endif
979: /*
980: * Fill the header
981: */
982: hdr.circuit_t = stream_getc (circuit->rcv_stream);
983: stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
984: hdr.hold_time = stream_getw (circuit->rcv_stream);
985: hdr.pdu_len = stream_getw (circuit->rcv_stream);
986: hdr.prio = stream_getc (circuit->rcv_stream);
987: stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
988:
1.1.1.3 misho 989: if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) ||
990: hdr.pdu_len > ISO_MTU(circuit) ||
1.1.1.2 misho 991: hdr.pdu_len > stream_get_endp (circuit->rcv_stream))
1.1 misho 992: {
1.1.1.2 misho 993: zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
994: "invalid pdu length %d",
995: circuit->area->area_tag, circuit->interface->name,
996: hdr.pdu_len);
997: return ISIS_WARNING;
998: }
999:
1000: /*
1001: * Set the stream endp to PDU length, ignoring additional padding
1002: * introduced by transport chips.
1003: */
1004: if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream))
1005: stream_set_endp (circuit->rcv_stream, hdr.pdu_len);
1006:
1007: if (hdr.circuit_t != IS_LEVEL_1 &&
1008: hdr.circuit_t != IS_LEVEL_2 &&
1009: hdr.circuit_t != IS_LEVEL_1_AND_2 &&
1010: (level & hdr.circuit_t) == 0)
1011: {
1012: zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
1013: hdr.circuit_t);
1.1 misho 1014: return ISIS_ERROR;
1015: }
1.1.1.2 misho 1016:
1.1 misho 1017: /*
1018: * Then get the tlvs
1019: */
1020: expected |= TLVFLAG_AUTH_INFO;
1021: expected |= TLVFLAG_AREA_ADDRS;
1022: expected |= TLVFLAG_LAN_NEIGHS;
1023: expected |= TLVFLAG_NLPID;
1024: expected |= TLVFLAG_IPV4_ADDR;
1025: expected |= TLVFLAG_IPV6_ADDR;
1026:
1.1.1.2 misho 1027: auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
1.1 misho 1028: retval = parse_tlvs (circuit->area->area_tag,
1.1.1.2 misho 1029: STREAM_PNT (circuit->rcv_stream),
1030: hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
1031: &expected, &found, &tlvs,
1032: &auth_tlv_offset);
1.1 misho 1033:
1034: if (retval > ISIS_WARNING)
1035: {
1036: zlog_warn ("parse_tlvs() failed");
1037: goto out;
1038: }
1039:
1040: if (!(found & TLVFLAG_AREA_ADDRS))
1041: {
1042: zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
1043: level);
1044: retval = ISIS_WARNING;
1045: goto out;
1046: }
1047:
1.1.1.3 misho 1048: if (!(found & TLVFLAG_NLPID))
1049: {
1050: zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello",
1051: level);
1052: retval = ISIS_WARNING;
1053: goto out;
1054: }
1055:
1.1.1.2 misho 1056: /* Verify authentication, either cleartext of HMAC MD5 */
1.1 misho 1057: if (circuit->passwd.type)
1058: {
1059: if (!(found & TLVFLAG_AUTH_INFO) ||
1.1.1.2 misho 1060: authentication_check (&tlvs.auth_info, &circuit->passwd,
1061: circuit->rcv_stream, auth_tlv_offset))
1062: {
1063: isis_event_auth_failure (circuit->area->area_tag,
1064: "LAN hello authentication failure",
1065: hdr.source_id);
1066: retval = ISIS_WARNING;
1067: goto out;
1068: }
1.1 misho 1069: }
1070:
1.1.1.3 misho 1071: if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN))
1072: {
1073: zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s",
1074: circuit->area->area_tag, circuit->interface->name);
1075: return ISIS_WARNING;
1076: }
1077:
1.1 misho 1078: /*
1079: * Accept the level 1 adjacency only if a match between local and
1080: * remote area addresses is found
1081: */
1.1.1.2 misho 1082: if (listcount (circuit->area->area_addrs) == 0 ||
1083: (level == IS_LEVEL_1 &&
1084: area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
1.1 misho 1085: {
1086: if (isis->debugs & DEBUG_ADJ_PACKETS)
1087: {
1088: zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
1089: circuit->area->area_tag, level,
1090: circuit->interface->name);
1091: }
1092: retval = ISIS_OK;
1093: goto out;
1094: }
1095:
1096: /*
1097: * it's own IIH PDU - discard silently
1098: */
1099: if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN))
1100: {
1101: zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
1102: circuit->area->area_tag);
1103:
1104: retval = ISIS_OK;
1105: goto out;
1106: }
1107:
1108: /*
1109: * check if it's own interface ip match iih ip addrs
1110: */
1.1.1.4 ! misho 1111: if (found & TLVFLAG_IPV4_ADDR)
1.1 misho 1112: {
1.1.1.4 ! misho 1113: if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
! 1114: v4_usable = 1;
! 1115: else
! 1116: zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
! 1117: "in LAN IIH from %s\n", circuit->interface->name);
! 1118: }
! 1119: #ifndef HAVE_IPV6
! 1120: else /* !(found & TLVFLAG_IPV4_ADDR) */
! 1121: zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s "
! 1122: "(this isisd has no IPv6)\n", circuit->interface->name);
! 1123:
! 1124: #else
! 1125: if (found & TLVFLAG_IPV6_ADDR)
! 1126: {
! 1127: /* TBA: check that we have a linklocal ourselves? */
! 1128: struct listnode *node;
! 1129: struct in6_addr *ip;
! 1130: for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip))
! 1131: if (IN6_IS_ADDR_LINKLOCAL (ip))
! 1132: {
! 1133: v6_usable = 1;
! 1134: break;
! 1135: }
! 1136:
! 1137: if (!v6_usable)
! 1138: zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
! 1139: "in LAN IIH from %s\n", circuit->interface->name);
! 1140: }
! 1141:
! 1142: if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
! 1143: zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n",
! 1144: circuit->interface->name);
! 1145: #endif
! 1146:
! 1147: if (!v6_usable && !v4_usable)
! 1148: {
! 1149: free_tlvs (&tlvs);
! 1150: return ISIS_WARNING;
1.1 misho 1151: }
1152:
1.1.1.4 ! misho 1153:
1.1 misho 1154: adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
1.1.1.2 misho 1155: if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
1156: (adj->level != level))
1.1 misho 1157: {
1.1.1.2 misho 1158: if (!adj)
1159: {
1160: /*
1161: * Do as in 8.4.2.5
1162: */
1163: adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
1164: if (adj == NULL)
1165: {
1166: retval = ISIS_ERROR;
1167: goto out;
1168: }
1169: }
1170: else
1171: {
1172: if (ssnpa) {
1173: memcpy (adj->snpa, ssnpa, 6);
1174: } else {
1175: memset (adj->snpa, ' ', 6);
1176: }
1177: adj->level = level;
1178: }
1.1 misho 1179: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
1180:
1.1.1.2 misho 1181: if (level == IS_LEVEL_1)
1182: adj->sys_type = ISIS_SYSTYPE_L1_IS;
1.1 misho 1183: else
1.1.1.2 misho 1184: adj->sys_type = ISIS_SYSTYPE_L2_IS;
1.1 misho 1185: list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
1186: isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
1.1.1.2 misho 1187: circuit->u.bc.lan_neighs[level - 1]);
1.1 misho 1188: }
1189:
1190: if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
1191: switch (level)
1192: {
1193: case 1:
1194: if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
1195: {
1.1.1.2 misho 1196: thread_add_event (master, isis_event_dis_status_change, circuit, 0);
1.1 misho 1197: memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
1198: ISIS_SYS_ID_LEN + 1);
1199: }
1200: break;
1201: case 2:
1202: if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
1203: {
1.1.1.2 misho 1204: thread_add_event (master, isis_event_dis_status_change, circuit, 0);
1.1 misho 1205: memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
1206: ISIS_SYS_ID_LEN + 1);
1207: }
1208: break;
1209: }
1210:
1211: adj->hold_time = hdr.hold_time;
1212: adj->last_upd = time (NULL);
1213: adj->prio[level - 1] = hdr.prio;
1214:
1215: memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
1216:
1.1.1.2 misho 1217: tlvs_to_adj_area_addrs (&tlvs, adj);
1218:
1.1 misho 1219: /* which protocol are spoken ??? */
1.1.1.3 misho 1220: if (tlvs_to_adj_nlpids (&tlvs, adj))
1221: {
1222: retval = ISIS_WARNING;
1223: goto out;
1224: }
1.1 misho 1225:
1226: /* we need to copy addresses to the adj */
1227: if (found & TLVFLAG_IPV4_ADDR)
1228: tlvs_to_adj_ipv4_addrs (&tlvs, adj);
1229:
1230: #ifdef HAVE_IPV6
1231: if (found & TLVFLAG_IPV6_ADDR)
1232: tlvs_to_adj_ipv6_addrs (&tlvs, adj);
1233: #endif /* HAVE_IPV6 */
1234:
1235: adj->circuit_t = hdr.circuit_t;
1236:
1237: /* lets take care of the expiry */
1238: THREAD_TIMER_OFF (adj->t_expire);
1239: THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
1.1.1.2 misho 1240: (long) adj->hold_time);
1.1 misho 1241:
1242: /*
1243: * If the snpa for this circuit is found from LAN Neighbours TLV
1244: * we have two-way communication -> adjacency can be put to state "up"
1245: */
1246:
1247: if (found & TLVFLAG_LAN_NEIGHS)
1.1.1.2 misho 1248: {
1249: if (adj->adj_state != ISIS_ADJ_UP)
1.1 misho 1250: {
1.1.1.2 misho 1251: for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
1252: {
1253: if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
1254: {
1255: isis_adj_state_change (adj, ISIS_ADJ_UP,
1256: "own SNPA found in LAN Neighbours TLV");
1257: }
1258: }
1259: }
1260: else
1261: {
1262: int found = 0;
1263: for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
1264: if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
1265: {
1266: found = 1;
1267: break;
1268: }
1269: if (found == 0)
1270: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
1271: "own SNPA not found in LAN Neighbours TLV");
1.1 misho 1272: }
1.1.1.2 misho 1273: }
1274: else if (adj->adj_state == ISIS_ADJ_UP)
1275: {
1276: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
1277: "no LAN Neighbours TLV found");
1278: }
1.1 misho 1279:
1280: out:
1281: if (isis->debugs & DEBUG_ADJ_PACKETS)
1282: {
1283: zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
1.1.1.4 ! misho 1284: "cirID %u, length %zd",
1.1 misho 1285: circuit->area->area_tag,
1286: level, snpa_print (ssnpa), circuit->interface->name,
1.1.1.2 misho 1287: circuit_t2string (circuit->is_type),
1.1 misho 1288: circuit->circuit_id,
1.1.1.2 misho 1289: stream_get_endp (circuit->rcv_stream));
1.1 misho 1290: }
1291:
1292: free_tlvs (&tlvs);
1293:
1294: return retval;
1295: }
1296:
1297: /*
1298: * Process Level 1/2 Link State
1299: * ISO - 10589
1300: * Section 7.3.15.1 - Action on receipt of a link state PDU
1301: */
1302: static int
1.1.1.4 ! misho 1303: process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
1.1 misho 1304: {
1305: struct isis_link_state_hdr *hdr;
1306: struct isis_adjacency *adj = NULL;
1307: struct isis_lsp *lsp, *lsp0 = NULL;
1308: int retval = ISIS_OK, comp = 0;
1309: u_char lspid[ISIS_SYS_ID_LEN + 2];
1310: struct isis_passwd *passwd;
1.1.1.2 misho 1311: uint16_t pdu_len;
1.1.1.4 ! misho 1312: int lsp_confusion;
1.1.1.2 misho 1313:
1314: if (isis->debugs & DEBUG_UPDATE_PACKETS)
1315: {
1316: zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
1317: circuit->area->area_tag, level, circuit->interface->name,
1318: circuit_t2string (circuit->is_type), circuit->circuit_id);
1319: if (isis->debugs & DEBUG_PACKET_DUMP)
1320: zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1321: stream_get_endp (circuit->rcv_stream));
1322: }
1.1 misho 1323:
1324: if ((stream_get_endp (circuit->rcv_stream) -
1325: stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
1326: {
1327: zlog_warn ("Packet too short");
1328: return ISIS_WARNING;
1329: }
1330:
1331: /* Reference the header */
1332: hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
1.1.1.2 misho 1333: pdu_len = ntohs (hdr->pdu_len);
1334:
1335: /* lsp length check */
1.1.1.3 misho 1336: if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) ||
1.1.1.2 misho 1337: pdu_len > ISO_MTU(circuit) ||
1338: pdu_len > stream_get_endp (circuit->rcv_stream))
1339: {
1340: zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
1341: circuit->area->area_tag,
1342: rawlspid_print (hdr->lsp_id), pdu_len);
1343:
1344: return ISIS_WARNING;
1345: }
1346:
1347: /*
1348: * Set the stream endp to PDU length, ignoring additional padding
1349: * introduced by transport chips.
1350: */
1351: if (pdu_len < stream_get_endp (circuit->rcv_stream))
1352: stream_set_endp (circuit->rcv_stream, pdu_len);
1.1 misho 1353:
1354: if (isis->debugs & DEBUG_UPDATE_PACKETS)
1355: {
1356: zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
1.1.1.2 misho 1357: "lifetime %us, len %u, on %s",
1.1 misho 1358: circuit->area->area_tag,
1359: level,
1360: rawlspid_print (hdr->lsp_id),
1361: ntohl (hdr->seq_num),
1362: ntohs (hdr->checksum),
1363: ntohs (hdr->rem_lifetime),
1.1.1.2 misho 1364: pdu_len,
1.1 misho 1365: circuit->interface->name);
1366: }
1367:
1.1.1.2 misho 1368: /* lsp is_type check */
1369: if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 &&
1370: (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2)
1371: {
1372: zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
1373: circuit->area->area_tag,
1374: rawlspid_print (hdr->lsp_id), hdr->lsp_bits);
1375: /* continue as per RFC1122 Be liberal in what you accept, and
1376: * conservative in what you send */
1377: }
1.1 misho 1378:
1379: /* Checksum sanity check - FIXME: move to correct place */
1380: /* 12 = sysid+pdu+remtime */
1381: if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
1.1.1.2 misho 1382: pdu_len - 12, &hdr->checksum))
1.1 misho 1383: {
1384: zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
1385: circuit->area->area_tag,
1386: rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum));
1387:
1388: return ISIS_WARNING;
1389: }
1390:
1391: /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
1392: if (circuit->ext_domain)
1393: {
1394: zlog_debug
1395: ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
1396: "externalDomain = true", circuit->area->area_tag,
1397: rawlspid_print (hdr->lsp_id), level);
1398:
1399: return ISIS_WARNING;
1400: }
1401:
1402: /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
1.1.1.2 misho 1403: if (!accept_level (level, circuit->is_type))
1.1 misho 1404: {
1405: zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
1406: " type %s",
1407: circuit->area->area_tag,
1408: rawlspid_print (hdr->lsp_id),
1.1.1.2 misho 1409: level, circuit_t2string (circuit->is_type));
1.1 misho 1410:
1411: return ISIS_WARNING;
1412: }
1413:
1414: /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
1415:
1416: /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
1417:
1418: /* 7.3.15.1 a) 7 - password check */
1.1.1.2 misho 1419: (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
1420: (passwd = &circuit->area->domain_passwd);
1.1 misho 1421: if (passwd->type)
1422: {
1.1.1.2 misho 1423: if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
1424: level, passwd))
1.1 misho 1425: {
1426: isis_event_auth_failure (circuit->area->area_tag,
1427: "LSP authentication failure", hdr->lsp_id);
1428: return ISIS_WARNING;
1429: }
1430: }
1431: /* Find the LSP in our database and compare it to this Link State header */
1432: lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
1433: if (lsp)
1434: comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
1435: hdr->checksum, hdr->rem_lifetime);
1436: if (lsp && (lsp->own_lsp
1437: #ifdef TOPOLOGY_GENERATE
1438: || lsp->from_topology
1439: #endif /* TOPOLOGY_GENERATE */
1440: ))
1441: goto dontcheckadj;
1442:
1443: /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1444: /* for broadcast circuits, snpa should be compared */
1445:
1446: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1447: {
1448: adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
1449: if (!adj)
1450: {
1451: zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1452: "lifetime %us on %s",
1453: circuit->area->area_tag,
1454: rawlspid_print (hdr->lsp_id),
1455: ntohl (hdr->seq_num),
1456: ntohs (hdr->checksum),
1457: ntohs (hdr->rem_lifetime), circuit->interface->name);
1458: return ISIS_WARNING; /* Silently discard */
1459: }
1460: }
1461: /* for non broadcast, we just need to find same level adj */
1462: else
1463: {
1464: /* If no adj, or no sharing of level */
1465: if (!circuit->u.p2p.neighbor)
1466: {
1467: return ISIS_OK; /* Silently discard */
1468: }
1469: else
1470: {
1.1.1.2 misho 1471: if (((level == IS_LEVEL_1) &&
1.1 misho 1472: (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
1.1.1.2 misho 1473: ((level == IS_LEVEL_2) &&
1.1 misho 1474: (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
1475: return ISIS_WARNING; /* Silently discard */
1.1.1.2 misho 1476: adj = circuit->u.p2p.neighbor;
1.1 misho 1477: }
1478: }
1.1.1.2 misho 1479:
1.1 misho 1480: dontcheckadj:
1481: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1482:
1483: /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1484:
1485: /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1486:
1.1.1.4 ! misho 1487: /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but
! 1488: * wrong checksum, initiate a purge. */
! 1489: if (lsp
! 1490: && (lsp->lsp_header->seq_num == hdr->seq_num)
! 1491: && (lsp->lsp_header->checksum != hdr->checksum))
! 1492: {
! 1493: zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
! 1494: circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
! 1495: ntohl(hdr->seq_num));
! 1496: hdr->rem_lifetime = 0;
! 1497: lsp_confusion = 1;
! 1498: }
! 1499: else
! 1500: lsp_confusion = 0;
! 1501:
1.1 misho 1502: /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1503: if (hdr->rem_lifetime == 0)
1504: {
1505: if (!lsp)
1506: {
1507: /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1508: /* only needed on explicit update, eg - p2p */
1509: if (circuit->circ_type == CIRCUIT_T_P2P)
1510: ack_lsp (hdr, circuit, level);
1511: return retval; /* FIXME: do we need a purge? */
1512: }
1513: else
1514: {
1515: if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
1516: {
1517: /* LSP by some other system -> do 7.3.16.4 b) */
1518: /* 7.3.16.4 b) 1) */
1519: if (comp == LSP_NEWER)
1520: {
1.1.1.2 misho 1521: lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
1.1 misho 1522: /* ii */
1.1.1.2 misho 1523: lsp_set_all_srmflags (lsp);
1.1 misho 1524: /* v */
1525: ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */
1526:
1.1.1.4 ! misho 1527: /* For the case of lsp confusion, flood the purge back to its
! 1528: * originator so that it can react. Otherwise, don't reflood
! 1529: * through incoming circuit as usual */
! 1530: if (!lsp_confusion)
! 1531: {
! 1532: /* iii */
! 1533: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1534: /* iv */
! 1535: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1536: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1537: }
1.1 misho 1538: } /* 7.3.16.4 b) 2) */
1539: else if (comp == LSP_EQUAL)
1540: {
1541: /* i */
1542: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1543: /* ii */
1544: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1545: ISIS_SET_FLAG (lsp->SSNflags, circuit);
1546: } /* 7.3.16.4 b) 3) */
1547: else
1548: {
1549: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1550: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1551: }
1552: }
1.1.1.2 misho 1553: else if (lsp->lsp_header->rem_lifetime != 0)
1554: {
1555: /* our own LSP -> 7.3.16.4 c) */
1556: if (comp == LSP_NEWER)
1557: {
1558: lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
1559: lsp_set_all_srmflags (lsp);
1560: }
1561: else
1562: {
1563: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1564: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1565: }
1566: if (isis->debugs & DEBUG_UPDATE_PACKETS)
1567: zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1568: "seq 0x%08x", circuit->area->area_tag,
1569: rawlspid_print (hdr->lsp_id),
1570: ntohl (lsp->lsp_header->seq_num));
1571: }
1.1 misho 1572: }
1573: return retval;
1574: }
1575: /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1576: * purge */
1577: if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
1578: {
1579: if (!lsp)
1580: {
1581: /* 7.3.16.4: initiate a purge */
1.1.1.4 ! misho 1582: lsp_purge_non_exist(level, hdr, circuit->area);
1.1 misho 1583: return ISIS_OK;
1584: }
1585: /* 7.3.15.1 d) - If this is our own lsp and we have it */
1586:
1587: /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1588: * has information that the current sequence number for source S is
1589: * "greater" than that held by S, ... */
1590:
1.1.1.2 misho 1591: if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
1.1 misho 1592: {
1593: /* 7.3.16.1 */
1.1.1.2 misho 1594: lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
1.1 misho 1595: if (isis->debugs & DEBUG_UPDATE_PACKETS)
1596: zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1597: "0x%08x", circuit->area->area_tag,
1598: rawlspid_print (hdr->lsp_id),
1599: ntohl (lsp->lsp_header->seq_num));
1600: }
1.1.1.2 misho 1601: /* If the received LSP is older or equal,
1602: * resend the LSP which will act as ACK */
1603: lsp_set_all_srmflags (lsp);
1.1 misho 1604: }
1605: else
1606: {
1607: /* 7.3.15.1 e) - This lsp originated on another system */
1608:
1609: /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1610: if ((!lsp || comp == LSP_NEWER))
1611: {
1612: /*
1613: * If this lsp is a frag, need to see if we have zero lsp present
1614: */
1615: if (LSP_FRAGMENT (hdr->lsp_id) != 0)
1616: {
1617: memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
1618: LSP_FRAGMENT (lspid) = 0;
1619: lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
1620: if (!lsp0)
1621: {
1.1.1.2 misho 1622: zlog_debug ("Got lsp frag, while zero lsp not in database");
1.1 misho 1623: return ISIS_OK;
1624: }
1625: }
1.1.1.2 misho 1626: /* i */
1627: if (!lsp)
1628: {
1629: lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
1630: pdu_len, lsp0,
1631: circuit->area, level);
1632: lsp_insert (lsp, circuit->area->lspdb[level - 1]);
1633: }
1634: else /* exists, so we overwrite */
1635: {
1636: lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
1637: }
1.1 misho 1638: /* ii */
1.1.1.2 misho 1639: lsp_set_all_srmflags (lsp);
1.1 misho 1640: /* iii */
1641: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1642:
1643: /* iv */
1644: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1645: ISIS_SET_FLAG (lsp->SSNflags, circuit);
1646: /* FIXME: v) */
1647: }
1648: /* 7.3.15.1 e) 2) LSP equal to the one in db */
1649: else if (comp == LSP_EQUAL)
1650: {
1651: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1.1.1.2 misho 1652: lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
1.1 misho 1653: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1.1.1.2 misho 1654: ISIS_SET_FLAG (lsp->SSNflags, circuit);
1.1 misho 1655: }
1656: /* 7.3.15.1 e) 3) LSP older than the one in db */
1657: else
1658: {
1659: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1660: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1661: }
1662: }
1663: return retval;
1664: }
1665:
1666: /*
1667: * Process Sequence Numbers
1668: * ISO - 10589
1669: * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1670: */
1671:
1672: static int
1673: process_snp (int snp_type, int level, struct isis_circuit *circuit,
1.1.1.4 ! misho 1674: const u_char *ssnpa)
1.1 misho 1675: {
1676: int retval = ISIS_OK;
1677: int cmp, own_lsp;
1678: char typechar = ' ';
1.1.1.2 misho 1679: uint16_t pdu_len;
1.1 misho 1680: struct isis_adjacency *adj;
1681: struct isis_complete_seqnum_hdr *chdr = NULL;
1682: struct isis_partial_seqnum_hdr *phdr = NULL;
1.1.1.2 misho 1683: uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
1.1 misho 1684: struct isis_lsp *lsp;
1685: struct lsp_entry *entry;
1686: struct listnode *node, *nnode;
1687: struct listnode *node2, *nnode2;
1688: struct tlvs tlvs;
1689: struct list *lsp_list = NULL;
1690: struct isis_passwd *passwd;
1691:
1692: if (snp_type == ISIS_SNP_CSNP_FLAG)
1693: {
1694: /* getting the header info */
1695: typechar = 'C';
1696: chdr =
1697: (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
1.1.1.2 misho 1698: stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN);
1699: pdu_len = ntohs (chdr->pdu_len);
1.1.1.3 misho 1700: if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) ||
1.1.1.2 misho 1701: pdu_len > ISO_MTU(circuit) ||
1702: pdu_len > stream_get_endp (circuit->rcv_stream))
1.1 misho 1703: {
1.1.1.2 misho 1704: zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
1705: return ISIS_WARNING;
1.1 misho 1706: }
1707: }
1708: else
1709: {
1710: typechar = 'P';
1711: phdr =
1712: (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
1.1.1.2 misho 1713: stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN);
1714: pdu_len = ntohs (phdr->pdu_len);
1.1.1.3 misho 1715: if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) ||
1.1.1.2 misho 1716: pdu_len > ISO_MTU(circuit) ||
1717: pdu_len > stream_get_endp (circuit->rcv_stream))
1.1 misho 1718: {
1.1.1.4 ! misho 1719: zlog_warn ("Received a PSNP with bogus length %d", pdu_len);
1.1.1.2 misho 1720: return ISIS_WARNING;
1.1 misho 1721: }
1722: }
1723:
1.1.1.2 misho 1724: /*
1725: * Set the stream endp to PDU length, ignoring additional padding
1726: * introduced by transport chips.
1727: */
1728: if (pdu_len < stream_get_endp (circuit->rcv_stream))
1729: stream_set_endp (circuit->rcv_stream, pdu_len);
1730:
1.1 misho 1731: /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1732: if (circuit->ext_domain)
1733: {
1734:
1735: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1736: "skipping: circuit externalDomain = true",
1737: circuit->area->area_tag,
1738: level, typechar, circuit->interface->name);
1739:
1740: return ISIS_OK;
1741: }
1742:
1743: /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1.1.1.2 misho 1744: if (!accept_level (level, circuit->is_type))
1.1 misho 1745: {
1746:
1747: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1748: "skipping: circuit type %s does not match level %d",
1749: circuit->area->area_tag,
1750: level,
1751: typechar,
1752: circuit->interface->name,
1.1.1.2 misho 1753: circuit_t2string (circuit->is_type), level);
1.1 misho 1754:
1755: return ISIS_OK;
1756: }
1757:
1758: /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1759: if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
1.1.1.2 misho 1760: (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
1761: (!circuit->u.bc.is_dr[level - 1]))
1.1 misho 1762: {
1.1.1.2 misho 1763: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1764: "skipping: we are not the DIS",
1765: circuit->area->area_tag,
1766: level,
1767: typechar, snpa_print (ssnpa), circuit->interface->name);
1.1 misho 1768:
1.1.1.2 misho 1769: return ISIS_OK;
1.1 misho 1770: }
1771:
1772: /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1773:
1774: /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1775: * - already checked */
1776:
1777: /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1778: /* for broadcast circuits, snpa should be compared */
1779: /* FIXME : Do we need to check SNPA? */
1780: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1781: {
1782: if (snp_type == ISIS_SNP_CSNP_FLAG)
1783: {
1784: adj =
1785: isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
1786: }
1787: else
1788: {
1789: /* a psnp on a broadcast, how lovely of Juniper :) */
1790: adj =
1791: isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
1792: }
1793: if (!adj)
1794: return ISIS_OK; /* Silently discard */
1795: }
1796: else
1797: {
1798: if (!circuit->u.p2p.neighbor)
1.1.1.2 misho 1799: {
1800: zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
1801: return ISIS_OK; /* Silently discard */
1802: }
1.1 misho 1803: }
1804:
1805: /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1806:
1807: /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1808:
1809: memset (&tlvs, 0, sizeof (struct tlvs));
1810:
1811: /* parse the SNP */
1812: expected |= TLVFLAG_LSP_ENTRIES;
1813: expected |= TLVFLAG_AUTH_INFO;
1.1.1.2 misho 1814:
1815: auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
1.1 misho 1816: retval = parse_tlvs (circuit->area->area_tag,
1817: STREAM_PNT (circuit->rcv_stream),
1.1.1.2 misho 1818: pdu_len - stream_get_getp (circuit->rcv_stream),
1819: &expected, &found, &tlvs, &auth_tlv_offset);
1.1 misho 1820:
1821: if (retval > ISIS_WARNING)
1822: {
1823: zlog_warn ("something went very wrong processing SNP");
1824: free_tlvs (&tlvs);
1825: return retval;
1826: }
1827:
1.1.1.2 misho 1828: if (level == IS_LEVEL_1)
1.1 misho 1829: passwd = &circuit->area->area_passwd;
1830: else
1831: passwd = &circuit->area->domain_passwd;
1832:
1833: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
1834: {
1835: if (passwd->type)
1.1.1.2 misho 1836: {
1837: if (!(found & TLVFLAG_AUTH_INFO) ||
1838: authentication_check (&tlvs.auth_info, passwd,
1839: circuit->rcv_stream, auth_tlv_offset))
1840: {
1841: isis_event_auth_failure (circuit->area->area_tag,
1842: "SNP authentication" " failure",
1843: phdr ? phdr->source_id :
1844: chdr->source_id);
1845: free_tlvs (&tlvs);
1846: return ISIS_OK;
1847: }
1848: }
1.1 misho 1849: }
1850:
1851: /* debug isis snp-packets */
1852: if (isis->debugs & DEBUG_SNP_PACKETS)
1853: {
1854: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1855: circuit->area->area_tag,
1856: level,
1857: typechar, snpa_print (ssnpa), circuit->interface->name);
1858: if (tlvs.lsp_entries)
1859: {
1860: for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
1861: {
1862: zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1863: " cksum 0x%04x, lifetime %us",
1864: circuit->area->area_tag,
1865: typechar,
1866: rawlspid_print (entry->lsp_id),
1867: ntohl (entry->seq_num),
1868: ntohs (entry->checksum), ntohs (entry->rem_lifetime));
1869: }
1870: }
1871: }
1872:
1873: /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1874: if (tlvs.lsp_entries)
1875: {
1876: for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
1877: {
1878: lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
1879: own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1880: if (lsp)
1881: {
1882: /* 7.3.15.2 b) 1) is this LSP newer */
1883: cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
1884: entry->checksum, entry->rem_lifetime);
1885: /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1886: if (cmp == LSP_EQUAL)
1887: {
1.1.1.2 misho 1888: /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1889: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1.1 misho 1890: }
1.1.1.2 misho 1891: /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1.1 misho 1892: else if (cmp == LSP_OLDER)
1893: {
1894: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1895: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1896: }
1.1.1.2 misho 1897: /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
1.1 misho 1898: else
1899: {
1900: if (own_lsp)
1901: {
1902: lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
1903: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1904: }
1905: else
1906: {
1907: ISIS_SET_FLAG (lsp->SSNflags, circuit);
1.1.1.2 misho 1908: /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1909: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1.1 misho 1910: }
1911: }
1912: }
1913: else
1914: {
1915: /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1916: * insert it and set SSN on it */
1917: if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
1918: memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
1919: {
1.1.1.4 ! misho 1920: lsp = lsp_new(circuit->area, entry->lsp_id,
! 1921: ntohs(entry->rem_lifetime),
! 1922: 0, 0, entry->checksum, level);
1.1 misho 1923: lsp_insert (lsp, circuit->area->lspdb[level - 1]);
1.1.1.2 misho 1924: ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
1.1 misho 1925: ISIS_SET_FLAG (lsp->SSNflags, circuit);
1926: }
1927: }
1928: }
1929: }
1930:
1931: /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1932: if (snp_type == ISIS_SNP_CSNP_FLAG)
1933: {
1934: /*
1.1.1.2 misho 1935: * Build a list from our own LSP db bounded with
1936: * start_lsp_id and stop_lsp_id
1.1 misho 1937: */
1938: lsp_list = list_new ();
1939: lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
1940: lsp_list, circuit->area->lspdb[level - 1]);
1941:
1942: /* Fixme: Find a better solution */
1943: if (tlvs.lsp_entries)
1944: {
1945: for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry))
1946: {
1947: for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp))
1948: {
1949: if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0)
1950: {
1951: list_delete_node (lsp_list, node2);
1952: break;
1953: }
1954: }
1955: }
1956: }
1957: /* on remaining LSPs we set SRM (neighbor knew not of) */
1958: for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
1959: ISIS_SET_FLAG (lsp->SRMflags, circuit);
1960: /* lets free it */
1.1.1.2 misho 1961: list_delete (lsp_list);
1962:
1.1 misho 1963: }
1964:
1965: free_tlvs (&tlvs);
1966: return retval;
1967: }
1968:
1969: static int
1.1.1.4 ! misho 1970: process_csnp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
1.1 misho 1971: {
1.1.1.2 misho 1972: if (isis->debugs & DEBUG_SNP_PACKETS)
1973: {
1974: zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
1975: circuit->area->area_tag, level, circuit->interface->name,
1976: circuit_t2string (circuit->is_type), circuit->circuit_id);
1977: if (isis->debugs & DEBUG_PACKET_DUMP)
1978: zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1979: stream_get_endp (circuit->rcv_stream));
1980: }
1981:
1.1 misho 1982: /* Sanity check - FIXME: move to correct place */
1983: if ((stream_get_endp (circuit->rcv_stream) -
1984: stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
1985: {
1986: zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
1987: return ISIS_WARNING;
1988: }
1989:
1990: return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
1991: }
1992:
1993: static int
1.1.1.4 ! misho 1994: process_psnp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
1.1 misho 1995: {
1.1.1.2 misho 1996: if (isis->debugs & DEBUG_SNP_PACKETS)
1997: {
1998: zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
1999: circuit->area->area_tag, level, circuit->interface->name,
2000: circuit_t2string (circuit->is_type), circuit->circuit_id);
2001: if (isis->debugs & DEBUG_PACKET_DUMP)
2002: zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
2003: stream_get_endp (circuit->rcv_stream));
2004: }
2005:
1.1 misho 2006: if ((stream_get_endp (circuit->rcv_stream) -
2007: stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
2008: {
1.1.1.2 misho 2009: zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
1.1 misho 2010: return ISIS_WARNING;
2011: }
2012:
2013: return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
2014: }
2015:
2016: /*
2017: * PDU Dispatcher
2018: */
2019:
2020: static int
2021: isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
2022: {
2023: struct isis_fixed_hdr *hdr;
2024:
2025: int retval = ISIS_OK;
2026:
2027: /*
2028: * Let's first read data from stream to the header
2029: */
2030: hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
2031:
2032: if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
2033: {
1.1.1.2 misho 2034: zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
1.1 misho 2035: return ISIS_ERROR;
2036: }
2037:
2038: /* now we need to know if this is an ISO 9542 packet and
2039: * take real good care of it, waaa!
2040: */
2041: if (hdr->idrp == ISO9542_ESIS)
2042: {
1.1.1.2 misho 2043: zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
2044: return ISIS_ERROR;
1.1 misho 2045: }
1.1.1.2 misho 2046: stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
2047:
1.1 misho 2048: /*
2049: * and then process it
2050: */
2051:
2052: if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN)
2053: {
2054: zlog_err ("Fixed header length = %d", hdr->length);
2055: return ISIS_ERROR;
2056: }
2057:
2058: if (hdr->version1 != 1)
2059: {
2060: zlog_warn ("Unsupported ISIS version %u", hdr->version1);
2061: return ISIS_WARNING;
2062: }
2063: /* either 6 or 0 */
2064: if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN))
2065: {
2066: zlog_err
2067: ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
2068: "while the parameter for this IS is %u", hdr->id_len,
2069: ISIS_SYS_ID_LEN);
2070: return ISIS_ERROR;
2071: }
2072:
2073: if (hdr->version2 != 1)
2074: {
2075: zlog_warn ("Unsupported ISIS version %u", hdr->version2);
2076: return ISIS_WARNING;
2077: }
1.1.1.2 misho 2078:
2079: if (circuit->is_passive)
2080: {
2081: zlog_warn ("Received ISIS PDU on passive circuit %s",
2082: circuit->interface->name);
2083: return ISIS_WARNING;
2084: }
2085:
1.1 misho 2086: /* either 3 or 0 */
2087: if ((hdr->max_area_addrs != 0)
2088: && (hdr->max_area_addrs != isis->max_area_addrs))
2089: {
2090: zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
2091: "received PDU %u while the parameter for this IS is %u",
2092: hdr->max_area_addrs, isis->max_area_addrs);
2093: return ISIS_ERROR;
2094: }
2095:
2096: switch (hdr->pdu_type)
2097: {
2098: case L1_LAN_HELLO:
2099: retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
2100: break;
2101: case L2_LAN_HELLO:
2102: retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
2103: break;
2104: case P2P_HELLO:
2105: retval = process_p2p_hello (circuit);
2106: break;
2107: case L1_LINK_STATE:
2108: retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
2109: break;
2110: case L2_LINK_STATE:
2111: retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
2112: break;
2113: case L1_COMPLETE_SEQ_NUM:
2114: retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
2115: break;
2116: case L2_COMPLETE_SEQ_NUM:
2117: retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
2118: break;
2119: case L1_PARTIAL_SEQ_NUM:
2120: retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
2121: break;
2122: case L2_PARTIAL_SEQ_NUM:
2123: retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
2124: break;
2125: default:
2126: return ISIS_ERROR;
2127: }
2128:
2129: return retval;
2130: }
2131:
2132: #ifdef GNU_LINUX
2133: int
2134: isis_receive (struct thread *thread)
2135: {
2136: struct isis_circuit *circuit;
2137: u_char ssnpa[ETH_ALEN];
2138: int retval;
2139:
2140: /*
2141: * Get the circuit
2142: */
2143: circuit = THREAD_ARG (thread);
2144: assert (circuit);
2145:
1.1.1.4 ! misho 2146: isis_circuit_stream(circuit, &circuit->rcv_stream);
1.1 misho 2147:
2148: retval = circuit->rx (circuit, ssnpa);
2149: circuit->t_read = NULL;
2150:
2151: if (retval == ISIS_OK)
2152: retval = isis_handle_pdu (circuit, ssnpa);
2153:
2154: /*
2155: * prepare for next packet.
2156: */
1.1.1.2 misho 2157: if (!circuit->is_passive)
2158: {
2159: THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
2160: circuit->fd);
2161: }
1.1 misho 2162:
2163: return retval;
2164: }
2165:
2166: #else
2167: int
2168: isis_receive (struct thread *thread)
2169: {
2170: struct isis_circuit *circuit;
2171: u_char ssnpa[ETH_ALEN];
2172: int retval;
2173:
2174: /*
2175: * Get the circuit
2176: */
2177: circuit = THREAD_ARG (thread);
2178: assert (circuit);
2179:
2180: circuit->t_read = NULL;
2181:
1.1.1.4 ! misho 2182: isis_circuit_stream(circuit, &circuit->rcv_stream);
1.1 misho 2183:
2184: retval = circuit->rx (circuit, ssnpa);
2185:
2186: if (retval == ISIS_OK)
2187: retval = isis_handle_pdu (circuit, ssnpa);
2188:
2189: /*
2190: * prepare for next packet.
2191: */
1.1.1.2 misho 2192: if (!circuit->is_passive)
2193: {
2194: circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
2195: listcount
2196: (circuit->area->circuit_list) *
2197: 100);
2198: }
1.1 misho 2199:
2200: return retval;
2201: }
2202:
2203: #endif
2204:
2205: /* filling of the fixed isis header */
2206: void
2207: fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
2208: {
2209: memset (hdr, 0, sizeof (struct isis_fixed_hdr));
2210:
2211: hdr->idrp = ISO10589_ISIS;
2212:
2213: switch (pdu_type)
2214: {
2215: case L1_LAN_HELLO:
2216: case L2_LAN_HELLO:
2217: hdr->length = ISIS_LANHELLO_HDRLEN;
2218: break;
2219: case P2P_HELLO:
2220: hdr->length = ISIS_P2PHELLO_HDRLEN;
2221: break;
2222: case L1_LINK_STATE:
2223: case L2_LINK_STATE:
2224: hdr->length = ISIS_LSP_HDR_LEN;
2225: break;
2226: case L1_COMPLETE_SEQ_NUM:
2227: case L2_COMPLETE_SEQ_NUM:
2228: hdr->length = ISIS_CSNP_HDRLEN;
2229: break;
2230: case L1_PARTIAL_SEQ_NUM:
2231: case L2_PARTIAL_SEQ_NUM:
2232: hdr->length = ISIS_PSNP_HDRLEN;
2233: break;
2234: default:
2235: zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
2236: return;
2237: }
2238: hdr->length += ISIS_FIXED_HDR_LEN;
2239: hdr->pdu_type = pdu_type;
2240: hdr->version1 = 1;
2241: hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */
2242: hdr->version2 = 1;
2243: hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */
2244: }
2245:
2246: /*
2247: * SEND SIDE
2248: */
2249: static void
2250: fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
2251: struct stream *stream)
2252: {
2253: fill_fixed_hdr (hdr, pdu_type);
2254:
2255: stream_putc (stream, hdr->idrp);
2256: stream_putc (stream, hdr->length);
2257: stream_putc (stream, hdr->version1);
2258: stream_putc (stream, hdr->id_len);
2259: stream_putc (stream, hdr->pdu_type);
2260: stream_putc (stream, hdr->version2);
2261: stream_putc (stream, hdr->reserved);
2262: stream_putc (stream, hdr->max_area_addrs);
2263:
2264: return;
2265: }
2266:
2267: int
2268: send_hello (struct isis_circuit *circuit, int level)
2269: {
2270: struct isis_fixed_hdr fixed_hdr;
2271: struct isis_lan_hello_hdr hello_hdr;
2272: struct isis_p2p_hello_hdr p2p_hello_hdr;
1.1.1.2 misho 2273: unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
1.1.1.4 ! misho 2274: size_t len_pointer, length, auth_tlv_offset = 0;
1.1 misho 2275: u_int32_t interval;
2276: int retval;
2277:
1.1.1.2 misho 2278: if (circuit->is_passive)
2279: return ISIS_OK;
2280:
1.1 misho 2281: if (circuit->interface->mtu == 0)
2282: {
2283: zlog_warn ("circuit has zero MTU");
2284: return ISIS_WARNING;
2285: }
2286:
1.1.1.4 ! misho 2287: isis_circuit_stream(circuit, &circuit->snd_stream);
1.1 misho 2288:
2289: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1.1.1.2 misho 2290: if (level == IS_LEVEL_1)
1.1 misho 2291: fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
2292: circuit->snd_stream);
2293: else
2294: fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO,
2295: circuit->snd_stream);
2296: else
2297: fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream);
2298:
2299: /*
2300: * Fill LAN Level 1 or 2 Hello PDU header
2301: */
2302: memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
2303: interval = circuit->hello_multiplier[level - 1] *
2304: circuit->hello_interval[level - 1];
2305: if (interval > USHRT_MAX)
2306: interval = USHRT_MAX;
1.1.1.2 misho 2307: hello_hdr.circuit_t = circuit->is_type;
1.1 misho 2308: memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
2309: hello_hdr.hold_time = htons ((u_int16_t) interval);
2310:
2311: hello_hdr.pdu_len = 0; /* Update the PDU Length later */
2312: len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
2313:
2314: /* copy the shared part of the hello to the p2p hello if needed */
2315: if (circuit->circ_type == CIRCUIT_T_P2P)
2316: {
2317: memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
2318: p2p_hello_hdr.local_id = circuit->circuit_id;
2319: /* FIXME: need better understanding */
2320: stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
2321: }
2322: else
2323: {
1.1.1.2 misho 2324: hello_hdr.prio = circuit->priority[level - 1];
2325: if (level == IS_LEVEL_1)
1.1 misho 2326: {
2327: memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
2328: ISIS_SYS_ID_LEN + 1);
2329: }
1.1.1.2 misho 2330: else if (level == IS_LEVEL_2)
1.1 misho 2331: {
2332: memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
2333: ISIS_SYS_ID_LEN + 1);
2334: }
2335: stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
2336: }
2337:
2338: /*
1.1.1.2 misho 2339: * Then the variable length part.
1.1 misho 2340: */
1.1.1.2 misho 2341:
1.1 misho 2342: /* add circuit password */
1.1.1.2 misho 2343: switch (circuit->passwd.type)
2344: {
2345: /* Cleartext */
2346: case ISIS_PASSWD_TYPE_CLEARTXT:
2347: if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
2348: circuit->passwd.passwd, circuit->snd_stream))
2349: return ISIS_WARNING;
2350: break;
2351:
2352: /* HMAC MD5 */
2353: case ISIS_PASSWD_TYPE_HMAC_MD5:
2354: /* Remember where TLV is written so we can later overwrite the MD5 hash */
2355: auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2356: memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2357: if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
2358: hmac_md5_hash, circuit->snd_stream))
2359: return ISIS_WARNING;
2360: break;
2361:
2362: default:
2363: break;
2364: }
2365:
1.1 misho 2366: /* Area Addresses TLV */
1.1.1.2 misho 2367: if (listcount (circuit->area->area_addrs) == 0)
2368: return ISIS_WARNING;
2369: if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
2370: return ISIS_WARNING;
1.1 misho 2371:
2372: /* LAN Neighbors TLV */
2373: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
2374: {
1.1.1.2 misho 2375: if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
2376: listcount (circuit->u.bc.lan_neighs[0]) > 0)
1.1 misho 2377: if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
2378: circuit->snd_stream))
2379: return ISIS_WARNING;
1.1.1.2 misho 2380: if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
2381: listcount (circuit->u.bc.lan_neighs[1]) > 0)
1.1 misho 2382: if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
2383: circuit->snd_stream))
2384: return ISIS_WARNING;
2385: }
2386:
2387: /* Protocols Supported TLV */
2388: if (circuit->nlpids.count > 0)
2389: if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
2390: return ISIS_WARNING;
2391: /* IP interface Address TLV */
1.1.1.2 misho 2392: if (circuit->ip_router && circuit->ip_addrs &&
2393: listcount (circuit->ip_addrs) > 0)
1.1 misho 2394: if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
2395: return ISIS_WARNING;
2396:
2397: #ifdef HAVE_IPV6
2398: /* IPv6 Interface Address TLV */
2399: if (circuit->ipv6_router && circuit->ipv6_link &&
1.1.1.2 misho 2400: listcount (circuit->ipv6_link) > 0)
1.1 misho 2401: if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
2402: return ISIS_WARNING;
2403: #endif /* HAVE_IPV6 */
2404:
1.1.1.2 misho 2405: if (circuit->pad_hellos)
1.1 misho 2406: if (tlv_add_padding (circuit->snd_stream))
2407: return ISIS_WARNING;
2408:
2409: length = stream_get_endp (circuit->snd_stream);
2410: /* Update PDU length */
2411: stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
2412:
1.1.1.2 misho 2413: /* For HMAC MD5 we need to compute the md5 hash and store it */
2414: if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
2415: {
2416: hmac_md5 (STREAM_DATA (circuit->snd_stream),
2417: stream_get_endp (circuit->snd_stream),
2418: (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
1.1.1.4 ! misho 2419: (unsigned char *) &hmac_md5_hash);
1.1.1.2 misho 2420: /* Copy the hash into the stream */
2421: memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2422: hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2423: }
1.1 misho 2424:
2425: if (isis->debugs & DEBUG_ADJ_PACKETS)
2426: {
2427: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
2428: {
1.1.1.4 ! misho 2429: zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd",
1.1 misho 2430: circuit->area->area_tag, level, circuit->interface->name,
1.1.1.2 misho 2431: length);
1.1 misho 2432: }
2433: else
2434: {
1.1.1.4 ! misho 2435: zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd",
1.1 misho 2436: circuit->area->area_tag, circuit->interface->name,
1.1.1.2 misho 2437: length);
1.1 misho 2438: }
1.1.1.2 misho 2439: if (isis->debugs & DEBUG_PACKET_DUMP)
2440: zlog_dump_data (STREAM_DATA (circuit->snd_stream),
2441: stream_get_endp (circuit->snd_stream));
1.1 misho 2442: }
2443:
1.1.1.2 misho 2444: retval = circuit->tx (circuit, level);
2445: if (retval != ISIS_OK)
2446: zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
2447: circuit->area->area_tag, level, circuit->interface->name);
1.1 misho 2448:
1.1.1.2 misho 2449: return retval;
1.1 misho 2450: }
2451:
2452: int
2453: send_lan_l1_hello (struct thread *thread)
2454: {
2455: struct isis_circuit *circuit;
2456: int retval;
2457:
2458: circuit = THREAD_ARG (thread);
2459: assert (circuit);
2460: circuit->u.bc.t_send_lan_hello[0] = NULL;
2461:
1.1.1.4 ! misho 2462: if (!(circuit->area->is_type & IS_LEVEL_1))
! 2463: {
! 2464: zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
! 2465: circuit->area->area_tag);
! 2466: return 1;
! 2467: }
! 2468:
1.1 misho 2469: if (circuit->u.bc.run_dr_elect[0])
2470: retval = isis_dr_elect (circuit, 1);
2471:
1.1.1.2 misho 2472: retval = send_hello (circuit, 1);
1.1 misho 2473:
2474: /* set next timer thread */
2475: THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
2476: send_lan_l1_hello, circuit,
1.1.1.2 misho 2477: isis_jitter (circuit->hello_interval[0], IIH_JITTER));
1.1 misho 2478:
2479: return retval;
2480: }
2481:
2482: int
2483: send_lan_l2_hello (struct thread *thread)
2484: {
2485: struct isis_circuit *circuit;
2486: int retval;
2487:
2488: circuit = THREAD_ARG (thread);
2489: assert (circuit);
2490: circuit->u.bc.t_send_lan_hello[1] = NULL;
2491:
1.1.1.4 ! misho 2492: if (!(circuit->area->is_type & IS_LEVEL_2))
! 2493: {
! 2494: zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
! 2495: circuit->area->area_tag);
! 2496: return 1;
! 2497: }
! 2498:
1.1 misho 2499: if (circuit->u.bc.run_dr_elect[1])
2500: retval = isis_dr_elect (circuit, 2);
2501:
1.1.1.2 misho 2502: retval = send_hello (circuit, 2);
1.1 misho 2503:
2504: /* set next timer thread */
2505: THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
2506: send_lan_l2_hello, circuit,
1.1.1.2 misho 2507: isis_jitter (circuit->hello_interval[1], IIH_JITTER));
1.1 misho 2508:
2509: return retval;
2510: }
2511:
2512: int
2513: send_p2p_hello (struct thread *thread)
2514: {
2515: struct isis_circuit *circuit;
2516:
2517: circuit = THREAD_ARG (thread);
2518: assert (circuit);
2519: circuit->u.p2p.t_send_p2p_hello = NULL;
2520:
2521: send_hello (circuit, 1);
2522:
2523: /* set next timer thread */
2524: THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello,
2525: circuit, isis_jitter (circuit->hello_interval[1],
2526: IIH_JITTER));
2527:
2528: return ISIS_OK;
2529: }
2530:
2531: static int
2532: build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
2533: struct isis_circuit *circuit)
2534: {
2535: struct isis_fixed_hdr fixed_hdr;
2536: struct isis_passwd *passwd;
2537: unsigned long lenp;
2538: u_int16_t length;
1.1.1.2 misho 2539: unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
2540: unsigned long auth_tlv_offset = 0;
2541: int retval = ISIS_OK;
2542:
1.1.1.4 ! misho 2543: isis_circuit_stream(circuit, &circuit->snd_stream);
1.1 misho 2544:
1.1.1.2 misho 2545: if (level == IS_LEVEL_1)
1.1 misho 2546: fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
2547: circuit->snd_stream);
2548: else
2549: fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
2550: circuit->snd_stream);
2551:
2552: /*
2553: * Fill Level 1 or 2 Complete Sequence Numbers header
2554: */
2555:
2556: lenp = stream_get_endp (circuit->snd_stream);
2557: stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
2558: /* no need to send the source here, it is always us if we csnp */
2559: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2560: /* with zero circuit id - ref 9.10, 9.11 */
2561: stream_putc (circuit->snd_stream, 0x00);
2562:
2563: stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
2564: stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
2565:
2566: /*
2567: * And TLVs
2568: */
1.1.1.2 misho 2569: if (level == IS_LEVEL_1)
1.1 misho 2570: passwd = &circuit->area->area_passwd;
2571: else
2572: passwd = &circuit->area->domain_passwd;
2573:
2574: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
1.1.1.2 misho 2575: {
2576: switch (passwd->type)
1.1 misho 2577: {
1.1.1.2 misho 2578: /* Cleartext */
2579: case ISIS_PASSWD_TYPE_CLEARTXT:
2580: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
2581: passwd->passwd, circuit->snd_stream))
2582: return ISIS_WARNING;
2583: break;
2584:
2585: /* HMAC MD5 */
2586: case ISIS_PASSWD_TYPE_HMAC_MD5:
2587: /* Remember where TLV is written so we can later overwrite the MD5 hash */
2588: auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2589: memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2590: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
2591: hmac_md5_hash, circuit->snd_stream))
2592: return ISIS_WARNING;
2593: break;
2594:
2595: default:
2596: break;
1.1 misho 2597: }
1.1.1.2 misho 2598: }
2599:
2600: retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
2601: if (retval != ISIS_OK)
2602: return retval;
2603:
1.1 misho 2604: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
2605: /* Update PU length */
2606: stream_putw_at (circuit->snd_stream, lenp, length);
2607:
1.1.1.2 misho 2608: /* For HMAC MD5 we need to compute the md5 hash and store it */
2609: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
2610: passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2611: {
2612: hmac_md5 (STREAM_DATA (circuit->snd_stream),
2613: stream_get_endp(circuit->snd_stream),
2614: (unsigned char *) &passwd->passwd, passwd->len,
1.1.1.4 ! misho 2615: (unsigned char *) &hmac_md5_hash);
1.1.1.2 misho 2616: /* Copy the hash into the stream */
2617: memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2618: hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2619: }
2620:
1.1 misho 2621: return retval;
2622: }
2623:
2624: /*
1.1.1.2 misho 2625: * Count the maximum number of lsps that can be accomodated by a given size.
2626: */
2627: static uint16_t
2628: get_max_lsp_count (uint16_t size)
2629: {
2630: uint16_t tlv_count;
2631: uint16_t lsp_count;
2632: uint16_t remaining_size;
2633:
2634: /* First count the full size TLVs */
2635: tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
2636: lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
2637:
2638: /* The last TLV, if any */
2639: remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
2640: if (remaining_size - 2 >= LSP_ENTRIES_LEN)
2641: lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
2642:
2643: return lsp_count;
2644: }
2645:
2646: /*
2647: * Calculate the length of Authentication Info. TLV.
2648: */
2649: static uint16_t
2650: auth_tlv_length (int level, struct isis_circuit *circuit)
2651: {
2652: struct isis_passwd *passwd;
2653: uint16_t length;
2654:
2655: if (level == IS_LEVEL_1)
2656: passwd = &circuit->area->area_passwd;
2657: else
2658: passwd = &circuit->area->domain_passwd;
2659:
2660: /* Also include the length of TLV header */
2661: length = AUTH_INFO_HDRLEN;
2662: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
2663: {
2664: switch (passwd->type)
2665: {
2666: /* Cleartext */
2667: case ISIS_PASSWD_TYPE_CLEARTXT:
2668: length += passwd->len;
2669: break;
2670:
2671: /* HMAC MD5 */
2672: case ISIS_PASSWD_TYPE_HMAC_MD5:
2673: length += ISIS_AUTH_MD5_SIZE;
2674: break;
2675:
2676: default:
2677: break;
2678: }
2679: }
2680:
2681: return length;
2682: }
2683:
2684: /*
2685: * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
2686: */
2687: static uint16_t
2688: max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
2689: {
2690: int snp_hdr_len;
2691: int auth_tlv_len;
2692: uint16_t lsp_count;
2693:
2694: snp_hdr_len = ISIS_FIXED_HDR_LEN;
2695: if (snp_type == ISIS_SNP_CSNP_FLAG)
2696: snp_hdr_len += ISIS_CSNP_HDRLEN;
2697: else
2698: snp_hdr_len += ISIS_PSNP_HDRLEN;
2699:
2700: auth_tlv_len = auth_tlv_length (level, circuit);
2701: lsp_count = get_max_lsp_count (
2702: stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
2703: return lsp_count;
2704: }
2705:
2706: /*
1.1 misho 2707: * FIXME: support multiple CSNPs
2708: */
2709:
2710: int
2711: send_csnp (struct isis_circuit *circuit, int level)
2712: {
2713: u_char start[ISIS_SYS_ID_LEN + 2];
2714: u_char stop[ISIS_SYS_ID_LEN + 2];
2715: struct list *list = NULL;
2716: struct listnode *node;
2717: struct isis_lsp *lsp;
1.1.1.2 misho 2718: u_char num_lsps, loop = 1;
2719: int i, retval = ISIS_OK;
2720:
2721: if (circuit->area->lspdb[level - 1] == NULL ||
2722: dict_count (circuit->area->lspdb[level - 1]) == 0)
2723: return retval;
1.1 misho 2724:
2725: memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
2726: memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
2727:
1.1.1.2 misho 2728: num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
2729:
2730: while (loop)
1.1 misho 2731: {
2732: list = list_new ();
1.1.1.2 misho 2733: lsp_build_list (start, stop, num_lsps, list,
2734: circuit->area->lspdb[level - 1]);
2735: /*
2736: * Update the stop lsp_id before encoding this CSNP.
2737: */
2738: if (listcount (list) < num_lsps)
2739: {
2740: memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
2741: }
1.1 misho 2742: else
1.1.1.2 misho 2743: {
2744: node = listtail (list);
2745: lsp = listgetdata (node);
2746: memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
2747: }
1.1 misho 2748:
2749: retval = build_csnp (level, start, stop, list, circuit);
1.1.1.2 misho 2750: if (retval != ISIS_OK)
2751: {
2752: zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
2753: circuit->area->area_tag, level, circuit->interface->name);
2754: list_delete (list);
2755: return retval;
2756: }
1.1 misho 2757:
2758: if (isis->debugs & DEBUG_SNP_PACKETS)
1.1.1.2 misho 2759: {
1.1.1.4 ! misho 2760: zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd",
1.1.1.2 misho 2761: circuit->area->area_tag, level, circuit->interface->name,
2762: stream_get_endp (circuit->snd_stream));
2763: for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
2764: {
2765: zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2766: " cksum 0x%04x, lifetime %us",
2767: circuit->area->area_tag,
2768: rawlspid_print (lsp->lsp_header->lsp_id),
2769: ntohl (lsp->lsp_header->seq_num),
2770: ntohs (lsp->lsp_header->checksum),
2771: ntohs (lsp->lsp_header->rem_lifetime));
2772: }
2773: if (isis->debugs & DEBUG_PACKET_DUMP)
2774: zlog_dump_data (STREAM_DATA (circuit->snd_stream),
2775: stream_get_endp (circuit->snd_stream));
2776: }
2777:
2778: retval = circuit->tx (circuit, level);
2779: if (retval != ISIS_OK)
2780: {
2781: zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
2782: circuit->area->area_tag, level,
2783: circuit->interface->name);
2784: list_delete (list);
2785: return retval;
2786: }
1.1 misho 2787:
1.1.1.2 misho 2788: /*
2789: * Start lsp_id of the next CSNP should be one plus the
2790: * stop lsp_id in this current CSNP.
2791: */
2792: memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
2793: loop = 0;
2794: for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
2795: {
2796: if (start[i] < (u_char)0xff)
2797: {
2798: start[i] += 1;
2799: loop = 1;
2800: break;
2801: }
2802: }
2803: memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
1.1 misho 2804: list_delete (list);
2805: }
1.1.1.2 misho 2806:
1.1 misho 2807: return retval;
2808: }
2809:
2810: int
2811: send_l1_csnp (struct thread *thread)
2812: {
2813: struct isis_circuit *circuit;
2814: int retval = ISIS_OK;
2815:
2816: circuit = THREAD_ARG (thread);
2817: assert (circuit);
2818:
2819: circuit->t_send_csnp[0] = NULL;
2820:
2821: if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
2822: {
2823: send_csnp (circuit, 1);
2824: }
2825: /* set next timer thread */
2826: THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
2827: isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
2828:
2829: return retval;
2830: }
2831:
2832: int
2833: send_l2_csnp (struct thread *thread)
2834: {
2835: struct isis_circuit *circuit;
2836: int retval = ISIS_OK;
2837:
2838: circuit = THREAD_ARG (thread);
2839: assert (circuit);
2840:
2841: circuit->t_send_csnp[1] = NULL;
2842:
2843: if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
2844: {
2845: send_csnp (circuit, 2);
2846: }
2847: /* set next timer thread */
2848: THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
2849: isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
2850:
2851: return retval;
2852: }
2853:
2854: static int
2855: build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
2856: {
2857: struct isis_fixed_hdr fixed_hdr;
2858: unsigned long lenp;
2859: u_int16_t length;
2860: struct isis_lsp *lsp;
2861: struct isis_passwd *passwd;
2862: struct listnode *node;
1.1.1.2 misho 2863: unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
2864: unsigned long auth_tlv_offset = 0;
2865: int retval = ISIS_OK;
1.1 misho 2866:
1.1.1.4 ! misho 2867: isis_circuit_stream(circuit, &circuit->snd_stream);
1.1.1.2 misho 2868:
2869: if (level == IS_LEVEL_1)
1.1 misho 2870: fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
2871: circuit->snd_stream);
2872: else
2873: fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
2874: circuit->snd_stream);
2875:
2876: /*
2877: * Fill Level 1 or 2 Partial Sequence Numbers header
2878: */
2879: lenp = stream_get_endp (circuit->snd_stream);
2880: stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
2881: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2882: stream_putc (circuit->snd_stream, circuit->idx);
2883:
2884: /*
2885: * And TLVs
2886: */
2887:
1.1.1.2 misho 2888: if (level == IS_LEVEL_1)
1.1 misho 2889: passwd = &circuit->area->area_passwd;
2890: else
2891: passwd = &circuit->area->domain_passwd;
2892:
2893: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
1.1.1.2 misho 2894: {
2895: switch (passwd->type)
1.1 misho 2896: {
1.1.1.2 misho 2897: /* Cleartext */
2898: case ISIS_PASSWD_TYPE_CLEARTXT:
2899: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
2900: passwd->passwd, circuit->snd_stream))
2901: return ISIS_WARNING;
2902: break;
2903:
2904: /* HMAC MD5 */
2905: case ISIS_PASSWD_TYPE_HMAC_MD5:
2906: /* Remember where TLV is written so we can later overwrite the MD5 hash */
2907: auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2908: memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2909: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
2910: hmac_md5_hash, circuit->snd_stream))
2911: return ISIS_WARNING;
2912: break;
2913:
2914: default:
2915: break;
1.1 misho 2916: }
1.1.1.2 misho 2917: }
2918:
2919: retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
2920: if (retval != ISIS_OK)
2921: return retval;
1.1 misho 2922:
2923: if (isis->debugs & DEBUG_SNP_PACKETS)
2924: {
2925: for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
2926: {
2927: zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2928: " cksum 0x%04x, lifetime %us",
2929: circuit->area->area_tag,
2930: rawlspid_print (lsp->lsp_header->lsp_id),
2931: ntohl (lsp->lsp_header->seq_num),
2932: ntohs (lsp->lsp_header->checksum),
2933: ntohs (lsp->lsp_header->rem_lifetime));
2934: }
2935: }
2936:
2937: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
2938: /* Update PDU length */
2939: stream_putw_at (circuit->snd_stream, lenp, length);
2940:
1.1.1.2 misho 2941: /* For HMAC MD5 we need to compute the md5 hash and store it */
2942: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
2943: passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2944: {
2945: hmac_md5 (STREAM_DATA (circuit->snd_stream),
2946: stream_get_endp(circuit->snd_stream),
2947: (unsigned char *) &passwd->passwd, passwd->len,
1.1.1.4 ! misho 2948: (unsigned char *) &hmac_md5_hash);
1.1.1.2 misho 2949: /* Copy the hash into the stream */
2950: memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2951: hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2952: }
2953:
1.1 misho 2954: return ISIS_OK;
2955: }
2956:
2957: /*
2958: * 7.3.15.4 action on expiration of partial SNP interval
2959: * level 1
2960: */
2961: static int
2962: send_psnp (int level, struct isis_circuit *circuit)
2963: {
2964: struct isis_lsp *lsp;
2965: struct list *list = NULL;
2966: struct listnode *node;
1.1.1.2 misho 2967: u_char num_lsps;
2968: int retval = ISIS_OK;
1.1 misho 2969:
1.1.1.2 misho 2970: if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
2971: circuit->u.bc.is_dr[level - 1])
2972: return ISIS_OK;
1.1 misho 2973:
1.1.1.2 misho 2974: if (circuit->area->lspdb[level - 1] == NULL ||
2975: dict_count (circuit->area->lspdb[level - 1]) == 0)
2976: return ISIS_OK;
1.1 misho 2977:
1.1.1.2 misho 2978: if (! circuit->snd_stream)
2979: return ISIS_ERROR;
1.1 misho 2980:
1.1.1.2 misho 2981: num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
1.1 misho 2982:
1.1.1.2 misho 2983: while (1)
2984: {
2985: list = list_new ();
2986: lsp_build_list_ssn (circuit, num_lsps, list,
2987: circuit->area->lspdb[level - 1]);
2988:
2989: if (listcount (list) == 0)
2990: {
2991: list_delete (list);
2992: return ISIS_OK;
2993: }
2994:
2995: retval = build_psnp (level, circuit, list);
2996: if (retval != ISIS_OK)
2997: {
2998: zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
2999: circuit->area->area_tag, level, circuit->interface->name);
3000: list_delete (list);
3001: return retval;
3002: }
3003:
3004: if (isis->debugs & DEBUG_SNP_PACKETS)
3005: {
1.1.1.4 ! misho 3006: zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd",
1.1.1.2 misho 3007: circuit->area->area_tag, level,
3008: circuit->interface->name,
3009: stream_get_endp (circuit->snd_stream));
3010: if (isis->debugs & DEBUG_PACKET_DUMP)
3011: zlog_dump_data (STREAM_DATA (circuit->snd_stream),
3012: stream_get_endp (circuit->snd_stream));
3013: }
3014:
3015: retval = circuit->tx (circuit, level);
3016: if (retval != ISIS_OK)
3017: {
3018: zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
3019: circuit->area->area_tag, level,
3020: circuit->interface->name);
3021: list_delete (list);
3022: return retval;
3023: }
3024:
3025: /*
3026: * sending succeeded, we can clear SSN flags of this circuit
3027: * for the LSPs in list
3028: */
3029: for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
3030: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
3031: list_delete (list);
1.1 misho 3032: }
3033:
3034: return retval;
3035: }
3036:
3037: int
3038: send_l1_psnp (struct thread *thread)
3039: {
3040:
3041: struct isis_circuit *circuit;
3042: int retval = ISIS_OK;
3043:
3044: circuit = THREAD_ARG (thread);
3045: assert (circuit);
3046:
3047: circuit->t_send_psnp[0] = NULL;
3048:
3049: send_psnp (1, circuit);
3050: /* set next timer thread */
3051: THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
3052: isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
3053:
3054: return retval;
3055: }
3056:
3057: /*
3058: * 7.3.15.4 action on expiration of partial SNP interval
3059: * level 2
3060: */
3061: int
3062: send_l2_psnp (struct thread *thread)
3063: {
3064: struct isis_circuit *circuit;
3065: int retval = ISIS_OK;
3066:
3067: circuit = THREAD_ARG (thread);
3068: assert (circuit);
3069:
3070: circuit->t_send_psnp[1] = NULL;
3071:
3072: send_psnp (2, circuit);
3073:
3074: /* set next timer thread */
3075: THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
3076: isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
3077:
3078: return retval;
3079: }
3080:
3081: /*
3082: * ISO 10589 - 7.3.14.3
3083: */
3084: int
3085: send_lsp (struct thread *thread)
3086: {
3087: struct isis_circuit *circuit;
3088: struct isis_lsp *lsp;
3089: struct listnode *node;
1.1.1.4 ! misho 3090: int clear_srm = 1;
1.1.1.2 misho 3091: int retval = ISIS_OK;
1.1 misho 3092:
3093: circuit = THREAD_ARG (thread);
3094: assert (circuit);
3095:
1.1.1.4 ! misho 3096: if (!circuit->lsp_queue)
! 3097: return ISIS_OK;
1.1.1.2 misho 3098:
1.1.1.3 misho 3099: node = listhead (circuit->lsp_queue);
3100:
3101: /*
3102: * Handle case where there are no LSPs on the queue. This can
3103: * happen, for instance, if an adjacency goes down before this
3104: * thread gets a chance to run.
3105: */
3106: if (!node)
1.1.1.4 ! misho 3107: return ISIS_OK;
1.1.1.3 misho 3108:
1.1.1.4 ! misho 3109: /*
! 3110: * Delete LSP from lsp_queue. If it's still in queue, it is assumed
! 3111: * as 'transmit pending', but send_lsp may never be called again.
! 3112: * Retry will happen because SRM flag will not be cleared.
! 3113: */
1.1.1.3 misho 3114: lsp = listgetdata(node);
1.1.1.4 ! misho 3115: list_delete_node (circuit->lsp_queue, node);
! 3116:
! 3117: /* Set the last-cleared time if the queue is empty. */
! 3118: /* TODO: Is is possible that new lsps keep being added to the queue
! 3119: * that the queue is never empty? */
! 3120: if (list_isempty (circuit->lsp_queue))
! 3121: circuit->lsp_queue_last_cleared = time (NULL);
! 3122:
! 3123: if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
! 3124: goto out;
1.1.1.2 misho 3125:
3126: /*
3127: * Do not send if levels do not match
3128: */
3129: if (!(lsp->level & circuit->is_type))
1.1.1.4 ! misho 3130: goto out;
1.1 misho 3131:
1.1.1.2 misho 3132: /*
3133: * Do not send if we do not have adjacencies in state up on the circuit
3134: */
3135: if (circuit->upadjcount[lsp->level - 1] == 0)
1.1.1.4 ! misho 3136: goto out;
! 3137:
! 3138: /* stream_copy will assert and stop program execution if LSP is larger than
! 3139: * the circuit's MTU. So handle and log this case here. */
! 3140: if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream))
! 3141: {
! 3142: zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
! 3143: " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
! 3144: " while interface stream size is %zu.",
! 3145: circuit->area->area_tag, lsp->level,
! 3146: rawlspid_print(lsp->lsp_header->lsp_id),
! 3147: ntohl(lsp->lsp_header->seq_num),
! 3148: ntohs(lsp->lsp_header->checksum),
! 3149: ntohs(lsp->lsp_header->rem_lifetime),
! 3150: circuit->interface->name,
! 3151: stream_get_endp(lsp->pdu),
! 3152: stream_get_size(circuit->snd_stream));
! 3153: if (isis->debugs & DEBUG_PACKET_DUMP)
! 3154: zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu));
! 3155: retval = ISIS_ERROR;
! 3156: goto out;
1.1.1.2 misho 3157: }
1.1 misho 3158:
1.1.1.2 misho 3159: /* copy our lsp to the send buffer */
3160: stream_copy (circuit->snd_stream, lsp->pdu);
1.1 misho 3161:
1.1.1.2 misho 3162: if (isis->debugs & DEBUG_UPDATE_PACKETS)
3163: {
3164: zlog_debug
1.1.1.4 ! misho 3165: ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
1.1.1.2 misho 3166: " lifetime %us on %s", circuit->area->area_tag, lsp->level,
3167: rawlspid_print (lsp->lsp_header->lsp_id),
3168: ntohl (lsp->lsp_header->seq_num),
3169: ntohs (lsp->lsp_header->checksum),
3170: ntohs (lsp->lsp_header->rem_lifetime),
3171: circuit->interface->name);
3172: if (isis->debugs & DEBUG_PACKET_DUMP)
3173: zlog_dump_data (STREAM_DATA (circuit->snd_stream),
3174: stream_get_endp (circuit->snd_stream));
3175: }
3176:
1.1.1.4 ! misho 3177: clear_srm = 0;
1.1.1.2 misho 3178: retval = circuit->tx (circuit, lsp->level);
3179: if (retval != ISIS_OK)
3180: {
1.1.1.4 ! misho 3181: zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s",
1.1.1.2 misho 3182: circuit->area->area_tag, lsp->level,
1.1.1.4 ! misho 3183: circuit->interface->name,
! 3184: (retval == ISIS_WARNING) ? "temporarily" : "permanently");
1.1.1.2 misho 3185: }
1.1 misho 3186:
1.1.1.4 ! misho 3187: out:
! 3188: if (clear_srm
! 3189: || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST)
! 3190: || (retval != ISIS_OK && retval != ISIS_WARNING))
! 3191: {
! 3192: /* SRM flag will trigger retransmission. We will not retransmit if we
! 3193: * encountered a fatal error.
! 3194: * On success, they should only be cleared if it's a broadcast circuit.
! 3195: * On a P2P circuit, we will wait for the ack from the neighbor to clear
! 3196: * the fag.
! 3197: */
! 3198: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 3199: }
1.1 misho 3200:
3201: return retval;
3202: }
3203:
3204: int
3205: ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
3206: int level)
3207: {
3208: unsigned long lenp;
3209: int retval;
3210: u_int16_t length;
3211: struct isis_fixed_hdr fixed_hdr;
3212:
1.1.1.4 ! misho 3213: isis_circuit_stream(circuit, &circuit->snd_stream);
1.1 misho 3214:
1.1.1.2 misho 3215: // fill_llc_hdr (stream);
3216: if (level == IS_LEVEL_1)
1.1 misho 3217: fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
3218: circuit->snd_stream);
3219: else
3220: fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
3221: circuit->snd_stream);
3222:
3223:
3224: lenp = stream_get_endp (circuit->snd_stream);
3225: stream_putw (circuit->snd_stream, 0); /* PDU length */
3226: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
3227: stream_putc (circuit->snd_stream, circuit->idx);
3228: stream_putc (circuit->snd_stream, 9); /* code */
3229: stream_putc (circuit->snd_stream, 16); /* len */
3230:
3231: stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime));
3232: stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
3233: stream_putl (circuit->snd_stream, ntohl (hdr->seq_num));
3234: stream_putw (circuit->snd_stream, ntohs (hdr->checksum));
3235:
3236: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
3237: /* Update PDU length */
3238: stream_putw_at (circuit->snd_stream, lenp, length);
3239:
3240: retval = circuit->tx (circuit, level);
1.1.1.2 misho 3241: if (retval != ISIS_OK)
3242: zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
3243: circuit->area->area_tag, level,
3244: circuit->interface->name);
1.1 misho 3245:
3246: return retval;
3247: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>