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