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