Annotation of embedaddon/bird/proto/ospf/dbdes.c, revision 1.1.1.1
1.1 misho 1: /*
2: * BIRD -- OSPF
3: *
4: * (c) 1999--2004 Ondrej Filip <feela@network.cz>
5: * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
6: * (c) 2009--2014 CZ.NIC z.s.p.o.
7: *
8: * Can be freely distributed and used under the terms of the GNU GPL.
9: */
10:
11: #include "ospf.h"
12:
13:
14: struct ospf_dbdes2_packet
15: {
16: struct ospf_packet hdr;
17: union ospf_auth auth;
18:
19: u16 iface_mtu;
20: u8 options;
21: u8 imms; /* I, M, MS bits */
22: u32 ddseq;
23:
24: struct ospf_lsa_header lsas[];
25: };
26:
27: struct ospf_dbdes3_packet
28: {
29: struct ospf_packet hdr;
30:
31: u32 options;
32: u16 iface_mtu;
33: u8 padding;
34: u8 imms; /* I, M, MS bits */
35: u32 ddseq;
36:
37: struct ospf_lsa_header lsas[];
38: };
39:
40:
41: static inline uint
42: ospf_dbdes_hdrlen(struct ospf_proto *p UNUSED4 UNUSED6)
43: {
44: return ospf_is_v2(p) ?
45: sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
46: }
47:
48:
49: static void
50: ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
51: struct ospf_lsa_header **body, uint *count)
52: {
53: uint plen = ntohs(pkt->length);
54: uint hlen = ospf_dbdes_hdrlen(p);
55:
56: *body = ((void *) pkt) + hlen;
57: *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
58: }
59:
60: static void
61: ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
62: {
63: struct ospf_lsa_header *lsas;
64: uint i, lsa_count;
65: u32 pkt_ddseq;
66: u16 pkt_iface_mtu;
67: u8 pkt_imms;
68:
69: ASSERT(pkt->type == DBDES_P);
70: ospf_dump_common(p, pkt);
71:
72: if (ospf_is_v2(p))
73: {
74: struct ospf_dbdes2_packet *ps = (void *) pkt;
75: pkt_iface_mtu = ntohs(ps->iface_mtu);
76: pkt_imms = ps->imms;
77: pkt_ddseq = ntohl(ps->ddseq);
78: }
79: else /* OSPFv3 */
80: {
81: struct ospf_dbdes3_packet *ps = (void *) pkt;
82: pkt_iface_mtu = ntohs(ps->iface_mtu);
83: pkt_imms = ps->imms;
84: pkt_ddseq = ntohl(ps->ddseq);
85: }
86:
87: log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
88: log(L_TRACE "%s: imms %s%s%s", p->p.name,
89: (pkt_imms & DBDES_I) ? "I " : "",
90: (pkt_imms & DBDES_M) ? "M " : "",
91: (pkt_imms & DBDES_MS) ? "MS" : "");
92: log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
93:
94: ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
95: for (i = 0; i < lsa_count; i++)
96: ospf_dump_lsahdr(p, lsas + i);
97: }
98:
99:
100: static void
101: ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
102: {
103: struct ospf_iface *ifa = n->ifa;
104: struct ospf_packet *pkt;
105: uint length;
106:
107: u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
108:
109: /* Update DBDES buffer */
110: if (n->ldd_bsize != ifa->tx_length)
111: {
112: mb_free(n->ldd_buffer);
113: n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
114: n->ldd_bsize = ifa->tx_length;
115: }
116:
117: pkt = n->ldd_buffer;
118: ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
119:
120: if (ospf_is_v2(p))
121: {
122: struct ospf_dbdes2_packet *ps = (void *) pkt;
123: ps->iface_mtu = htons(iface_mtu);
124: ps->options = ifa->oa->options;
125: ps->imms = 0; /* Will be set later */
126: ps->ddseq = htonl(n->dds);
127: length = sizeof(struct ospf_dbdes2_packet);
128: }
129: else /* OSPFv3 */
130: {
131: struct ospf_dbdes3_packet *ps = (void *) pkt;
132: ps->options = htonl(ifa->oa->options);
133: ps->iface_mtu = htons(iface_mtu);
134: ps->padding = 0;
135: ps->imms = 0; /* Will be set later */
136: ps->ddseq = htonl(n->dds);
137: length = sizeof(struct ospf_dbdes3_packet);
138: }
139:
140: /* Prepare DBDES body */
141: if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
142: {
143: struct ospf_lsa_header *lsas;
144: struct top_hash_entry *en;
145: uint i = 0, lsa_max;
146:
147: ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
148: en = (void *) s_get(&(n->dbsi));
149:
150: while (i < lsa_max)
151: {
152: if (!SNODE_VALID(en))
153: {
154: n->myimms &= ~DBDES_M; /* Unset More bit */
155: break;
156: }
157:
158: if ((en->lsa.age < LSA_MAXAGE) &&
159: lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
160: {
161: lsa_hton_hdr(&(en->lsa), lsas + i);
162: i++;
163: }
164:
165: en = SNODE_NEXT(en);
166: }
167:
168: s_put(&(n->dbsi), SNODE en);
169:
170: length += i * sizeof(struct ospf_lsa_header);
171: }
172:
173: if (ospf_is_v2(p))
174: ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
175: else
176: ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
177:
178: pkt->length = htons(length);
179: }
180:
181: static void
182: ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
183: {
184: struct ospf_iface *ifa = n->ifa;
185:
186: OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
187: "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
188: sk_set_tbuf(ifa->sk, n->ldd_buffer);
189: ospf_send_to(ifa, n->ip);
190: sk_set_tbuf(ifa->sk, NULL);
191: }
192:
193: /**
194: * ospf_send_dbdes - transmit database description packet
195: * @p: OSPF protocol instance
196: * @n: neighbor
197: *
198: * Sending of a database description packet is described in 10.8 of RFC 2328.
199: * Reception of each packet is acknowledged in the sequence number of another.
200: * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
201: * does not reply, I don't create a new packet but just send the content
202: * of the buffer.
203: */
204: void
205: ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
206: {
207: /* RFC 2328 10.8 */
208:
209: ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
210:
211: if (n->ifa->oa->rt == NULL)
212: return;
213:
214: ospf_prepare_dbdes(p, n);
215: ospf_do_send_dbdes(p, n);
216: }
217:
218: void
219: ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
220: {
221: ASSERT(n->state > NEIGHBOR_EXSTART);
222:
223: if (!n->ldd_buffer)
224: {
225: log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
226: ospf_neigh_sm(n, INM_SEQMIS);
227: return;
228: }
229:
230: /* Send last packet */
231: ospf_do_send_dbdes(p, n);
232: }
233:
234: static int
235: ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
236: {
237: struct ospf_iface *ifa = n->ifa;
238: struct ospf_lsa_header *lsas, lsa;
239: struct top_hash_entry *en, *req;
240: const char *err_dsc = NULL;
241: u32 lsa_type, lsa_domain;
242: uint i, lsa_count;
243:
244: ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
245:
246: for (i = 0; i < lsa_count; i++)
247: {
248: lsa_ntoh_hdr(lsas + i, &lsa);
249: lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
250:
251: /* RFC 2328 10.6 and RFC 5340 4.2.2 */
252:
253: if (!lsa_type)
254: DROP1("LSA of unknown type");
255:
256: if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
257: DROP1("LSA with AS scope in stub area");
258:
259: /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
260: if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
261: DROP1("rt-summary-LSA in stub area");
262:
263: /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
264: if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
265: DROP1("LSA with invalid scope");
266:
267: en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
268: if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
269: {
270: /* This should be splitted to ospf_lsa_lsrq_up() */
271: req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
272:
273: if (!SNODE_VALID(req))
274: s_add_tail(&n->lsrql, SNODE req);
275:
276: if (!SNODE_VALID(n->lsrqi))
277: n->lsrqi = req;
278:
279: req->lsa = lsa;
280: req->lsa_body = LSA_BODY_DUMMY;
281:
282: if (!tm_active(n->lsrq_timer))
283: tm_start(n->lsrq_timer, 0);
284: }
285: }
286:
287: return 0;
288:
289: drop:
290: LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
291: LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
292:
293: ospf_neigh_sm(n, INM_SEQMIS);
294: return -1;
295: }
296:
297: void
298: ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
299: struct ospf_neighbor *n)
300: {
301: struct ospf_proto *p = ifa->oa->po;
302: const char *err_dsc = NULL;
303: u32 rcv_ddseq, rcv_options;
304: u16 rcv_iface_mtu;
305: u8 rcv_imms;
306: uint plen, err_val = 0;
307:
308: /* RFC 2328 10.6 */
309:
310: plen = ntohs(pkt->length);
311: if (plen < ospf_dbdes_hdrlen(p))
312: {
313: LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
314: return;
315: }
316:
317: OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
318:
319: ospf_neigh_sm(n, INM_HELLOREC);
320:
321: if (ospf_is_v2(p))
322: {
323: struct ospf_dbdes2_packet *ps = (void *) pkt;
324: rcv_iface_mtu = ntohs(ps->iface_mtu);
325: rcv_options = ps->options;
326: rcv_imms = ps->imms;
327: rcv_ddseq = ntohl(ps->ddseq);
328: }
329: else /* OSPFv3 */
330: {
331: struct ospf_dbdes3_packet *ps = (void *) pkt;
332: rcv_options = ntohl(ps->options);
333: rcv_iface_mtu = ntohs(ps->iface_mtu);
334: rcv_imms = ps->imms;
335: rcv_ddseq = ntohl(ps->ddseq);
336: }
337:
338: switch (n->state)
339: {
340: case NEIGHBOR_DOWN:
341: case NEIGHBOR_ATTEMPT:
342: case NEIGHBOR_2WAY:
343: OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
344: return;
345:
346: case NEIGHBOR_INIT:
347: ospf_neigh_sm(n, INM_2WAYREC);
348: if (n->state != NEIGHBOR_EXSTART)
349: return;
350:
351: case NEIGHBOR_EXSTART:
352: if ((ifa->type != OSPF_IT_VLINK) &&
353: (rcv_iface_mtu != ifa->iface->mtu) &&
354: (rcv_iface_mtu != 0) &&
355: (ifa->iface->mtu != 0))
356: LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
357: n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
358:
359: if ((rcv_imms == DBDES_IMMS) &&
360: (n->rid > p->router_id) &&
361: (plen == ospf_dbdes_hdrlen(p)))
362: {
363: /* I'm slave! */
364: n->dds = rcv_ddseq;
365: n->ddr = rcv_ddseq;
366: n->options = rcv_options;
367: n->myimms &= ~DBDES_MS;
368: n->imms = rcv_imms;
369: tm_stop(n->dbdes_timer);
370: ospf_neigh_sm(n, INM_NEGDONE);
371: ospf_send_dbdes(p, n);
372: break;
373: }
374:
375: if (!(rcv_imms & DBDES_I) &&
376: !(rcv_imms & DBDES_MS) &&
377: (n->rid < p->router_id) &&
378: (n->dds == rcv_ddseq))
379: {
380: /* I'm master! */
381: n->options = rcv_options;
382: n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
383: n->imms = rcv_imms;
384: ospf_neigh_sm(n, INM_NEGDONE);
385: /* Continue to the NEIGHBOR_EXCHANGE case */
386: }
387: else
388: {
389: DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
390: break;
391: }
392:
393: case NEIGHBOR_EXCHANGE:
394: if ((rcv_imms == n->imms) &&
395: (rcv_options == n->options) &&
396: (rcv_ddseq == n->ddr))
397: goto duplicate;
398:
399: if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
400: DROP("MS-bit mismatch", rcv_imms);
401:
402: if (rcv_imms & DBDES_I)
403: DROP("I-bit mismatch", rcv_imms);
404:
405: if (rcv_options != n->options)
406: DROP("options mismatch", rcv_options);
407:
408: n->ddr = rcv_ddseq;
409: n->imms = rcv_imms;
410:
411: if (n->myimms & DBDES_MS)
412: {
413: /* MASTER */
414:
415: if (rcv_ddseq != n->dds)
416: DROP("DD sequence number mismatch", rcv_ddseq);
417:
418: n->dds++;
419:
420: if (ospf_process_dbdes(p, pkt, n) < 0)
421: return;
422:
423: if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
424: {
425: tm_stop(n->dbdes_timer);
426: ospf_neigh_sm(n, INM_EXDONE);
427: break;
428: }
429:
430: ospf_send_dbdes(p, n);
431: tm_start(n->dbdes_timer, n->ifa->rxmtint);
432: }
433: else
434: {
435: /* SLAVE */
436:
437: if (rcv_ddseq != (n->dds + 1))
438: DROP("DD sequence number mismatch", rcv_ddseq);
439:
440: n->ddr = rcv_ddseq;
441: n->dds = rcv_ddseq;
442:
443: if (ospf_process_dbdes(p, pkt, n) < 0)
444: return;
445:
446: ospf_send_dbdes(p, n);
447:
448: if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
449: ospf_neigh_sm(n, INM_EXDONE);
450: }
451: break;
452:
453: case NEIGHBOR_LOADING:
454: case NEIGHBOR_FULL:
455: if ((rcv_imms == n->imms) &&
456: (rcv_options == n->options) &&
457: (rcv_ddseq == n->ddr))
458: goto duplicate;
459:
460: DROP("too late for DD exchange", n->state);
461:
462: default:
463: bug("Undefined interface state");
464: }
465: return;
466:
467: duplicate:
468: OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
469:
470: /* Slave should retransmit DBDES packet */
471: if (!(n->myimms & DBDES_MS))
472: ospf_rxmt_dbdes(p, n);
473: return;
474:
475: drop:
476: LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
477: n->rid, ifa->ifname, err_dsc, err_val);
478:
479: ospf_neigh_sm(n, INM_SEQMIS);
480: return;
481: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>