]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_message.c
Merge pull request #8899 from idryzhov/ospf6-asbr
[mirror_frr.git] / ospf6d / ospf6_message.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "memory.h"
24 #include "log.h"
25 #include "vty.h"
26 #include "command.h"
27 #include "thread.h"
28 #include "linklist.h"
29 #include "lib_errors.h"
30
31 #include "ospf6_proto.h"
32 #include "ospf6_lsa.h"
33 #include "ospf6_lsdb.h"
34 #include "ospf6_top.h"
35 #include "ospf6_network.h"
36 #include "ospf6_message.h"
37
38 #include "ospf6_area.h"
39 #include "ospf6_neighbor.h"
40 #include "ospf6_interface.h"
41
42 /* for structures and macros ospf6_lsa_examin() needs */
43 #include "ospf6_abr.h"
44 #include "ospf6_asbr.h"
45 #include "ospf6_intra.h"
46
47 #include "ospf6_flood.h"
48 #include "ospf6d.h"
49
50 #include <netinet/ip6.h>
51
52 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
53 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet");
54 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue");
55
56 unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
57 static const struct message ospf6_message_type_str[] = {
58 {OSPF6_MESSAGE_TYPE_HELLO, "Hello"},
59 {OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc"},
60 {OSPF6_MESSAGE_TYPE_LSREQ, "LSReq"},
61 {OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate"},
62 {OSPF6_MESSAGE_TYPE_LSACK, "LSAck"},
63 {0}};
64
65 /* Minimum (besides the standard OSPF packet header) lengths for OSPF
66 packets of particular types, offset is the "type" field. */
67 const uint16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] = {
68 0,
69 OSPF6_HELLO_MIN_SIZE,
70 OSPF6_DB_DESC_MIN_SIZE,
71 OSPF6_LS_REQ_MIN_SIZE,
72 OSPF6_LS_UPD_MIN_SIZE,
73 OSPF6_LS_ACK_MIN_SIZE};
74
75 /* Minimum (besides the standard LSA header) lengths for LSAs of particular
76 types, offset is the "LSA function code" portion of "LSA type" field. */
77 const uint16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = {
78 0,
79 /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE,
80 /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE,
81 /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
82 /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE,
83 /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
84 /* 0x2006 */ 0,
85 /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
86 /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE,
87 /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE};
88
89 /* print functions */
90
91 static void ospf6_header_print(struct ospf6_header *oh)
92 {
93 zlog_debug(" OSPFv%d Type:%d Len:%hu Router-ID:%pI4", oh->version,
94 oh->type, ntohs(oh->length), &oh->router_id);
95 zlog_debug(" Area-ID:%pI4 Cksum:%hx Instance-ID:%d", &oh->area_id,
96 ntohs(oh->checksum), oh->instance_id);
97 }
98
99 void ospf6_hello_print(struct ospf6_header *oh, int action)
100 {
101 struct ospf6_hello *hello;
102 char options[16];
103 char *p;
104
105 ospf6_header_print(oh);
106 assert(oh->type == OSPF6_MESSAGE_TYPE_HELLO);
107
108 hello = (struct ospf6_hello *)((caddr_t)oh
109 + sizeof(struct ospf6_header));
110
111 ospf6_options_printbuf(hello->options, options, sizeof(options));
112
113 zlog_debug(" I/F-Id:%ld Priority:%d Option:%s",
114 (unsigned long)ntohl(hello->interface_id), hello->priority,
115 options);
116 zlog_debug(" HelloInterval:%hu DeadInterval:%hu",
117 ntohs(hello->hello_interval), ntohs(hello->dead_interval));
118 zlog_debug(" DR:%pI4 BDR:%pI4", &hello->drouter, &hello->bdrouter);
119
120 if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
121 && action == OSPF6_ACTION_RECV)
122 || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
123 && action == OSPF6_ACTION_SEND)) {
124
125 for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
126 p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
127 p += sizeof(uint32_t))
128 zlog_debug(" Neighbor: %pI4", (in_addr_t *)p);
129
130 assert(p == OSPF6_MESSAGE_END(oh));
131 }
132 }
133
134 void ospf6_dbdesc_print(struct ospf6_header *oh, int action)
135 {
136 struct ospf6_dbdesc *dbdesc;
137 char options[16];
138 char *p;
139
140 ospf6_header_print(oh);
141 assert(oh->type == OSPF6_MESSAGE_TYPE_DBDESC);
142
143 dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
144 + sizeof(struct ospf6_header));
145
146 ospf6_options_printbuf(dbdesc->options, options, sizeof(options));
147
148 zlog_debug(" MBZ: %#x Option: %s IfMTU: %hu", dbdesc->reserved1,
149 options, ntohs(dbdesc->ifmtu));
150 zlog_debug(" MBZ: %#x Bits: %s%s%s SeqNum: %#lx", dbdesc->reserved2,
151 (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"),
152 (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"),
153 (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"),
154 (unsigned long)ntohl(dbdesc->seqnum));
155
156 if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
157 && action == OSPF6_ACTION_RECV)
158 || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
159 && action == OSPF6_ACTION_SEND)) {
160
161 for (p = (char *)((caddr_t)dbdesc
162 + sizeof(struct ospf6_dbdesc));
163 p + sizeof(struct ospf6_lsa_header)
164 <= OSPF6_MESSAGE_END(oh);
165 p += sizeof(struct ospf6_lsa_header))
166 ospf6_lsa_header_print_raw(
167 (struct ospf6_lsa_header *)p);
168
169 assert(p == OSPF6_MESSAGE_END(oh));
170 }
171 }
172
173 void ospf6_lsreq_print(struct ospf6_header *oh, int action)
174 {
175 char *p;
176
177 ospf6_header_print(oh);
178 assert(oh->type == OSPF6_MESSAGE_TYPE_LSREQ);
179
180 if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
181 && action == OSPF6_ACTION_RECV)
182 || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
183 && action == OSPF6_ACTION_SEND)) {
184
185 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
186 p + sizeof(struct ospf6_lsreq_entry)
187 <= OSPF6_MESSAGE_END(oh);
188 p += sizeof(struct ospf6_lsreq_entry)) {
189 struct ospf6_lsreq_entry *e =
190 (struct ospf6_lsreq_entry *)p;
191
192 zlog_debug(" [%s Id:%pI4 Adv:%pI4]",
193 ospf6_lstype_name(e->type), &e->id,
194 &e->adv_router);
195 }
196
197 assert(p == OSPF6_MESSAGE_END(oh));
198 }
199 }
200
201 void ospf6_lsupdate_print(struct ospf6_header *oh, int action)
202 {
203 struct ospf6_lsupdate *lsupdate;
204 unsigned long num;
205 char *p;
206
207 ospf6_header_print(oh);
208 assert(oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE);
209
210 lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
211 + sizeof(struct ospf6_header));
212
213 num = ntohl(lsupdate->lsa_number);
214 zlog_debug(" Number of LSA: %ld", num);
215
216 if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
217 && action == OSPF6_ACTION_RECV)
218 || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
219 && action == OSPF6_ACTION_SEND)) {
220
221 for (p = (char *)((caddr_t)lsupdate
222 + sizeof(struct ospf6_lsupdate));
223 p < OSPF6_MESSAGE_END(oh)
224 && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
225 p += OSPF6_LSA_SIZE(p)) {
226 ospf6_lsa_header_print_raw(
227 (struct ospf6_lsa_header *)p);
228 }
229
230 assert(p == OSPF6_MESSAGE_END(oh));
231 }
232 }
233
234 void ospf6_lsack_print(struct ospf6_header *oh, int action)
235 {
236 char *p;
237
238 ospf6_header_print(oh);
239 assert(oh->type == OSPF6_MESSAGE_TYPE_LSACK);
240
241 if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
242 && action == OSPF6_ACTION_RECV)
243 || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
244 && action == OSPF6_ACTION_SEND)) {
245
246 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
247 p + sizeof(struct ospf6_lsa_header)
248 <= OSPF6_MESSAGE_END(oh);
249 p += sizeof(struct ospf6_lsa_header))
250 ospf6_lsa_header_print_raw(
251 (struct ospf6_lsa_header *)p);
252
253 assert(p == OSPF6_MESSAGE_END(oh));
254 }
255 }
256
257 static struct ospf6_packet *ospf6_packet_new(size_t size)
258 {
259 struct ospf6_packet *new;
260
261 new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
262 new->s = stream_new(size);
263
264 return new;
265 }
266
267 static void ospf6_packet_free(struct ospf6_packet *op)
268 {
269 if (op->s)
270 stream_free(op->s);
271
272 XFREE(MTYPE_OSPF6_PACKET, op);
273 }
274
275 struct ospf6_fifo *ospf6_fifo_new(void)
276 {
277 struct ospf6_fifo *new;
278
279 new = XCALLOC(MTYPE_OSPF6_FIFO, sizeof(struct ospf6_fifo));
280 return new;
281 }
282
283 /* Add new packet to fifo. */
284 static void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op)
285 {
286 if (fifo->tail)
287 fifo->tail->next = op;
288 else
289 fifo->head = op;
290
291 fifo->tail = op;
292
293 fifo->count++;
294 }
295
296 /* Add new packet to head of fifo. */
297 static void ospf6_fifo_push_head(struct ospf6_fifo *fifo,
298 struct ospf6_packet *op)
299 {
300 op->next = fifo->head;
301
302 if (fifo->tail == NULL)
303 fifo->tail = op;
304
305 fifo->head = op;
306
307 fifo->count++;
308 }
309
310 /* Delete first packet from fifo. */
311 static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo)
312 {
313 struct ospf6_packet *op;
314
315 op = fifo->head;
316
317 if (op) {
318 fifo->head = op->next;
319
320 if (fifo->head == NULL)
321 fifo->tail = NULL;
322
323 fifo->count--;
324 }
325
326 return op;
327 }
328
329 /* Return first fifo entry. */
330 static struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo)
331 {
332 return fifo->head;
333 }
334
335 /* Flush ospf packet fifo. */
336 void ospf6_fifo_flush(struct ospf6_fifo *fifo)
337 {
338 struct ospf6_packet *op;
339 struct ospf6_packet *next;
340
341 for (op = fifo->head; op; op = next) {
342 next = op->next;
343 ospf6_packet_free(op);
344 }
345 fifo->head = fifo->tail = NULL;
346 fifo->count = 0;
347 }
348
349 /* Free ospf packet fifo. */
350 void ospf6_fifo_free(struct ospf6_fifo *fifo)
351 {
352 ospf6_fifo_flush(fifo);
353
354 XFREE(MTYPE_OSPF6_FIFO, fifo);
355 }
356
357 static void ospf6_packet_add(struct ospf6_interface *oi,
358 struct ospf6_packet *op)
359 {
360 /* Add packet to end of queue. */
361 ospf6_fifo_push(oi->obuf, op);
362
363 /* Debug of packet fifo*/
364 /* ospf_fifo_debug (oi->obuf); */
365 }
366
367 static void ospf6_packet_add_top(struct ospf6_interface *oi,
368 struct ospf6_packet *op)
369 {
370 /* Add packet to head of queue. */
371 ospf6_fifo_push_head(oi->obuf, op);
372
373 /* Debug of packet fifo*/
374 /* ospf_fifo_debug (oi->obuf); */
375 }
376
377 static void ospf6_packet_delete(struct ospf6_interface *oi)
378 {
379 struct ospf6_packet *op;
380
381 op = ospf6_fifo_pop(oi->obuf);
382
383 if (op)
384 ospf6_packet_free(op);
385 }
386
387
388 static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
389 struct ospf6_interface *oi,
390 struct ospf6_header *oh)
391 {
392 struct ospf6_hello *hello;
393 struct ospf6_neighbor *on;
394 char *p;
395 int twoway = 0;
396 int neighborchange = 0;
397 int neighbor_ifindex_change = 0;
398 int backupseen = 0;
399 int64_t latency = 0;
400 struct timeval timestamp;
401
402 monotime(&timestamp);
403 hello = (struct ospf6_hello *)((caddr_t)oh
404 + sizeof(struct ospf6_header));
405
406 /* HelloInterval check */
407 if (ntohs(hello->hello_interval) != oi->hello_interval) {
408 zlog_warn(
409 "VRF %s: I/F %s HelloInterval mismatch: (my %d, rcvd %d)",
410 vrf_id_to_name(oi->interface->vrf_id),
411 oi->interface->name, oi->hello_interval,
412 ntohs(hello->hello_interval));
413 return;
414 }
415
416 /* RouterDeadInterval check */
417 if (ntohs(hello->dead_interval) != oi->dead_interval) {
418 zlog_warn(
419 "VRF %s: I/F %s DeadInterval mismatch: (my %d, rcvd %d)",
420 vrf_id_to_name(oi->interface->vrf_id),
421 oi->interface->name, oi->dead_interval,
422 ntohs(hello->dead_interval));
423 return;
424 }
425
426 /* E-bit check */
427 if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_E)
428 != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_E)) {
429 zlog_warn("VRF %s: IF %s E-bit mismatch",
430 vrf_id_to_name(oi->interface->vrf_id),
431 oi->interface->name);
432 return;
433 }
434
435 /* Find neighbor, create if not exist */
436 on = ospf6_neighbor_lookup(oh->router_id, oi);
437 if (on == NULL) {
438 on = ospf6_neighbor_create(oh->router_id, oi);
439 on->prev_drouter = on->drouter = hello->drouter;
440 on->prev_bdrouter = on->bdrouter = hello->bdrouter;
441 on->priority = hello->priority;
442 }
443
444 /* check latency against hello period */
445 if (on->hello_in)
446 latency = monotime_since(&on->last_hello, NULL)
447 - (oi->hello_interval * 1000000);
448 /* log if latency exceeds the hello period */
449 if (latency > (oi->hello_interval * 1000000))
450 zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__,
451 &on->router_id, latency);
452 on->last_hello = timestamp;
453 on->hello_in++;
454
455 /* Always override neighbor's source address */
456 memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
457
458 /* Neighbor ifindex check */
459 if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) {
460 on->ifindex = ntohl(hello->interface_id);
461 neighbor_ifindex_change++;
462 }
463
464 /* TwoWay check */
465 for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
466 p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
467 p += sizeof(uint32_t)) {
468 uint32_t *router_id = (uint32_t *)p;
469
470 if (*router_id == oi->area->ospf6->router_id)
471 twoway++;
472 }
473
474 assert(p == OSPF6_MESSAGE_END(oh));
475
476 /* RouterPriority check */
477 if (on->priority != hello->priority) {
478 on->priority = hello->priority;
479 neighborchange++;
480 }
481
482 /* DR check */
483 if (on->drouter != hello->drouter) {
484 on->prev_drouter = on->drouter;
485 on->drouter = hello->drouter;
486 if (on->prev_drouter == on->router_id
487 || on->drouter == on->router_id)
488 neighborchange++;
489 }
490
491 /* BDR check */
492 if (on->bdrouter != hello->bdrouter) {
493 on->prev_bdrouter = on->bdrouter;
494 on->bdrouter = hello->bdrouter;
495 if (on->prev_bdrouter == on->router_id
496 || on->bdrouter == on->router_id)
497 neighborchange++;
498 }
499
500 /* BackupSeen check */
501 if (oi->state == OSPF6_INTERFACE_WAITING) {
502 if (hello->bdrouter == on->router_id)
503 backupseen++;
504 else if (hello->drouter == on->router_id
505 && hello->bdrouter == htonl(0))
506 backupseen++;
507 }
508
509 oi->hello_in++;
510
511 /* Execute neighbor events */
512 thread_execute(master, hello_received, on, 0);
513 if (twoway)
514 thread_execute(master, twoway_received, on, 0);
515 else
516 thread_execute(master, oneway_received, on, 0);
517
518 /* Schedule interface events */
519 if (backupseen)
520 thread_add_event(master, backup_seen, oi, 0, NULL);
521 if (neighborchange)
522 thread_add_event(master, neighbor_change, oi, 0, NULL);
523
524 if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL)
525 OSPF6_ROUTER_LSA_SCHEDULE(oi->area);
526 }
527
528 static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
529 struct ospf6_neighbor *on)
530 {
531 struct ospf6_dbdesc *dbdesc;
532 char *p;
533
534 dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
535 + sizeof(struct ospf6_header));
536
537 if (on->state < OSPF6_NEIGHBOR_INIT) {
538 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
539 zlog_debug("Neighbor state less than Init, ignore");
540 return;
541 }
542
543 switch (on->state) {
544 case OSPF6_NEIGHBOR_TWOWAY:
545 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
546 zlog_debug("Neighbor state is 2-Way, ignore");
547 return;
548
549 case OSPF6_NEIGHBOR_INIT:
550 thread_execute(master, twoway_received, on, 0);
551 if (on->state != OSPF6_NEIGHBOR_EXSTART) {
552 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
553 zlog_debug(
554 "Neighbor state is not ExStart, ignore");
555 return;
556 }
557 /* else fall through to ExStart */
558 /* fallthru */
559 case OSPF6_NEIGHBOR_EXSTART:
560 /* if neighbor obeys us as our slave, schedule negotiation_done
561 and process LSA Headers. Otherwise, ignore this message */
562 if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)
563 && !CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)
564 && ntohl(dbdesc->seqnum) == on->dbdesc_seqnum) {
565 /* execute NegotiationDone */
566 thread_execute(master, negotiation_done, on, 0);
567
568 /* Record neighbor options */
569 memcpy(on->options, dbdesc->options,
570 sizeof(on->options));
571 } else {
572 zlog_warn(
573 "VRF %s: Nbr %s: Negotiation failed",
574 vrf_id_to_name(on->ospf6_if->interface->vrf_id),
575 on->name);
576 return;
577 }
578 /* fall through to exchange */
579
580 case OSPF6_NEIGHBOR_EXCHANGE:
581 if (!memcmp(dbdesc, &on->dbdesc_last,
582 sizeof(struct ospf6_dbdesc))) {
583 /* Duplicated DatabaseDescription is dropped by master
584 */
585 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
586 zlog_debug(
587 "Duplicated dbdesc discarded by Master, ignore");
588 return;
589 }
590
591 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
592 zlog_warn(
593 "DbDesc recv: Master/Slave bit mismatch Nbr %s",
594 on->name);
595 thread_add_event(master, seqnumber_mismatch, on, 0,
596 NULL);
597 return;
598 }
599
600 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
601 zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
602 on->name);
603 thread_add_event(master, seqnumber_mismatch, on, 0,
604 NULL);
605 return;
606 }
607
608 if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
609 zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
610 on->name);
611 thread_add_event(master, seqnumber_mismatch, on, 0,
612 NULL);
613 return;
614 }
615
616 if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
617 zlog_warn(
618 "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)",
619 on->name, (unsigned long)on->dbdesc_seqnum);
620 thread_add_event(master, seqnumber_mismatch, on, 0,
621 NULL);
622 return;
623 }
624 break;
625
626 case OSPF6_NEIGHBOR_LOADING:
627 case OSPF6_NEIGHBOR_FULL:
628 if (!memcmp(dbdesc, &on->dbdesc_last,
629 sizeof(struct ospf6_dbdesc))) {
630 /* Duplicated DatabaseDescription is dropped by master
631 */
632 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
633 zlog_debug(
634 "Duplicated dbdesc discarded by Master, ignore");
635 return;
636 }
637
638 zlog_warn(
639 "DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
640 ospf6_neighbor_state_str[on->state], on->name);
641 thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
642 return;
643
644 default:
645 assert(0);
646 break;
647 }
648
649 /* Process LSA headers */
650 for (p = (char *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
651 p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
652 p += sizeof(struct ospf6_lsa_header)) {
653 struct ospf6_lsa *his, *mine;
654 struct ospf6_lsdb *lsdb = NULL;
655
656 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
657
658 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
659 zlog_debug("%s", his->name);
660
661 switch (OSPF6_LSA_SCOPE(his->header->type)) {
662 case OSPF6_SCOPE_LINKLOCAL:
663 lsdb = on->ospf6_if->lsdb;
664 break;
665 case OSPF6_SCOPE_AREA:
666 lsdb = on->ospf6_if->area->lsdb;
667 break;
668 case OSPF6_SCOPE_AS:
669 lsdb = on->ospf6_if->area->ospf6->lsdb;
670 break;
671 case OSPF6_SCOPE_RESERVED:
672 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
673 zlog_debug("Ignoring LSA of reserved scope");
674 ospf6_lsa_delete(his);
675 continue;
676 break;
677 }
678
679 if (ntohs(his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
680 && (IS_AREA_STUB(on->ospf6_if->area)
681 || IS_AREA_NSSA(on->ospf6_if->area))) {
682 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
683 zlog_debug(
684 "SeqNumMismatch (E-bit mismatch), discard");
685 ospf6_lsa_delete(his);
686 thread_add_event(master, seqnumber_mismatch, on, 0,
687 NULL);
688 return;
689 }
690
691 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
692 his->header->adv_router, lsdb);
693 if (mine == NULL) {
694 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
695 zlog_debug("Add request (No database copy)");
696 ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
697 } else if (ospf6_lsa_compare(his, mine) < 0) {
698 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
699 zlog_debug("Add request (Received MoreRecent)");
700 ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
701 } else {
702 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
703 zlog_debug("Discard (Existing MoreRecent)");
704 }
705 ospf6_lsa_delete(his);
706 }
707
708 assert(p == OSPF6_MESSAGE_END(oh));
709
710 /* Increment sequence number */
711 on->dbdesc_seqnum++;
712
713 /* schedule send lsreq */
714 if (on->request_list->count)
715 thread_add_event(master, ospf6_lsreq_send, on, 0,
716 &on->thread_send_lsreq);
717
718 THREAD_OFF(on->thread_send_dbdesc);
719
720 /* More bit check */
721 if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
722 && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
723 thread_add_event(master, exchange_done, on, 0, NULL);
724 else {
725 on->thread_send_dbdesc = NULL;
726 thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
727 &on->thread_send_dbdesc);
728 }
729
730 /* save last received dbdesc */
731 memcpy(&on->dbdesc_last, dbdesc, sizeof(struct ospf6_dbdesc));
732 }
733
734 static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
735 struct ospf6_neighbor *on)
736 {
737 struct ospf6_dbdesc *dbdesc;
738 char *p;
739
740 dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
741 + sizeof(struct ospf6_header));
742
743 if (on->state < OSPF6_NEIGHBOR_INIT) {
744 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
745 zlog_debug("Neighbor state less than Init, ignore");
746 return;
747 }
748
749 switch (on->state) {
750 case OSPF6_NEIGHBOR_TWOWAY:
751 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
752 zlog_debug("Neighbor state is 2-Way, ignore");
753 return;
754
755 case OSPF6_NEIGHBOR_INIT:
756 thread_execute(master, twoway_received, on, 0);
757 if (on->state != OSPF6_NEIGHBOR_EXSTART) {
758 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
759 zlog_debug(
760 "Neighbor state is not ExStart, ignore");
761 return;
762 }
763 /* else fall through to ExStart */
764 /* fallthru */
765 case OSPF6_NEIGHBOR_EXSTART:
766 /* If the neighbor is Master, act as Slave. Schedule
767 negotiation_done
768 and process LSA Headers. Otherwise, ignore this message */
769 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)
770 && CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
771 && CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)
772 && ntohs(oh->length)
773 == sizeof(struct ospf6_header)
774 + sizeof(struct ospf6_dbdesc)) {
775 /* set the master/slave bit to slave */
776 UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
777
778 /* set the DD sequence number to one specified by master
779 */
780 on->dbdesc_seqnum = ntohl(dbdesc->seqnum);
781
782 /* schedule NegotiationDone */
783 thread_execute(master, negotiation_done, on, 0);
784
785 /* Record neighbor options */
786 memcpy(on->options, dbdesc->options,
787 sizeof(on->options));
788 } else {
789 zlog_warn(
790 "VRF %s: Nbr %s Negotiation failed",
791 vrf_id_to_name(on->ospf6_if->interface->vrf_id),
792 on->name);
793 return;
794 }
795 break;
796
797 case OSPF6_NEIGHBOR_EXCHANGE:
798 if (!memcmp(dbdesc, &on->dbdesc_last,
799 sizeof(struct ospf6_dbdesc))) {
800 /* Duplicated DatabaseDescription causes slave to
801 * retransmit */
802 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
803 zlog_debug(
804 "Duplicated dbdesc causes retransmit");
805 THREAD_OFF(on->thread_send_dbdesc);
806 on->thread_send_dbdesc = NULL;
807 thread_add_event(master, ospf6_dbdesc_send, on, 0,
808 &on->thread_send_dbdesc);
809 return;
810 }
811
812 if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
813 zlog_warn(
814 "DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
815 on->name);
816 thread_add_event(master, seqnumber_mismatch, on, 0,
817 NULL);
818 return;
819 }
820
821 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
822 zlog_warn(
823 "DbDesc slave recv: Initialize bit mismatch Nbr %s",
824 on->name);
825 thread_add_event(master, seqnumber_mismatch, on, 0,
826 NULL);
827 return;
828 }
829
830 if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
831 zlog_warn(
832 "DbDesc slave recv: Option field mismatch Nbr %s",
833 on->name);
834 thread_add_event(master, seqnumber_mismatch, on, 0,
835 NULL);
836 return;
837 }
838
839 if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
840 zlog_warn(
841 "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)",
842 on->name, (unsigned long)on->dbdesc_seqnum + 1);
843 thread_add_event(master, seqnumber_mismatch, on, 0,
844 NULL);
845 return;
846 }
847 break;
848
849 case OSPF6_NEIGHBOR_LOADING:
850 case OSPF6_NEIGHBOR_FULL:
851 if (!memcmp(dbdesc, &on->dbdesc_last,
852 sizeof(struct ospf6_dbdesc))) {
853 /* Duplicated DatabaseDescription causes slave to
854 * retransmit */
855 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
856 zlog_debug(
857 "Duplicated dbdesc causes retransmit");
858 THREAD_OFF(on->thread_send_dbdesc);
859 thread_add_event(master, ospf6_dbdesc_send, on, 0,
860 &on->thread_send_dbdesc);
861 return;
862 }
863
864 zlog_warn(
865 "DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
866 ospf6_neighbor_state_str[on->state], on->name);
867 thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
868 return;
869
870 default:
871 assert(0);
872 break;
873 }
874
875 /* Process LSA headers */
876 for (p = (char *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
877 p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
878 p += sizeof(struct ospf6_lsa_header)) {
879 struct ospf6_lsa *his, *mine;
880 struct ospf6_lsdb *lsdb = NULL;
881
882 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
883
884 switch (OSPF6_LSA_SCOPE(his->header->type)) {
885 case OSPF6_SCOPE_LINKLOCAL:
886 lsdb = on->ospf6_if->lsdb;
887 break;
888 case OSPF6_SCOPE_AREA:
889 lsdb = on->ospf6_if->area->lsdb;
890 break;
891 case OSPF6_SCOPE_AS:
892 lsdb = on->ospf6_if->area->ospf6->lsdb;
893 break;
894 case OSPF6_SCOPE_RESERVED:
895 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
896 zlog_debug("Ignoring LSA of reserved scope");
897 ospf6_lsa_delete(his);
898 continue;
899 break;
900 }
901
902 if (OSPF6_LSA_SCOPE(his->header->type) == OSPF6_SCOPE_AS
903 && (IS_AREA_STUB(on->ospf6_if->area)
904 || IS_AREA_NSSA(on->ospf6_if->area))) {
905 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
906 zlog_debug("E-bit mismatch with LSA Headers");
907 ospf6_lsa_delete(his);
908 thread_add_event(master, seqnumber_mismatch, on, 0,
909 NULL);
910 return;
911 }
912
913 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
914 his->header->adv_router, lsdb);
915 if (mine == NULL || ospf6_lsa_compare(his, mine) < 0) {
916 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
917 zlog_debug("Add request-list: %s", his->name);
918 ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
919 }
920 ospf6_lsa_delete(his);
921 }
922
923 assert(p == OSPF6_MESSAGE_END(oh));
924
925 /* Set sequence number to Master's */
926 on->dbdesc_seqnum = ntohl(dbdesc->seqnum);
927
928 /* schedule send lsreq */
929 if (on->request_list->count)
930 thread_add_event(master, ospf6_lsreq_send, on, 0,
931 &on->thread_send_lsreq);
932
933 THREAD_OFF(on->thread_send_dbdesc);
934 thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
935 &on->thread_send_dbdesc);
936
937 /* save last received dbdesc */
938 memcpy(&on->dbdesc_last, dbdesc, sizeof(struct ospf6_dbdesc));
939 }
940
941 static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst,
942 struct ospf6_interface *oi,
943 struct ospf6_header *oh)
944 {
945 struct ospf6_neighbor *on;
946 struct ospf6_dbdesc *dbdesc;
947
948 on = ospf6_neighbor_lookup(oh->router_id, oi);
949 if (on == NULL) {
950 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
951 zlog_debug("Neighbor not found, ignore");
952 return;
953 }
954
955 dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
956 + sizeof(struct ospf6_header));
957
958 /* Interface MTU check */
959 if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) {
960 zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)",
961 vrf_id_to_name(oi->interface->vrf_id),
962 oi->interface->name, oi->ifmtu, ntohs(dbdesc->ifmtu));
963 return;
964 }
965
966 if (dbdesc->reserved1 || dbdesc->reserved2) {
967 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
968 zlog_debug(
969 "Non-0 reserved field in %s's DbDesc, correct",
970 on->name);
971 dbdesc->reserved1 = 0;
972 dbdesc->reserved2 = 0;
973 }
974
975 oi->db_desc_in++;
976
977 if (ntohl(oh->router_id) < ntohl(oi->area->ospf6->router_id))
978 ospf6_dbdesc_recv_master(oh, on);
979 else if (ntohl(oi->area->ospf6->router_id) < ntohl(oh->router_id))
980 ospf6_dbdesc_recv_slave(oh, on);
981 else {
982 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
983 zlog_debug("Can't decide which is master, ignore");
984 }
985 }
986
987 static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
988 struct ospf6_interface *oi,
989 struct ospf6_header *oh)
990 {
991 struct ospf6_neighbor *on;
992 char *p;
993 struct ospf6_lsreq_entry *e;
994 struct ospf6_lsdb *lsdb = NULL;
995 struct ospf6_lsa *lsa;
996
997 on = ospf6_neighbor_lookup(oh->router_id, oi);
998 if (on == NULL) {
999 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1000 zlog_debug("Neighbor not found, ignore");
1001 return;
1002 }
1003
1004 if (on->state != OSPF6_NEIGHBOR_EXCHANGE
1005 && on->state != OSPF6_NEIGHBOR_LOADING
1006 && on->state != OSPF6_NEIGHBOR_FULL) {
1007 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1008 zlog_debug("Neighbor state less than Exchange, ignore");
1009 return;
1010 }
1011
1012 oi->ls_req_in++;
1013
1014 /* Process each request */
1015 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
1016 p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh);
1017 p += sizeof(struct ospf6_lsreq_entry)) {
1018 e = (struct ospf6_lsreq_entry *)p;
1019
1020 switch (OSPF6_LSA_SCOPE(e->type)) {
1021 case OSPF6_SCOPE_LINKLOCAL:
1022 lsdb = on->ospf6_if->lsdb;
1023 break;
1024 case OSPF6_SCOPE_AREA:
1025 lsdb = on->ospf6_if->area->lsdb;
1026 break;
1027 case OSPF6_SCOPE_AS:
1028 lsdb = on->ospf6_if->area->ospf6->lsdb;
1029 break;
1030 default:
1031 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1032 zlog_debug("Ignoring LSA of reserved scope");
1033 continue;
1034 break;
1035 }
1036
1037 /* Find database copy */
1038 lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb);
1039 if (lsa == NULL) {
1040 zlog_warn(
1041 "Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
1042 ospf6_lstype_name(e->type), &e->id,
1043 &e->adv_router);
1044 thread_add_event(master, bad_lsreq, on, 0, NULL);
1045 return;
1046 }
1047
1048 ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->lsupdate_list);
1049 }
1050
1051 assert(p == OSPF6_MESSAGE_END(oh));
1052
1053 /* schedule send lsupdate */
1054 THREAD_OFF(on->thread_send_lsupdate);
1055 thread_add_event(master, ospf6_lsupdate_send_neighbor, on, 0,
1056 &on->thread_send_lsupdate);
1057 }
1058
1059 /* Verify, that the specified memory area contains exactly N valid IPv6
1060 prefixes as specified by RFC5340, A.4.1. */
1061 static unsigned ospf6_prefixes_examin(
1062 struct ospf6_prefix *current, /* start of buffer */
1063 unsigned length,
1064 const uint32_t req_num_pfxs /* always compared with the actual number
1065 of prefixes */
1066 )
1067 {
1068 uint8_t requested_pfx_bytes;
1069 uint32_t real_num_pfxs = 0;
1070
1071 while (length) {
1072 if (length < OSPF6_PREFIX_MIN_SIZE) {
1073 zlog_warn("%s: undersized IPv6 prefix header",
1074 __func__);
1075 return MSG_NG;
1076 }
1077 /* safe to look deeper */
1078 if (current->prefix_length > IPV6_MAX_BITLEN) {
1079 zlog_warn("%s: invalid PrefixLength (%u bits)",
1080 __func__, current->prefix_length);
1081 return MSG_NG;
1082 }
1083 /* covers both fixed- and variable-sized fields */
1084 requested_pfx_bytes =
1085 OSPF6_PREFIX_MIN_SIZE
1086 + OSPF6_PREFIX_SPACE(current->prefix_length);
1087 if (requested_pfx_bytes > length) {
1088 zlog_warn("%s: undersized IPv6 prefix", __func__);
1089 return MSG_NG;
1090 }
1091 /* next prefix */
1092 length -= requested_pfx_bytes;
1093 current = (struct ospf6_prefix *)((caddr_t)current
1094 + requested_pfx_bytes);
1095 real_num_pfxs++;
1096 }
1097 if (real_num_pfxs != req_num_pfxs) {
1098 zlog_warn(
1099 "%s: IPv6 prefix number mismatch (%u required, %u real)",
1100 __func__, req_num_pfxs, real_num_pfxs);
1101 return MSG_NG;
1102 }
1103 return MSG_OK;
1104 }
1105
1106 /* Verify an LSA to have a valid length and dispatch further (where
1107 appropriate) to check if the contents, including nested IPv6 prefixes,
1108 is properly sized/aligned within the LSA. Note that this function gets
1109 LSA type in network byte order, uses in host byte order and passes to
1110 ospf6_lstype_name() in network byte order again. */
1111 static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
1112 const uint16_t lsalen,
1113 const uint8_t headeronly)
1114 {
1115 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1116 struct ospf6_as_external_lsa *as_external_lsa;
1117 struct ospf6_link_lsa *link_lsa;
1118 unsigned exp_length;
1119 uint8_t ltindex;
1120 uint16_t lsatype;
1121
1122 /* In case an additional minimum length constraint is defined for
1123 current
1124 LSA type, make sure that this constraint is met. */
1125 lsatype = ntohs(lsah->type);
1126 ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
1127 if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
1128 && lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
1129 zlog_warn("%s: undersized (%u B) LSA", __func__, lsalen);
1130 return MSG_NG;
1131 }
1132 switch (lsatype) {
1133 case OSPF6_LSTYPE_ROUTER:
1134 /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes
1135 followed
1136 by N>=0 interface descriptions. */
1137 if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
1138 % OSPF6_ROUTER_LSDESC_FIX_SIZE) {
1139 zlog_warn(
1140 "%s: Router LSA interface description alignment error",
1141 __func__);
1142 return MSG_NG;
1143 }
1144 break;
1145 case OSPF6_LSTYPE_NETWORK:
1146 /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes
1147 followed by N>=0 attached router descriptions. */
1148 if ((lsalen - OSPF6_LSA_HEADER_SIZE
1149 - OSPF6_NETWORK_LSA_MIN_SIZE)
1150 % OSPF6_NETWORK_LSDESC_FIX_SIZE) {
1151 zlog_warn(
1152 "%s: Network LSA router description alignment error",
1153 __func__);
1154 return MSG_NG;
1155 }
1156 break;
1157 case OSPF6_LSTYPE_INTER_PREFIX:
1158 /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE
1159 bytes
1160 followed by 3-4 fields of a single IPv6 prefix. */
1161 if (headeronly)
1162 break;
1163 return ospf6_prefixes_examin(
1164 (struct ospf6_prefix
1165 *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE
1166 + OSPF6_INTER_PREFIX_LSA_MIN_SIZE),
1167 lsalen - OSPF6_LSA_HEADER_SIZE
1168 - OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
1169 1);
1170 case OSPF6_LSTYPE_INTER_ROUTER:
1171 /* RFC5340 A.4.6, fixed-size LSA. */
1172 if (lsalen
1173 > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
1174 zlog_warn("%s: Inter Router LSA oversized (%u B) LSA",
1175 __func__, lsalen);
1176 return MSG_NG;
1177 }
1178 break;
1179 case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */
1180 case OSPF6_LSTYPE_TYPE_7:
1181 /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE
1182 bytes
1183 followed by 3-4 fields of IPv6 prefix and 3 conditional LSA
1184 fields:
1185 16 bytes of forwarding address, 4 bytes of external route
1186 tag,
1187 4 bytes of referenced link state ID. */
1188 if (headeronly)
1189 break;
1190 as_external_lsa =
1191 (struct ospf6_as_external_lsa
1192 *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
1193 exp_length =
1194 OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE;
1195 /* To find out if the last optional field (Referenced Link State
1196 ID) is
1197 assumed in this LSA, we need to access fixed fields of the
1198 IPv6
1199 prefix before ospf6_prefix_examin() confirms its sizing. */
1200 if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
1201 zlog_warn(
1202 "%s: AS External undersized (%u B) LSA header",
1203 __func__, lsalen);
1204 return MSG_NG;
1205 }
1206 /* forwarding address */
1207 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F))
1208 exp_length += 16;
1209 /* external route tag */
1210 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T))
1211 exp_length += 4;
1212 /* referenced link state ID */
1213 if (as_external_lsa->prefix.u._prefix_referenced_lstype)
1214 exp_length += 4;
1215 /* All the fixed-size fields (mandatory and optional) must fit.
1216 I.e.,
1217 this check does not include any IPv6 prefix fields. */
1218 if (exp_length > lsalen) {
1219 zlog_warn(
1220 "%s: AS External undersized (%u B) LSA header",
1221 __func__, lsalen);
1222 return MSG_NG;
1223 }
1224 /* The last call completely covers the remainder (IPv6 prefix).
1225 */
1226 return ospf6_prefixes_examin(
1227 (struct ospf6_prefix
1228 *)((caddr_t)as_external_lsa
1229 + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE),
1230 lsalen - exp_length, 1);
1231 case OSPF6_LSTYPE_LINK:
1232 /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes
1233 followed
1234 by N>=0 IPv6 prefix blocks (with N declared beforehand). */
1235 if (headeronly)
1236 break;
1237 link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsah
1238 + OSPF6_LSA_HEADER_SIZE);
1239 return ospf6_prefixes_examin(
1240 (struct ospf6_prefix *)((caddr_t)link_lsa
1241 + OSPF6_LINK_LSA_MIN_SIZE),
1242 lsalen - OSPF6_LSA_HEADER_SIZE
1243 - OSPF6_LINK_LSA_MIN_SIZE,
1244 ntohl(link_lsa->prefix_num) /* 32 bits */
1245 );
1246 case OSPF6_LSTYPE_INTRA_PREFIX:
1247 /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE
1248 bytes
1249 followed by N>=0 IPv6 prefixes (with N declared beforehand).
1250 */
1251 if (headeronly)
1252 break;
1253 intra_prefix_lsa =
1254 (struct ospf6_intra_prefix_lsa
1255 *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
1256 return ospf6_prefixes_examin(
1257 (struct ospf6_prefix
1258 *)((caddr_t)intra_prefix_lsa
1259 + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE),
1260 lsalen - OSPF6_LSA_HEADER_SIZE
1261 - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
1262 ntohs(intra_prefix_lsa->prefix_num) /* 16 bits */
1263 );
1264 }
1265 /* No additional validation is possible for unknown LSA types, which are
1266 themselves valid in OPSFv3, hence the default decision is to accept.
1267 */
1268 return MSG_OK;
1269 }
1270
1271 /* Verify if the provided input buffer is a valid sequence of LSAs. This
1272 includes verification of LSA blocks length/alignment and dispatching
1273 of deeper-level checks. */
1274 static unsigned
1275 ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
1276 size_t length, const uint8_t headeronly,
1277 /* When declared_num_lsas is not 0, compare it to the real
1278 number of LSAs
1279 and treat the difference as an error. */
1280 const uint32_t declared_num_lsas)
1281 {
1282 uint32_t counted_lsas = 0;
1283
1284 while (length) {
1285 uint16_t lsalen;
1286 if (length < OSPF6_LSA_HEADER_SIZE) {
1287 zlog_warn(
1288 "%s: undersized (%zu B) trailing (#%u) LSA header",
1289 __func__, length, counted_lsas);
1290 return MSG_NG;
1291 }
1292 /* save on ntohs() calls here and in the LSA validator */
1293 lsalen = OSPF6_LSA_SIZE(lsah);
1294 if (lsalen < OSPF6_LSA_HEADER_SIZE) {
1295 zlog_warn(
1296 "%s: malformed LSA header #%u, declared length is %u B",
1297 __func__, counted_lsas, lsalen);
1298 return MSG_NG;
1299 }
1300 if (headeronly) {
1301 /* less checks here and in ospf6_lsa_examin() */
1302 if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
1303 zlog_warn(
1304 "%s: anomaly in header-only %s LSA #%u",
1305 __func__, ospf6_lstype_name(lsah->type),
1306 counted_lsas);
1307 return MSG_NG;
1308 }
1309 lsah = (struct ospf6_lsa_header
1310 *)((caddr_t)lsah
1311 + OSPF6_LSA_HEADER_SIZE);
1312 length -= OSPF6_LSA_HEADER_SIZE;
1313 } else {
1314 /* make sure the input buffer is deep enough before
1315 * further checks */
1316 if (lsalen > length) {
1317 zlog_warn(
1318 "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
1319 __func__, ospf6_lstype_name(lsah->type),
1320 counted_lsas, lsalen, length);
1321 return MSG_NG;
1322 }
1323 if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
1324 zlog_warn("%s: anomaly in %s LSA #%u", __func__,
1325 ospf6_lstype_name(lsah->type),
1326 counted_lsas);
1327 return MSG_NG;
1328 }
1329 lsah = (struct ospf6_lsa_header *)((caddr_t)lsah
1330 + lsalen);
1331 length -= lsalen;
1332 }
1333 counted_lsas++;
1334 }
1335
1336 if (declared_num_lsas && counted_lsas != declared_num_lsas) {
1337 zlog_warn("%s: #LSAs declared (%u) does not match actual (%u)",
1338 __func__, declared_num_lsas, counted_lsas);
1339 return MSG_NG;
1340 }
1341 return MSG_OK;
1342 }
1343
1344 /* Verify a complete OSPF packet for proper sizing/alignment. */
1345 static unsigned ospf6_packet_examin(struct ospf6_header *oh,
1346 const unsigned bytesonwire)
1347 {
1348 struct ospf6_lsupdate *lsupd;
1349 unsigned test;
1350
1351 /* length, 1st approximation */
1352 if (bytesonwire < OSPF6_HEADER_SIZE) {
1353 zlog_warn("%s: undersized (%u B) packet", __func__,
1354 bytesonwire);
1355 return MSG_NG;
1356 }
1357 /* Now it is safe to access header fields. */
1358 if (bytesonwire != ntohs(oh->length)) {
1359 zlog_warn("%s: %s packet length error (%u real, %u declared)",
1360 __func__,
1361 lookup_msg(ospf6_message_type_str, oh->type, NULL),
1362 bytesonwire, ntohs(oh->length));
1363 return MSG_NG;
1364 }
1365 /* version check */
1366 if (oh->version != OSPFV3_VERSION) {
1367 zlog_warn("%s: invalid (%u) protocol version", __func__,
1368 oh->version);
1369 return MSG_NG;
1370 }
1371 /* length, 2nd approximation */
1372 if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
1373 && bytesonwire
1374 < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
1375 zlog_warn("%s: undersized (%u B) %s packet", __func__,
1376 bytesonwire,
1377 lookup_msg(ospf6_message_type_str, oh->type, NULL));
1378 return MSG_NG;
1379 }
1380 /* type-specific deeper validation */
1381 switch (oh->type) {
1382 case OSPF6_MESSAGE_TYPE_HELLO:
1383 /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes
1384 followed
1385 by N>=0 router-IDs. */
1386 if (0
1387 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
1388 % 4)
1389 return MSG_OK;
1390 zlog_warn("%s: alignment error in %s packet", __func__,
1391 lookup_msg(ospf6_message_type_str, oh->type, NULL));
1392 return MSG_NG;
1393 case OSPF6_MESSAGE_TYPE_DBDESC:
1394 /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes
1395 followed
1396 by N>=0 header-only LSAs. */
1397 test = ospf6_lsaseq_examin(
1398 (struct ospf6_lsa_header *)((caddr_t)oh
1399 + OSPF6_HEADER_SIZE
1400 + OSPF6_DB_DESC_MIN_SIZE),
1401 bytesonwire - OSPF6_HEADER_SIZE
1402 - OSPF6_DB_DESC_MIN_SIZE,
1403 1, 0);
1404 break;
1405 case OSPF6_MESSAGE_TYPE_LSREQ:
1406 /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */
1407 if (0
1408 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
1409 % OSPF6_LSREQ_LSDESC_FIX_SIZE)
1410 return MSG_OK;
1411 zlog_warn("%s: alignment error in %s packet", __func__,
1412 lookup_msg(ospf6_message_type_str, oh->type, NULL));
1413 return MSG_NG;
1414 case OSPF6_MESSAGE_TYPE_LSUPDATE:
1415 /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes
1416 followed
1417 by N>=0 full LSAs (with N declared beforehand). */
1418 lsupd = (struct ospf6_lsupdate *)((caddr_t)oh
1419 + OSPF6_HEADER_SIZE);
1420 test = ospf6_lsaseq_examin(
1421 (struct ospf6_lsa_header *)((caddr_t)lsupd
1422 + OSPF6_LS_UPD_MIN_SIZE),
1423 bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE,
1424 0, ntohl(lsupd->lsa_number) /* 32 bits */
1425 );
1426 break;
1427 case OSPF6_MESSAGE_TYPE_LSACK:
1428 /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */
1429 test = ospf6_lsaseq_examin(
1430 (struct ospf6_lsa_header *)((caddr_t)oh
1431 + OSPF6_HEADER_SIZE
1432 + OSPF6_LS_ACK_MIN_SIZE),
1433 bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE,
1434 1, 0);
1435 break;
1436 default:
1437 zlog_warn("%s: invalid (%u) message type", __func__, oh->type);
1438 return MSG_NG;
1439 }
1440 if (test != MSG_OK)
1441 zlog_warn("%s: anomaly in %s packet", __func__,
1442 lookup_msg(ospf6_message_type_str, oh->type, NULL));
1443 return test;
1444 }
1445
1446 /* Verify particular fields of otherwise correct received OSPF packet to
1447 meet the requirements of RFC. */
1448 static int ospf6_rxpacket_examin(struct ospf6_interface *oi,
1449 struct ospf6_header *oh,
1450 const unsigned bytesonwire)
1451 {
1452
1453 if (MSG_OK != ospf6_packet_examin(oh, bytesonwire))
1454 return MSG_NG;
1455
1456 /* Area-ID check */
1457 if (oh->area_id != oi->area->area_id) {
1458 if (oh->area_id == OSPF_AREA_BACKBONE)
1459 zlog_warn(
1460 "VRF %s: I/F %s Message may be via Virtual Link: not supported",
1461 vrf_id_to_name(oi->interface->vrf_id),
1462 oi->interface->name);
1463 else
1464 zlog_warn(
1465 "VRF %s: I/F %s Area-ID mismatch (my %pI4, rcvd %pI4)",
1466 vrf_id_to_name(oi->interface->vrf_id),
1467 oi->interface->name, &oi->area->area_id,
1468 &oh->area_id);
1469 return MSG_NG;
1470 }
1471
1472 /* Instance-ID check */
1473 if (oh->instance_id != oi->instance_id) {
1474 zlog_warn(
1475 "VRF %s: I/F %s Instance-ID mismatch (my %u, rcvd %u)",
1476 vrf_id_to_name(oi->interface->vrf_id),
1477 oi->interface->name, oi->instance_id, oh->instance_id);
1478 return MSG_NG;
1479 }
1480
1481 /* Router-ID check */
1482 if (oh->router_id == oi->area->ospf6->router_id) {
1483 zlog_warn("VRF %s: I/F %s Duplicate Router-ID (%pI4)",
1484 vrf_id_to_name(oi->interface->vrf_id),
1485 oi->interface->name, &oh->router_id);
1486 return MSG_NG;
1487 }
1488 return MSG_OK;
1489 }
1490
1491 static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst,
1492 struct ospf6_interface *oi,
1493 struct ospf6_header *oh)
1494 {
1495 struct ospf6_neighbor *on;
1496 struct ospf6_lsupdate *lsupdate;
1497 char *p;
1498
1499 on = ospf6_neighbor_lookup(oh->router_id, oi);
1500 if (on == NULL) {
1501 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1502 zlog_debug("Neighbor not found, ignore");
1503 return;
1504 }
1505
1506 if (on->state != OSPF6_NEIGHBOR_EXCHANGE
1507 && on->state != OSPF6_NEIGHBOR_LOADING
1508 && on->state != OSPF6_NEIGHBOR_FULL) {
1509 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1510 zlog_debug("Neighbor state less than Exchange, ignore");
1511 return;
1512 }
1513
1514 lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
1515 + sizeof(struct ospf6_header));
1516
1517 oi->ls_upd_in++;
1518
1519 /* Process LSAs */
1520 for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
1521 p < OSPF6_MESSAGE_END(oh)
1522 && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
1523 p += OSPF6_LSA_SIZE(p)) {
1524 ospf6_receive_lsa(on, (struct ospf6_lsa_header *)p);
1525 }
1526
1527 assert(p == OSPF6_MESSAGE_END(oh));
1528 }
1529
1530 static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst,
1531 struct ospf6_interface *oi,
1532 struct ospf6_header *oh)
1533 {
1534 struct ospf6_neighbor *on;
1535 char *p;
1536 struct ospf6_lsa *his, *mine;
1537 struct ospf6_lsdb *lsdb = NULL;
1538
1539 assert(oh->type == OSPF6_MESSAGE_TYPE_LSACK);
1540
1541 on = ospf6_neighbor_lookup(oh->router_id, oi);
1542 if (on == NULL) {
1543 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1544 zlog_debug("Neighbor not found, ignore");
1545 return;
1546 }
1547
1548 if (on->state != OSPF6_NEIGHBOR_EXCHANGE
1549 && on->state != OSPF6_NEIGHBOR_LOADING
1550 && on->state != OSPF6_NEIGHBOR_FULL) {
1551 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
1552 zlog_debug("Neighbor state less than Exchange, ignore");
1553 return;
1554 }
1555
1556 oi->ls_ack_in++;
1557
1558 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
1559 p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
1560 p += sizeof(struct ospf6_lsa_header)) {
1561 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
1562
1563 switch (OSPF6_LSA_SCOPE(his->header->type)) {
1564 case OSPF6_SCOPE_LINKLOCAL:
1565 lsdb = on->ospf6_if->lsdb;
1566 break;
1567 case OSPF6_SCOPE_AREA:
1568 lsdb = on->ospf6_if->area->lsdb;
1569 break;
1570 case OSPF6_SCOPE_AS:
1571 lsdb = on->ospf6_if->area->ospf6->lsdb;
1572 break;
1573 case OSPF6_SCOPE_RESERVED:
1574 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1575 zlog_debug("Ignoring LSA of reserved scope");
1576 ospf6_lsa_delete(his);
1577 continue;
1578 break;
1579 }
1580
1581 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1582 zlog_debug("%s acknowledged by %s", his->name,
1583 on->name);
1584
1585 /* Find database copy */
1586 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
1587 his->header->adv_router, lsdb);
1588 if (mine == NULL) {
1589 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1590 zlog_debug("No database copy");
1591 ospf6_lsa_delete(his);
1592 continue;
1593 }
1594
1595 /* Check if the LSA is on his retrans-list */
1596 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
1597 his->header->adv_router,
1598 on->retrans_list);
1599 if (mine == NULL) {
1600 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1601 zlog_debug("Not on %s's retrans-list",
1602 on->name);
1603 ospf6_lsa_delete(his);
1604 continue;
1605 }
1606
1607 if (ospf6_lsa_compare(his, mine) != 0) {
1608 /* Log this questionable acknowledgement,
1609 and examine the next one. */
1610 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1611 zlog_debug("Questionable acknowledgement");
1612 ospf6_lsa_delete(his);
1613 continue;
1614 }
1615
1616 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
1617 zlog_debug(
1618 "Acknowledged, remove from %s's retrans-list",
1619 on->name);
1620
1621 ospf6_decrement_retrans_count(mine);
1622 if (OSPF6_LSA_IS_MAXAGE(mine))
1623 ospf6_maxage_remove(on->ospf6_if->area->ospf6);
1624 ospf6_lsdb_remove(mine, on->retrans_list);
1625 ospf6_lsa_delete(his);
1626 }
1627
1628 assert(p == OSPF6_MESSAGE_END(oh));
1629 }
1630
1631 static uint8_t *recvbuf = NULL;
1632 static uint8_t *sendbuf = NULL;
1633 static unsigned int iobuflen = 0;
1634
1635 int ospf6_iobuf_size(unsigned int size)
1636 {
1637 uint8_t *recvnew, *sendnew;
1638
1639 if (size <= iobuflen)
1640 return iobuflen;
1641
1642 recvnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
1643 sendnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
1644
1645 XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
1646 XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
1647 recvbuf = recvnew;
1648 sendbuf = sendnew;
1649 iobuflen = size;
1650
1651 return iobuflen;
1652 }
1653
1654 void ospf6_message_terminate(void)
1655 {
1656 XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
1657 XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
1658
1659 iobuflen = 0;
1660 }
1661
1662 enum ospf6_read_return_enum {
1663 OSPF6_READ_ERROR,
1664 OSPF6_READ_CONTINUE,
1665 };
1666
1667 static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6)
1668 {
1669 int len;
1670 struct in6_addr src, dst;
1671 ifindex_t ifindex;
1672 struct iovec iovector[2];
1673 struct ospf6_interface *oi;
1674 struct ospf6_header *oh;
1675
1676 /* initialize */
1677 memset(&src, 0, sizeof(src));
1678 memset(&dst, 0, sizeof(dst));
1679 ifindex = 0;
1680 memset(recvbuf, 0, iobuflen);
1681 iovector[0].iov_base = recvbuf;
1682 iovector[0].iov_len = iobuflen;
1683 iovector[1].iov_base = NULL;
1684 iovector[1].iov_len = 0;
1685
1686 /* receive message */
1687 len = ospf6_recvmsg(&src, &dst, &ifindex, iovector, sockfd);
1688 if (len < 0)
1689 return OSPF6_READ_ERROR;
1690
1691 if ((uint)len > iobuflen) {
1692 flog_err(EC_LIB_DEVELOPMENT, "Excess message read");
1693 return OSPF6_READ_ERROR;
1694 }
1695
1696 oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
1697 if (oi == NULL || oi->area == NULL
1698 || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
1699 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
1700 RECV_HDR))
1701 zlog_debug("Message received on disabled interface");
1702 return OSPF6_READ_CONTINUE;
1703 }
1704 if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
1705 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
1706 RECV_HDR))
1707 zlog_debug("%s: Ignore message on passive interface %s",
1708 __func__, oi->interface->name);
1709 return OSPF6_READ_CONTINUE;
1710 }
1711
1712 oh = (struct ospf6_header *)recvbuf;
1713 if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK)
1714 return OSPF6_READ_CONTINUE;
1715
1716 /* Being here means, that no sizing/alignment issues were detected in
1717 the input packet. This renders the additional checks performed below
1718 and also in the type-specific dispatching functions a dead code,
1719 which can be dismissed in a cleanup-focused review round later. */
1720
1721 /* Log */
1722 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) {
1723 zlog_debug("%s received on %s",
1724 lookup_msg(ospf6_message_type_str, oh->type, NULL),
1725 oi->interface->name);
1726 zlog_debug(" src: %pI6", &src);
1727 zlog_debug(" dst: %pI6", &dst);
1728
1729 switch (oh->type) {
1730 case OSPF6_MESSAGE_TYPE_HELLO:
1731 ospf6_hello_print(oh, OSPF6_ACTION_RECV);
1732 break;
1733 case OSPF6_MESSAGE_TYPE_DBDESC:
1734 ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
1735 break;
1736 case OSPF6_MESSAGE_TYPE_LSREQ:
1737 ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
1738 break;
1739 case OSPF6_MESSAGE_TYPE_LSUPDATE:
1740 ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
1741 break;
1742 case OSPF6_MESSAGE_TYPE_LSACK:
1743 ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
1744 break;
1745 default:
1746 assert(0);
1747 }
1748 }
1749
1750 switch (oh->type) {
1751 case OSPF6_MESSAGE_TYPE_HELLO:
1752 ospf6_hello_recv(&src, &dst, oi, oh);
1753 break;
1754
1755 case OSPF6_MESSAGE_TYPE_DBDESC:
1756 ospf6_dbdesc_recv(&src, &dst, oi, oh);
1757 break;
1758
1759 case OSPF6_MESSAGE_TYPE_LSREQ:
1760 ospf6_lsreq_recv(&src, &dst, oi, oh);
1761 break;
1762
1763 case OSPF6_MESSAGE_TYPE_LSUPDATE:
1764 ospf6_lsupdate_recv(&src, &dst, oi, oh);
1765 break;
1766
1767 case OSPF6_MESSAGE_TYPE_LSACK:
1768 ospf6_lsack_recv(&src, &dst, oi, oh);
1769 break;
1770
1771 default:
1772 assert(0);
1773 }
1774
1775 return OSPF6_READ_CONTINUE;
1776 }
1777
1778 int ospf6_receive(struct thread *thread)
1779 {
1780 int sockfd;
1781 struct ospf6 *ospf6;
1782 int count = 0;
1783
1784 /* add next read thread */
1785 ospf6 = THREAD_ARG(thread);
1786 sockfd = THREAD_FD(thread);
1787
1788 thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
1789 &ospf6->t_ospf6_receive);
1790
1791 while (count < ospf6->write_oi_count) {
1792 count++;
1793 switch (ospf6_read_helper(sockfd, ospf6)) {
1794 case OSPF6_READ_ERROR:
1795 return 0;
1796 case OSPF6_READ_CONTINUE:
1797 break;
1798 }
1799 }
1800
1801 return 0;
1802 }
1803
1804 static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi,
1805 struct stream *s)
1806 {
1807 struct ospf6_header *oh;
1808
1809 oh = (struct ospf6_header *)STREAM_DATA(s);
1810
1811 oh->version = (uint8_t)OSPFV3_VERSION;
1812 oh->type = type;
1813
1814 oh->router_id = oi->area->ospf6->router_id;
1815 oh->area_id = oi->area->area_id;
1816 oh->instance_id = oi->instance_id;
1817 oh->reserved = 0;
1818 stream_forward_endp(s, OSPF6_HEADER_SIZE);
1819 }
1820
1821 static void ospf6_fill_header(struct ospf6_interface *oi, struct stream *s,
1822 uint16_t length)
1823 {
1824 struct ospf6_header *oh;
1825
1826 oh = (struct ospf6_header *)STREAM_DATA(s);
1827
1828 oh->length = htons(length);
1829 }
1830
1831 static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num)
1832 {
1833 struct ospf6_header *oh;
1834 struct ospf6_lsupdate *lsu;
1835
1836 oh = (struct ospf6_header *)STREAM_DATA(s);
1837
1838 lsu = (struct ospf6_lsupdate *)((caddr_t)oh
1839 + sizeof(struct ospf6_header));
1840 lsu->lsa_number = htonl(lsa_num);
1841 }
1842
1843 static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
1844 {
1845 assert(oi->ifmtu > sizeof(struct ip6_hdr));
1846 return oi->ifmtu - (sizeof(struct ip6_hdr));
1847 }
1848
1849 static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s)
1850 {
1851 struct listnode *node, *nnode;
1852 struct ospf6_neighbor *on;
1853 uint16_t length = OSPF6_HELLO_MIN_SIZE;
1854
1855 stream_putl(s, oi->interface->ifindex);
1856 stream_putc(s, oi->priority);
1857 stream_putc(s, oi->area->options[0]);
1858 stream_putc(s, oi->area->options[1]);
1859 stream_putc(s, oi->area->options[2]);
1860 stream_putw(s, oi->hello_interval);
1861 stream_putw(s, oi->dead_interval);
1862 stream_put_ipv4(s, oi->drouter);
1863 stream_put_ipv4(s, oi->bdrouter);
1864
1865 for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
1866 if (on->state < OSPF6_NEIGHBOR_INIT)
1867 continue;
1868
1869 if ((length + sizeof(uint32_t) + OSPF6_HEADER_SIZE)
1870 > ospf6_packet_max(oi)) {
1871 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
1872 SEND))
1873 zlog_debug(
1874 "sending Hello message: exceeds I/F MTU");
1875 break;
1876 }
1877
1878 stream_put_ipv4(s, on->router_id);
1879 length += sizeof(uint32_t);
1880 }
1881
1882 return length;
1883 }
1884
1885 static int ospf6_write(struct thread *thread)
1886 {
1887 struct ospf6 *ospf6 = THREAD_ARG(thread);
1888 struct ospf6_interface *oi;
1889 struct ospf6_interface *last_serviced_oi = NULL;
1890 struct ospf6_header *oh;
1891 struct ospf6_packet *op;
1892 struct listnode *node;
1893 char srcname[64], dstname[64];
1894 struct iovec iovector[2];
1895 int pkt_count = 0;
1896 int len;
1897 int64_t latency = 0;
1898 struct timeval timestamp;
1899
1900 if (ospf6->fd < 0) {
1901 zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd);
1902 return -1;
1903 }
1904
1905 node = listhead(ospf6->oi_write_q);
1906 assert(node);
1907 oi = listgetdata(node);
1908
1909 while ((pkt_count < ospf6->write_oi_count) && oi
1910 && (last_serviced_oi != oi)) {
1911
1912 op = ospf6_fifo_head(oi->obuf);
1913 assert(op);
1914 assert(op->length >= OSPF6_HEADER_SIZE);
1915
1916 iovector[0].iov_base = (caddr_t)stream_pnt(op->s);
1917 iovector[0].iov_len = op->length;
1918 iovector[1].iov_base = NULL;
1919 iovector[1].iov_len = 0;
1920
1921 oh = (struct ospf6_header *)STREAM_DATA(op->s);
1922
1923 len = ospf6_sendmsg(oi->linklocal_addr, &op->dst,
1924 oi->interface->ifindex, iovector,
1925 ospf6->fd);
1926 if (len != op->length)
1927 flog_err(EC_LIB_DEVELOPMENT,
1928 "Could not send entire message");
1929
1930 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) {
1931 inet_ntop(AF_INET6, &op->dst, dstname, sizeof(dstname));
1932 inet_ntop(AF_INET6, oi->linklocal_addr, srcname,
1933 sizeof(srcname));
1934 zlog_debug("%s send on %s",
1935 lookup_msg(ospf6_message_type_str, oh->type,
1936 NULL),
1937 oi->interface->name);
1938 zlog_debug(" src: %s", srcname);
1939 zlog_debug(" dst: %s", dstname);
1940 }
1941 switch (oh->type) {
1942 case OSPF6_MESSAGE_TYPE_HELLO:
1943 monotime(&timestamp);
1944 if (oi->hello_out)
1945 latency = monotime_since(&oi->last_hello, NULL)
1946 - (oi->hello_interval * 1000000);
1947
1948 /* log if latency exceeds the hello period */
1949 if (latency > (oi->hello_interval * 1000000))
1950 zlog_warn("%s hello TX high latency %" PRId64
1951 "us.",
1952 __func__, latency);
1953 oi->last_hello = timestamp;
1954 oi->hello_out++;
1955 ospf6_hello_print(oh, OSPF6_ACTION_SEND);
1956 break;
1957 case OSPF6_MESSAGE_TYPE_DBDESC:
1958 oi->db_desc_out++;
1959 ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
1960 break;
1961 case OSPF6_MESSAGE_TYPE_LSREQ:
1962 oi->ls_req_out++;
1963 ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
1964 break;
1965 case OSPF6_MESSAGE_TYPE_LSUPDATE:
1966 oi->ls_upd_out++;
1967 ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
1968 break;
1969 case OSPF6_MESSAGE_TYPE_LSACK:
1970 oi->ls_ack_out++;
1971 ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
1972 break;
1973 default:
1974 zlog_debug("Unknown message");
1975 assert(0);
1976 break;
1977 }
1978 /* Now delete packet from queue. */
1979 ospf6_packet_delete(oi);
1980
1981 /* Move this interface to the tail of write_q to
1982 serve everyone in a round robin fashion */
1983 list_delete_node(ospf6->oi_write_q, node);
1984 if (ospf6_fifo_head(oi->obuf) == NULL) {
1985 oi->on_write_q = 0;
1986 last_serviced_oi = NULL;
1987 oi = NULL;
1988 } else {
1989 listnode_add(ospf6->oi_write_q, oi);
1990 }
1991
1992 /* Setup to service from the head of the queue again */
1993 if (!list_isempty(ospf6->oi_write_q)) {
1994 node = listhead(ospf6->oi_write_q);
1995 oi = listgetdata(node);
1996 }
1997 }
1998
1999 /* If packets still remain in queue, call write thread. */
2000 if (!list_isempty(ospf6->oi_write_q))
2001 thread_add_write(master, ospf6_write, ospf6, ospf6->fd,
2002 &ospf6->t_write);
2003
2004 return 0;
2005 }
2006
2007 int ospf6_hello_send(struct thread *thread)
2008 {
2009 struct ospf6_interface *oi;
2010 struct ospf6_packet *op;
2011 uint16_t length = OSPF6_HEADER_SIZE;
2012
2013 oi = (struct ospf6_interface *)THREAD_ARG(thread);
2014 oi->thread_send_hello = (struct thread *)NULL;
2015
2016 if (oi->state <= OSPF6_INTERFACE_DOWN) {
2017 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND_HDR))
2018 zlog_debug("Unable to send Hello on down interface %s",
2019 oi->interface->name);
2020 return 0;
2021 }
2022
2023 op = ospf6_packet_new(oi->ifmtu);
2024
2025 ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
2026
2027 /* Prepare OSPF Hello body */
2028 length += ospf6_make_hello(oi, op->s);
2029 if (length == OSPF6_HEADER_SIZE) {
2030 /* Hello overshooting MTU */
2031 ospf6_packet_free(op);
2032 return 0;
2033 }
2034
2035 /* Fill OSPF header. */
2036 ospf6_fill_header(oi, op->s, length);
2037
2038 /* Set packet length. */
2039 op->length = length;
2040
2041 op->dst = allspfrouters6;
2042
2043 /* Add packet to the top of the interface output queue, so that they
2044 * can't get delayed by things like long queues of LS Update packets
2045 */
2046 ospf6_packet_add_top(oi, op);
2047
2048 /* set next thread */
2049 thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
2050 &oi->thread_send_hello);
2051
2052 OSPF6_MESSAGE_WRITE_ON(oi);
2053
2054 return 0;
2055 }
2056
2057 static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
2058 {
2059 uint16_t length = OSPF6_DB_DESC_MIN_SIZE;
2060 struct ospf6_lsa *lsa, *lsanext;
2061
2062 /* if this is initial one, initialize sequence number for DbDesc */
2063 if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
2064 && (on->dbdesc_seqnum == 0)) {
2065 on->dbdesc_seqnum = monotime(NULL);
2066 }
2067
2068 /* reserved */
2069 stream_putc(s, 0); /* reserved 1 */
2070 stream_putc(s, on->ospf6_if->area->options[0]);
2071 stream_putc(s, on->ospf6_if->area->options[1]);
2072 stream_putc(s, on->ospf6_if->area->options[2]);
2073 stream_putw(s, on->ospf6_if->ifmtu);
2074 stream_putc(s, 0); /* reserved 2 */
2075 stream_putc(s, on->dbdesc_bits);
2076 stream_putl(s, on->dbdesc_seqnum);
2077
2078 /* if this is not initial one, set LSA headers in dbdesc */
2079 if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)) {
2080 for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) {
2081 ospf6_lsa_age_update_to_send(lsa,
2082 on->ospf6_if->transdelay);
2083
2084 /* MTU check */
2085 if ((length + sizeof(struct ospf6_lsa_header)
2086 + OSPF6_HEADER_SIZE)
2087 > ospf6_packet_max(on->ospf6_if)) {
2088 ospf6_lsa_unlock(lsa);
2089 if (lsanext)
2090 ospf6_lsa_unlock(lsanext);
2091 break;
2092 }
2093 stream_put(s, lsa->header,
2094 sizeof(struct ospf6_lsa_header));
2095 length += sizeof(struct ospf6_lsa_header);
2096 }
2097 }
2098 return length;
2099 }
2100
2101 int ospf6_dbdesc_send(struct thread *thread)
2102 {
2103 struct ospf6_neighbor *on;
2104 uint16_t length = OSPF6_HEADER_SIZE;
2105 struct ospf6_packet *op;
2106
2107 on = (struct ospf6_neighbor *)THREAD_ARG(thread);
2108 on->thread_send_dbdesc = (struct thread *)NULL;
2109
2110 if (on->state < OSPF6_NEIGHBOR_EXSTART) {
2111 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND))
2112 zlog_debug(
2113 "Quit to send DbDesc to neighbor %s state %s",
2114 on->name, ospf6_neighbor_state_str[on->state]);
2115 return 0;
2116 }
2117
2118 /* set next thread if master */
2119 if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
2120 thread_add_timer(master, ospf6_dbdesc_send, on,
2121 on->ospf6_if->rxmt_interval,
2122 &on->thread_send_dbdesc);
2123
2124 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2125 ospf6_make_header(OSPF6_MESSAGE_TYPE_DBDESC, on->ospf6_if, op->s);
2126
2127 length += ospf6_make_dbdesc(on, op->s);
2128 ospf6_fill_header(on->ospf6_if, op->s, length);
2129
2130 /* Set packet length. */
2131 op->length = length;
2132
2133 if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
2134 op->dst = allspfrouters6;
2135 else
2136 op->dst = on->linklocal_addr;
2137
2138 ospf6_packet_add(on->ospf6_if, op);
2139
2140 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2141
2142 return 0;
2143 }
2144
2145 int ospf6_dbdesc_send_newone(struct thread *thread)
2146 {
2147 struct ospf6_neighbor *on;
2148 struct ospf6_lsa *lsa, *lsanext;
2149 unsigned int size = 0;
2150
2151 on = (struct ospf6_neighbor *)THREAD_ARG(thread);
2152 ospf6_lsdb_remove_all(on->dbdesc_list);
2153
2154 /* move LSAs from summary_list to dbdesc_list (within neighbor
2155 structure)
2156 so that ospf6_send_dbdesc () can send those LSAs */
2157 size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
2158 for (ALL_LSDB(on->summary_list, lsa, lsanext)) {
2159 /* if stub area then don't advertise AS-External LSAs */
2160 if ((IS_AREA_STUB(on->ospf6_if->area)
2161 || IS_AREA_NSSA(on->ospf6_if->area))
2162 && ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
2163 ospf6_lsdb_remove(lsa, on->summary_list);
2164 continue;
2165 }
2166
2167 if (size + sizeof(struct ospf6_lsa_header)
2168 > ospf6_packet_max(on->ospf6_if)) {
2169 ospf6_lsa_unlock(lsa);
2170 if (lsanext)
2171 ospf6_lsa_unlock(lsanext);
2172 break;
2173 }
2174
2175 ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->dbdesc_list);
2176 ospf6_lsdb_remove(lsa, on->summary_list);
2177 size += sizeof(struct ospf6_lsa_header);
2178 }
2179
2180 if (on->summary_list->count == 0)
2181 UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
2182
2183 /* If slave, More bit check must be done here */
2184 if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */
2185 !CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT)
2186 && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
2187 thread_add_event(master, exchange_done, on, 0, NULL);
2188
2189 thread_execute(master, ospf6_dbdesc_send, on, 0);
2190 return 0;
2191 }
2192
2193 static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
2194 {
2195 uint16_t length = 0;
2196 struct ospf6_lsa *lsa, *lsanext, *last_req = NULL;
2197
2198 for (ALL_LSDB(on->request_list, lsa, lsanext)) {
2199 if ((length + OSPF6_HEADER_SIZE)
2200 > ospf6_packet_max(on->ospf6_if)) {
2201 ospf6_lsa_unlock(lsa);
2202 if (lsanext)
2203 ospf6_lsa_unlock(lsanext);
2204 break;
2205 }
2206 stream_putw(s, 0); /* reserved */
2207 stream_putw(s, ntohs(lsa->header->type));
2208 stream_putl(s, ntohl(lsa->header->id));
2209 stream_putl(s, ntohl(lsa->header->adv_router));
2210 length += sizeof(struct ospf6_lsreq_entry);
2211 last_req = lsa;
2212 }
2213
2214 if (last_req != NULL) {
2215 if (on->last_ls_req != NULL)
2216 on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
2217
2218 ospf6_lsa_lock(last_req);
2219 on->last_ls_req = last_req;
2220 }
2221
2222 return length;
2223 }
2224
2225 static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on,
2226 struct ospf6_packet **op)
2227 {
2228 uint16_t length = 0;
2229 struct ospf6_lsa *lsa, *lsanext;
2230 int lsa_cnt = 0;
2231
2232 for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
2233 if ((length + sizeof(struct ospf6_lsa_header)
2234 + OSPF6_HEADER_SIZE)
2235 > ospf6_packet_max(on->ospf6_if)) {
2236 /* if we run out of packet size/space here,
2237 better to try again soon. */
2238 if (lsa_cnt) {
2239 ospf6_fill_header(on->ospf6_if, (*op)->s,
2240 length + OSPF6_HEADER_SIZE);
2241
2242 (*op)->length = length + OSPF6_HEADER_SIZE;
2243 (*op)->dst = on->linklocal_addr;
2244 ospf6_packet_add(on->ospf6_if, *op);
2245 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2246 /* new packet */
2247 *op = ospf6_packet_new(on->ospf6_if->ifmtu);
2248 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK,
2249 on->ospf6_if, (*op)->s);
2250 length = 0;
2251 lsa_cnt = 0;
2252 }
2253 }
2254 ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
2255 stream_put((*op)->s, lsa->header,
2256 sizeof(struct ospf6_lsa_header));
2257 length += sizeof(struct ospf6_lsa_header);
2258
2259 assert(lsa->lock == 2);
2260 ospf6_lsdb_remove(lsa, on->lsack_list);
2261 lsa_cnt++;
2262 }
2263 return length;
2264 }
2265
2266 int ospf6_lsreq_send(struct thread *thread)
2267 {
2268 struct ospf6_neighbor *on;
2269 struct ospf6_packet *op;
2270 uint16_t length = OSPF6_HEADER_SIZE;
2271
2272 on = (struct ospf6_neighbor *)THREAD_ARG(thread);
2273 on->thread_send_lsreq = (struct thread *)NULL;
2274
2275 /* LSReq will be sent only in ExStart or Loading */
2276 if (on->state != OSPF6_NEIGHBOR_EXCHANGE
2277 && on->state != OSPF6_NEIGHBOR_LOADING) {
2278 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSREQ, SEND_HDR))
2279 zlog_debug("Quit to send LSReq to neighbor %s state %s",
2280 on->name,
2281 ospf6_neighbor_state_str[on->state]);
2282 return 0;
2283 }
2284
2285 /* schedule loading_done if request list is empty */
2286 if (on->request_list->count == 0) {
2287 thread_add_event(master, loading_done, on, 0, NULL);
2288 return 0;
2289 }
2290
2291 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2292 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSREQ, on->ospf6_if, op->s);
2293
2294 length += ospf6_make_lsreq(on, op->s);
2295
2296 if (length == OSPF6_HEADER_SIZE) {
2297 /* Hello overshooting MTU */
2298 ospf6_packet_free(op);
2299 return 0;
2300 }
2301
2302 /* Fill OSPF header. */
2303 ospf6_fill_header(on->ospf6_if, op->s, length);
2304
2305 /* Set packet length */
2306 op->length = length;
2307
2308 if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
2309 op->dst = allspfrouters6;
2310 else
2311 op->dst = on->linklocal_addr;
2312
2313 ospf6_packet_add(on->ospf6_if, op);
2314
2315 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2316
2317 /* set next thread */
2318 if (on->request_list->count != 0) {
2319 on->thread_send_lsreq = NULL;
2320 thread_add_timer(master, ospf6_lsreq_send, on,
2321 on->ospf6_if->rxmt_interval,
2322 &on->thread_send_lsreq);
2323 }
2324
2325 return 0;
2326 }
2327
2328 static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
2329 struct ospf6_interface *oi,
2330 struct ospf6_packet *op)
2331 {
2332
2333 if (on) {
2334
2335 if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
2336 || (on->ospf6_if->state == OSPF6_INTERFACE_DR)
2337 || (on->ospf6_if->state == OSPF6_INTERFACE_BDR))
2338 op->dst = allspfrouters6;
2339 else
2340 op->dst = on->linklocal_addr;
2341 oi = on->ospf6_if;
2342 } else if (oi) {
2343 if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
2344 || (oi->state == OSPF6_INTERFACE_DR)
2345 || (oi->state == OSPF6_INTERFACE_BDR))
2346 op->dst = allspfrouters6;
2347 else
2348 op->dst = alldrouters6;
2349 }
2350 if (oi) {
2351 ospf6_packet_add(oi, op);
2352 OSPF6_MESSAGE_WRITE_ON(oi);
2353 }
2354 }
2355
2356 static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on,
2357 struct ospf6_packet **op, int *lsa_cnt)
2358 {
2359 uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
2360 struct ospf6_lsa *lsa, *lsanext;
2361
2362 /* skip over fixed header */
2363 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2364
2365 for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
2366 if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
2367 + OSPF6_HEADER_SIZE)
2368 > ospf6_packet_max(on->ospf6_if)) {
2369 ospf6_fill_header(on->ospf6_if, (*op)->s,
2370 length + OSPF6_HEADER_SIZE);
2371 (*op)->length = length + OSPF6_HEADER_SIZE;
2372 ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
2373 ospf6_send_lsupdate(on, NULL, *op);
2374
2375 /* refresh packet */
2376 *op = ospf6_packet_new(on->ospf6_if->ifmtu);
2377 length = OSPF6_LS_UPD_MIN_SIZE;
2378 *lsa_cnt = 0;
2379 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
2380 on->ospf6_if, (*op)->s);
2381 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2382 }
2383 ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
2384 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
2385 (*lsa_cnt)++;
2386 length += OSPF6_LSA_SIZE(lsa->header);
2387 assert(lsa->lock == 2);
2388 ospf6_lsdb_remove(lsa, on->lsupdate_list);
2389 }
2390 return length;
2391 }
2392
2393 static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on,
2394 struct ospf6_packet **op,
2395 int *lsa_cnt)
2396 {
2397 uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
2398 struct ospf6_lsa *lsa, *lsanext;
2399
2400 /* skip over fixed header */
2401 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2402
2403 for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
2404 if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
2405 + OSPF6_HEADER_SIZE)
2406 > ospf6_packet_max(on->ospf6_if)) {
2407 ospf6_fill_header(on->ospf6_if, (*op)->s,
2408 length + OSPF6_HEADER_SIZE);
2409 (*op)->length = length + OSPF6_HEADER_SIZE;
2410 ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
2411 if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
2412 (*op)->dst = allspfrouters6;
2413 else
2414 (*op)->dst = on->linklocal_addr;
2415
2416 ospf6_packet_add(on->ospf6_if, *op);
2417 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2418
2419 /* refresh packet */
2420 *op = ospf6_packet_new(on->ospf6_if->ifmtu);
2421 length = OSPF6_LS_UPD_MIN_SIZE;
2422 *lsa_cnt = 0;
2423 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
2424 on->ospf6_if, (*op)->s);
2425 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2426 }
2427 ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
2428 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
2429 (*lsa_cnt)++;
2430 length += OSPF6_LSA_SIZE(lsa->header);
2431 }
2432 return length;
2433 }
2434
2435 int ospf6_lsupdate_send_neighbor(struct thread *thread)
2436 {
2437 struct ospf6_neighbor *on;
2438 struct ospf6_packet *op;
2439 uint16_t length = OSPF6_HEADER_SIZE;
2440 int lsa_cnt = 0;
2441
2442 on = (struct ospf6_neighbor *)THREAD_ARG(thread);
2443 on->thread_send_lsupdate = (struct thread *)NULL;
2444
2445 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
2446 zlog_debug("LSUpdate to neighbor %s", on->name);
2447
2448 if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
2449 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
2450 SEND_HDR))
2451 zlog_debug("Quit to send (neighbor state %s)",
2452 ospf6_neighbor_state_str[on->state]);
2453 return 0;
2454 }
2455
2456 /* first do lsupdate_list */
2457 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2458 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
2459 length += ospf6_make_lsupdate_list(on, &op, &lsa_cnt);
2460 if (lsa_cnt) {
2461 /* Fill OSPF header. */
2462 ospf6_fill_header(on->ospf6_if, op->s, length);
2463 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
2464 op->length = length;
2465 ospf6_send_lsupdate(on, NULL, op);
2466
2467 /* prepare new packet */
2468 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2469 length = OSPF6_HEADER_SIZE;
2470 lsa_cnt = 0;
2471 } else {
2472 stream_reset(op->s);
2473 length = OSPF6_HEADER_SIZE;
2474 }
2475
2476 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
2477 /* now do retransmit list */
2478 length += ospf6_make_ls_retrans_list(on, &op, &lsa_cnt);
2479 if (lsa_cnt) {
2480 ospf6_fill_header(on->ospf6_if, op->s, length);
2481 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
2482 op->length = length;
2483 if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
2484 op->dst = allspfrouters6;
2485 else
2486 op->dst = on->linklocal_addr;
2487 ospf6_packet_add(on->ospf6_if, op);
2488 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2489 } else
2490 ospf6_packet_free(op);
2491
2492 if (on->lsupdate_list->count != 0) {
2493 on->thread_send_lsupdate = NULL;
2494 thread_add_event(master, ospf6_lsupdate_send_neighbor, on, 0,
2495 &on->thread_send_lsupdate);
2496 } else if (on->retrans_list->count != 0) {
2497 on->thread_send_lsupdate = NULL;
2498 thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
2499 on->ospf6_if->rxmt_interval,
2500 &on->thread_send_lsupdate);
2501 }
2502 return 0;
2503 }
2504
2505 int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
2506 struct ospf6_lsa *lsa)
2507 {
2508 struct ospf6_packet *op;
2509 uint16_t length = OSPF6_HEADER_SIZE;
2510
2511 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2512 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
2513
2514 /* skip over fixed header */
2515 stream_forward_endp(op->s, OSPF6_LS_UPD_MIN_SIZE);
2516 ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
2517 stream_put(op->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
2518 length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE
2519 + OSPF6_LSA_SIZE(lsa->header);
2520 ospf6_fill_header(on->ospf6_if, op->s, length);
2521 ospf6_fill_lsupdate_header(op->s, 1);
2522 op->length = length;
2523
2524 if (IS_OSPF6_DEBUG_FLOODING
2525 || IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
2526 zlog_debug("%s: Send lsupdate with lsa %s (age %u)", __func__,
2527 lsa->name, ntohs(lsa->header->age));
2528
2529 ospf6_send_lsupdate(on, NULL, op);
2530
2531 return 0;
2532 }
2533
2534 static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi,
2535 struct ospf6_packet **op,
2536 int *lsa_cnt)
2537 {
2538 uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
2539 struct ospf6_lsa *lsa, *lsanext;
2540
2541 /* skip over fixed header */
2542 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2543
2544 for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
2545 if (length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
2546 + OSPF6_HEADER_SIZE
2547 > ospf6_packet_max(oi)) {
2548 ospf6_fill_header(oi, (*op)->s,
2549 length + OSPF6_HEADER_SIZE);
2550 (*op)->length = length + OSPF6_HEADER_SIZE;
2551 ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
2552 ospf6_send_lsupdate(NULL, oi, *op);
2553
2554 /* refresh packet */
2555 *op = ospf6_packet_new(oi->ifmtu);
2556 length = OSPF6_LS_UPD_MIN_SIZE;
2557 *lsa_cnt = 0;
2558 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi,
2559 (*op)->s);
2560 stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
2561 }
2562
2563 ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
2564 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
2565 (*lsa_cnt)++;
2566 length += OSPF6_LSA_SIZE(lsa->header);
2567
2568 assert(lsa->lock == 2);
2569 ospf6_lsdb_remove(lsa, oi->lsupdate_list);
2570 }
2571 return length;
2572 }
2573
2574 int ospf6_lsupdate_send_interface(struct thread *thread)
2575 {
2576 struct ospf6_interface *oi;
2577 struct ospf6_packet *op;
2578 uint16_t length = OSPF6_HEADER_SIZE;
2579 int lsa_cnt = 0;
2580
2581 oi = (struct ospf6_interface *)THREAD_ARG(thread);
2582 oi->thread_send_lsupdate = (struct thread *)NULL;
2583
2584 if (oi->state <= OSPF6_INTERFACE_WAITING) {
2585 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
2586 SEND_HDR))
2587 zlog_debug(
2588 "Quit to send LSUpdate to interface %s state %s",
2589 oi->interface->name,
2590 ospf6_interface_state_str[oi->state]);
2591 return 0;
2592 }
2593
2594 /* if we have nothing to send, return */
2595 if (oi->lsupdate_list->count == 0)
2596 return 0;
2597
2598 op = ospf6_packet_new(oi->ifmtu);
2599 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi, op->s);
2600 length += ospf6_make_lsupdate_interface(oi, &op, &lsa_cnt);
2601 if (lsa_cnt) {
2602 /* Fill OSPF header. */
2603 ospf6_fill_header(oi, op->s, length);
2604 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
2605 op->length = length;
2606 ospf6_send_lsupdate(NULL, oi, op);
2607 } else
2608 ospf6_packet_free(op);
2609
2610 if (oi->lsupdate_list->count > 0) {
2611 oi->thread_send_lsupdate = NULL;
2612 thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0,
2613 &oi->thread_send_lsupdate);
2614 }
2615
2616 return 0;
2617 }
2618
2619 int ospf6_lsack_send_neighbor(struct thread *thread)
2620 {
2621 struct ospf6_neighbor *on;
2622 struct ospf6_packet *op;
2623 uint16_t length = OSPF6_HEADER_SIZE;
2624
2625 on = (struct ospf6_neighbor *)THREAD_ARG(thread);
2626 on->thread_send_lsack = (struct thread *)NULL;
2627
2628 if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
2629 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
2630 zlog_debug("Quit to send LSAck to neighbor %s state %s",
2631 on->name,
2632 ospf6_neighbor_state_str[on->state]);
2633 return 0;
2634 }
2635
2636 /* if we have nothing to send, return */
2637 if (on->lsack_list->count == 0)
2638 return 0;
2639
2640 op = ospf6_packet_new(on->ospf6_if->ifmtu);
2641 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s);
2642
2643 length += ospf6_make_lsack_neighbor(on, &op);
2644
2645 if (length == OSPF6_HEADER_SIZE) {
2646 ospf6_packet_free(op);
2647 return 0;
2648 }
2649
2650 /* Fill OSPF header. */
2651 ospf6_fill_header(on->ospf6_if, op->s, length);
2652
2653 /* Set packet length, dst and queue to FIFO. */
2654 op->length = length;
2655 op->dst = on->linklocal_addr;
2656 ospf6_packet_add(on->ospf6_if, op);
2657 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
2658
2659 if (on->lsack_list->count > 0)
2660 thread_add_event(master, ospf6_lsack_send_neighbor, on, 0,
2661 &on->thread_send_lsack);
2662
2663 return 0;
2664 }
2665
2666 static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi,
2667 struct ospf6_packet *op)
2668 {
2669 uint16_t length = 0;
2670 struct ospf6_lsa *lsa, *lsanext;
2671
2672 for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
2673 if ((length + sizeof(struct ospf6_lsa_header)
2674 + OSPF6_HEADER_SIZE)
2675 > ospf6_packet_max(oi)) {
2676 /* if we run out of packet size/space here,
2677 better to try again soon. */
2678 THREAD_OFF(oi->thread_send_lsack);
2679 thread_add_event(master, ospf6_lsack_send_interface, oi,
2680 0, &oi->thread_send_lsack);
2681
2682 ospf6_lsa_unlock(lsa);
2683 if (lsanext)
2684 ospf6_lsa_unlock(lsanext);
2685 break;
2686 }
2687 ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
2688 stream_put(op->s, lsa->header, sizeof(struct ospf6_lsa_header));
2689 length += sizeof(struct ospf6_lsa_header);
2690
2691 assert(lsa->lock == 2);
2692 ospf6_lsdb_remove(lsa, oi->lsack_list);
2693 }
2694 return length;
2695 }
2696
2697 int ospf6_lsack_send_interface(struct thread *thread)
2698 {
2699 struct ospf6_interface *oi;
2700 struct ospf6_packet *op;
2701 uint16_t length = OSPF6_HEADER_SIZE;
2702
2703 oi = (struct ospf6_interface *)THREAD_ARG(thread);
2704 oi->thread_send_lsack = (struct thread *)NULL;
2705
2706 if (oi->state <= OSPF6_INTERFACE_WAITING) {
2707 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
2708 zlog_debug(
2709 "Quit to send LSAck to interface %s state %s",
2710 oi->interface->name,
2711 ospf6_interface_state_str[oi->state]);
2712 return 0;
2713 }
2714
2715 /* if we have nothing to send, return */
2716 if (oi->lsack_list->count == 0)
2717 return 0;
2718
2719 op = ospf6_packet_new(oi->ifmtu);
2720 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s);
2721
2722 length += ospf6_make_lsack_interface(oi, op);
2723
2724 if (length == OSPF6_HEADER_SIZE) {
2725 ospf6_packet_free(op);
2726 return 0;
2727 }
2728 /* Fill OSPF header. */
2729 ospf6_fill_header(oi, op->s, length);
2730
2731 /* Set packet length, dst and queue to FIFO. */
2732 op->length = length;
2733 if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
2734 || (oi->state == OSPF6_INTERFACE_DR)
2735 || (oi->state == OSPF6_INTERFACE_BDR))
2736 op->dst = allspfrouters6;
2737 else
2738 op->dst = alldrouters6;
2739
2740 ospf6_packet_add(oi, op);
2741 OSPF6_MESSAGE_WRITE_ON(oi);
2742
2743 if (oi->lsack_list->count > 0)
2744 thread_add_event(master, ospf6_lsack_send_interface, oi, 0,
2745 &oi->thread_send_lsack);
2746
2747 return 0;
2748 }
2749
2750 /* Commands */
2751 DEFUN(debug_ospf6_message, debug_ospf6_message_cmd,
2752 "debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
2753 DEBUG_STR OSPF6_STR
2754 "Debug OSPFv3 message\n"
2755 "Debug Unknown message\n"
2756 "Debug Hello message\n"
2757 "Debug Database Description message\n"
2758 "Debug Link State Request message\n"
2759 "Debug Link State Update message\n"
2760 "Debug Link State Acknowledgement message\n"
2761 "Debug All message\n"
2762 "Debug only sending message, entire packet\n"
2763 "Debug only receiving message, entire packet\n"
2764 "Debug only sending message, header only\n"
2765 "Debug only receiving message, header only\n")
2766 {
2767 int idx_packet = 3;
2768 int idx_send_recv = 4;
2769 unsigned char level = 0;
2770 int type = 0;
2771 int i;
2772
2773 /* check type */
2774 if (!strncmp(argv[idx_packet]->arg, "u", 1))
2775 type = OSPF6_MESSAGE_TYPE_UNKNOWN;
2776 else if (!strncmp(argv[idx_packet]->arg, "h", 1))
2777 type = OSPF6_MESSAGE_TYPE_HELLO;
2778 else if (!strncmp(argv[idx_packet]->arg, "d", 1))
2779 type = OSPF6_MESSAGE_TYPE_DBDESC;
2780 else if (!strncmp(argv[idx_packet]->arg, "lsr", 3))
2781 type = OSPF6_MESSAGE_TYPE_LSREQ;
2782 else if (!strncmp(argv[idx_packet]->arg, "lsu", 3))
2783 type = OSPF6_MESSAGE_TYPE_LSUPDATE;
2784 else if (!strncmp(argv[idx_packet]->arg, "lsa", 3))
2785 type = OSPF6_MESSAGE_TYPE_LSACK;
2786 else if (!strncmp(argv[idx_packet]->arg, "a", 1))
2787 type = OSPF6_MESSAGE_TYPE_ALL;
2788
2789 if (argc == 4)
2790 level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
2791 else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
2792 level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
2793 else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
2794 level = OSPF6_DEBUG_MESSAGE_SEND;
2795 else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
2796 level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
2797 else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
2798 level = OSPF6_DEBUG_MESSAGE_RECV;
2799
2800 if (type == OSPF6_MESSAGE_TYPE_ALL) {
2801 for (i = 0; i < 6; i++)
2802 OSPF6_DEBUG_MESSAGE_ON(i, level);
2803 } else
2804 OSPF6_DEBUG_MESSAGE_ON(type, level);
2805
2806 return CMD_SUCCESS;
2807 }
2808
2809 DEFUN(no_debug_ospf6_message, no_debug_ospf6_message_cmd,
2810 "no debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
2811 NO_STR DEBUG_STR OSPF6_STR
2812 "Debug OSPFv3 message\n"
2813 "Debug Unknown message\n"
2814 "Debug Hello message\n"
2815 "Debug Database Description message\n"
2816 "Debug Link State Request message\n"
2817 "Debug Link State Update message\n"
2818 "Debug Link State Acknowledgement message\n"
2819 "Debug All message\n"
2820 "Debug only sending message, entire pkt\n"
2821 "Debug only receiving message, entire pkt\n"
2822 "Debug only sending message, header only\n"
2823 "Debug only receiving message, header only\n")
2824 {
2825 int idx_packet = 4;
2826 int idx_send_recv = 5;
2827 unsigned char level = 0;
2828 int type = 0;
2829 int i;
2830
2831 /* check type */
2832 if (!strncmp(argv[idx_packet]->arg, "u", 1))
2833 type = OSPF6_MESSAGE_TYPE_UNKNOWN;
2834 else if (!strncmp(argv[idx_packet]->arg, "h", 1))
2835 type = OSPF6_MESSAGE_TYPE_HELLO;
2836 else if (!strncmp(argv[idx_packet]->arg, "d", 1))
2837 type = OSPF6_MESSAGE_TYPE_DBDESC;
2838 else if (!strncmp(argv[idx_packet]->arg, "lsr", 3))
2839 type = OSPF6_MESSAGE_TYPE_LSREQ;
2840 else if (!strncmp(argv[idx_packet]->arg, "lsu", 3))
2841 type = OSPF6_MESSAGE_TYPE_LSUPDATE;
2842 else if (!strncmp(argv[idx_packet]->arg, "lsa", 3))
2843 type = OSPF6_MESSAGE_TYPE_LSACK;
2844 else if (!strncmp(argv[idx_packet]->arg, "a", 1))
2845 type = OSPF6_MESSAGE_TYPE_ALL;
2846
2847 if (argc == 5)
2848 level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV
2849 | OSPF6_DEBUG_MESSAGE_SEND_HDR
2850 | OSPF6_DEBUG_MESSAGE_RECV_HDR;
2851 else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
2852 level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
2853 else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
2854 level = OSPF6_DEBUG_MESSAGE_SEND;
2855 else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
2856 level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
2857 else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
2858 level = OSPF6_DEBUG_MESSAGE_RECV;
2859
2860 if (type == OSPF6_MESSAGE_TYPE_ALL) {
2861 for (i = 0; i < 6; i++)
2862 OSPF6_DEBUG_MESSAGE_OFF(i, level);
2863 } else
2864 OSPF6_DEBUG_MESSAGE_OFF(type, level);
2865
2866 return CMD_SUCCESS;
2867 }
2868
2869
2870 int config_write_ospf6_debug_message(struct vty *vty)
2871 {
2872 const char *type_str[] = {"unknown", "hello", "dbdesc",
2873 "lsreq", "lsupdate", "lsack"};
2874 unsigned char s = 0, r = 0, sh = 0, rh = 0;
2875 int i;
2876
2877 for (i = 0; i < 6; i++) {
2878 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
2879 s |= 1 << i;
2880 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
2881 r |= 1 << i;
2882 }
2883
2884 for (i = 0; i < 6; i++) {
2885 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
2886 sh |= 1 << i;
2887 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
2888 rh |= 1 << i;
2889 }
2890
2891 if (s == 0x3f && r == 0x3f) {
2892 vty_out(vty, "debug ospf6 message all\n");
2893 return 0;
2894 }
2895
2896 if (s == 0x3f && r == 0) {
2897 vty_out(vty, "debug ospf6 message all send\n");
2898 return 0;
2899 } else if (s == 0 && r == 0x3f) {
2900 vty_out(vty, "debug ospf6 message all recv\n");
2901 return 0;
2902 }
2903
2904 if (sh == 0x3f && rh == 0) {
2905 vty_out(vty, "debug ospf6 message all send-hdr\n");
2906 return 0;
2907 } else if (sh == 0 && rh == 0x3f) {
2908 vty_out(vty, "debug ospf6 message all recv-hdr\n");
2909 return 0;
2910 }
2911
2912 /* Unknown message is logged by default */
2913 if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)
2914 && !IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
2915 vty_out(vty, "no debug ospf6 message unknown\n");
2916 else if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, SEND))
2917 vty_out(vty, "no debug ospf6 message unknown send\n");
2918 else if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
2919 vty_out(vty, "no debug ospf6 message unknown recv\n");
2920
2921 for (i = 1; i < 6; i++) {
2922 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND)
2923 && IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV)) {
2924 vty_out(vty, "debug ospf6 message %s\n", type_str[i]);
2925 continue;
2926 }
2927
2928 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
2929 vty_out(vty, "debug ospf6 message %s send\n",
2930 type_str[i]);
2931 else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
2932 vty_out(vty, "debug ospf6 message %s send-hdr\n",
2933 type_str[i]);
2934
2935 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
2936 vty_out(vty, "debug ospf6 message %s recv\n",
2937 type_str[i]);
2938 else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
2939 vty_out(vty, "debug ospf6 message %s recv-hdr\n",
2940 type_str[i]);
2941 }
2942
2943 return 0;
2944 }
2945
2946 void install_element_ospf6_debug_message(void)
2947 {
2948 install_element(ENABLE_NODE, &debug_ospf6_message_cmd);
2949 install_element(ENABLE_NODE, &no_debug_ospf6_message_cmd);
2950 install_element(CONFIG_NODE, &debug_ospf6_message_cmd);
2951 install_element(CONFIG_NODE, &no_debug_ospf6_message_cmd);
2952 }