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