dbdes.c 11.2 KB
Newer Older
1 2 3
/*
 *	BIRD -- OSPF
 *
Ondřej Filip's avatar
Ondřej Filip committed
4
 *	(c) 1999--2004 Ondrej Filip <feela@network.cz>
5 6
 *	(c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2009--2014 CZ.NIC z.s.p.o.
7 8 9 10 11 12
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

13

14
struct ospf_dbdes2_packet
15
{
16 17 18
  struct ospf_packet hdr;
  union ospf_auth auth;

19 20
  u16 iface_mtu;
  u8 options;
21
  u8 imms;			/* I, M, MS bits */
22 23
  u32 ddseq;

24 25
  struct ospf_lsa_header lsas[];
};
26

27
struct ospf_dbdes3_packet
28
{
29 30
  struct ospf_packet hdr;

31 32 33
  u32 options;
  u16 iface_mtu;
  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 45 46 47 48 49 50 51 52 53 54 55 56 57 58
{
  return ospf_is_v2(p) ?
    sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
}


static void
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
		struct ospf_lsa_header **body, uint *count)
{
  uint plen = ntohs(pkt->length);
  uint hlen = ospf_dbdes_hdrlen(p);

  *body = ((void *) pkt) + hlen;
  *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
}
59

60 61
static void
ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
62
{
63 64 65 66 67
  struct ospf_lsa_header *lsas;
  uint i, lsa_count;
  u32 pkt_ddseq;
  u16 pkt_iface_mtu;
  u8 pkt_imms;
68

69 70
  ASSERT(pkt->type == DBDES_P);
  ospf_dump_common(p, pkt);
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85
  if (ospf_is_v2(p))
  {
    struct ospf_dbdes2_packet *ps = (void *) pkt;
    pkt_iface_mtu = ntohs(ps->iface_mtu);
    pkt_imms = ps->imms;
    pkt_ddseq = ntohl(ps->ddseq);
  }
  else /* OSPFv3 */
  {
    struct ospf_dbdes3_packet *ps = (void *) pkt;
    pkt_iface_mtu = ntohs(ps->iface_mtu);
    pkt_imms = ps->imms;
    pkt_ddseq = ntohl(ps->ddseq);
  }
86

87 88 89 90 91 92
  log(L_TRACE "%s:     mtu      %u", p->p.name, pkt_iface_mtu);
  log(L_TRACE "%s:     imms     %s%s%s", p->p.name,
      (pkt_imms & DBDES_I) ? "I " : "",
      (pkt_imms & DBDES_M) ? "M " : "",
      (pkt_imms & DBDES_MS) ? "MS" : "");
  log(L_TRACE "%s:     ddseq    %u", p->p.name, pkt_ddseq);
93

94 95 96
  ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
  for (i = 0; i < lsa_count; i++)
    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 104 105 106 107 108
{
  struct ospf_iface *ifa = n->ifa;
  struct ospf_packet *pkt;
  uint length;

  u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;

109
  /* Update DBDES buffer */
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  if (n->ldd_bsize != ifa->tx_length)
  {
    mb_free(n->ldd_buffer);
    n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
    n->ldd_bsize = ifa->tx_length;
  }

  pkt = n->ldd_buffer;
  ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);

  if (ospf_is_v2(p))
  {
    struct ospf_dbdes2_packet *ps = (void *) pkt;
    ps->iface_mtu = htons(iface_mtu);
    ps->options = ifa->oa->options;
    ps->imms = 0;	/* Will be set later */
    ps->ddseq = htonl(n->dds);
    length = sizeof(struct ospf_dbdes2_packet);
  }
  else /* OSPFv3 */
  {
    struct ospf_dbdes3_packet *ps = (void *) pkt;
    ps->options = htonl(ifa->oa->options);
    ps->iface_mtu = htons(iface_mtu);
    ps->padding = 0;
    ps->imms = 0;	/* Will be set later */
    ps->ddseq = htonl(n->dds);
    length = sizeof(struct ospf_dbdes3_packet);
  }

140 141
  /* Prepare DBDES body */
  if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
  {
    struct ospf_lsa_header *lsas;
    struct top_hash_entry *en;
    uint i = 0, lsa_max;

    ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
    en = (void *) s_get(&(n->dbsi));

    while (i < lsa_max)
    {
      if (!SNODE_VALID(en))
      {
	n->myimms &= ~DBDES_M;	/* Unset More bit */
	break;
      }

      if ((en->lsa.age < LSA_MAXAGE) &&
	  lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
      {
	lsa_hton_hdr(&(en->lsa), lsas + i);
	i++;
      }

      en = SNODE_NEXT(en);
    }

    s_put(&(n->dbsi), SNODE en);

    length += i * sizeof(struct ospf_lsa_header);
  }

  if (ospf_is_v2(p))
    ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
  else
    ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;

  pkt->length = htons(length);
}

static void
ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
  struct ospf_iface *ifa = n->ifa;

  OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
187
	      "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
188 189 190 191 192
  sk_set_tbuf(ifa->sk, n->ldd_buffer);
  ospf_send_to(ifa, n->ip);
  sk_set_tbuf(ifa->sk, NULL);
}

Ondřej Filip's avatar
Ondřej Filip committed
193
/**
194
 * ospf_send_dbdes - transmit database description packet
195
 * @p: OSPF protocol instance
Ondřej Filip's avatar
Ondřej Filip committed
196 197
 * @n: neighbor
 *
198
 * Sending of a database description packet is described in 10.8 of RFC 2328.
199 200 201 202
 * Reception of each packet is acknowledged in the sequence number of another.
 * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
 * does not reply, I don't create a new packet but just send the content
 * of the buffer.
Ondřej Filip's avatar
Ondřej Filip committed
203
 */
204
void
205
ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
206
{
207
  /* RFC 2328 10.8 */
208

209 210
  ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));

211
  if (n->ifa->oa->rt == NULL)
212
    return;
213

214 215 216
  ospf_prepare_dbdes(p, n);
  ospf_do_send_dbdes(p, n);
}
217

218 219 220 221
void
ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
  ASSERT(n->state > NEIGHBOR_EXSTART);
222

223 224 225 226 227
  if (!n->ldd_buffer)
  {
    log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
    ospf_neigh_sm(n, INM_SEQMIS);
    return;
228
  }
229

230 231 232
  /* Send last packet */
  ospf_do_send_dbdes(p, n);
}
233

234 235 236 237
static int
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
{
  struct ospf_iface *ifa = n->ifa;
238 239 240 241
  struct ospf_lsa_header *lsas, lsa;
  struct top_hash_entry *en, *req;
  const char *err_dsc = NULL;
  u32 lsa_type, lsa_domain;
242 243 244 245 246 247 248 249
  uint i, lsa_count;

  ospf_dbdes_body(p, pkt, &lsas, &lsa_count);

  for (i = 0; i < lsa_count; i++)
  {
    lsa_ntoh_hdr(lsas + i, &lsa);
    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 260
    /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
    if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
261
      DROP1("rt-summary-LSA in stub area");
262

263 264
    /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
    if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
265
      DROP1("LSA with invalid scope");
266

267 268 269
    en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
    if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
    {
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);
Ondřej Filip's avatar
Ondřej Filip committed
272

273 274
      if (!SNODE_VALID(req))
	s_add_tail(&n->lsrql, SNODE req);
Ondřej Filip's avatar
Ondřej Filip committed
275

276 277 278
      if (!SNODE_VALID(n->lsrqi))
	n->lsrqi = req;

279
      req->lsa = lsa;
280
      req->lsa_body = LSA_BODY_DUMMY;
281 282 283

      if (!tm_active(n->lsrq_timer))
	tm_start(n->lsrq_timer, 0);
284
    }
Ondřej Filip's avatar
Ondřej Filip committed
285
  }
286 287 288

  return 0;

289 290 291 292
drop:
  LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
  LOG_LSA2("  received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);

293 294
  ospf_neigh_sm(n, INM_SEQMIS);
  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 304 305
  u32 rcv_ddseq, rcv_options;
  u16 rcv_iface_mtu;
  u8 rcv_imms;
306
  uint plen, err_val = 0;
307

308 309 310 311
  /* RFC 2328 10.6 */

  plen = ntohs(pkt->length);
  if (plen < ospf_dbdes_hdrlen(p))
312 313 314 315
  {
    LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
    return;
  }
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);
Ondřej Filip's avatar
Ondřej Filip committed
320

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
  if (ospf_is_v2(p))
  {
    struct ospf_dbdes2_packet *ps = (void *) pkt;
    rcv_iface_mtu = ntohs(ps->iface_mtu);
    rcv_options = ps->options;
    rcv_imms = ps->imms;
    rcv_ddseq = ntohl(ps->ddseq);
  }
  else /* OSPFv3 */
  {
    struct ospf_dbdes3_packet *ps = (void *) pkt;
    rcv_options = ntohl(ps->options);
    rcv_iface_mtu = ntohs(ps->iface_mtu);
    rcv_imms = ps->imms;
    rcv_ddseq = ntohl(ps->ddseq);
  }
337

338
  switch (n->state)
339
  {
340 341 342
  case NEIGHBOR_DOWN:
  case NEIGHBOR_ATTEMPT:
  case NEIGHBOR_2WAY:
343
    OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
344
    return;
345

346 347 348 349
  case NEIGHBOR_INIT:
    ospf_neigh_sm(n, INM_2WAYREC);
    if (n->state != NEIGHBOR_EXSTART)
      return;
350

351 352 353 354 355
  case NEIGHBOR_EXSTART:
    if ((ifa->type != OSPF_IT_VLINK) &&
	(rcv_iface_mtu != ifa->iface->mtu) &&
	(rcv_iface_mtu != 0) &&
	(ifa->iface->mtu != 0))
356 357
      LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
		   n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
358 359 360 361

    if ((rcv_imms == DBDES_IMMS) &&
	(n->rid > p->router_id) &&
	(plen == ospf_dbdes_hdrlen(p)))
362 363
    {
      /* I'm slave! */
364 365 366 367 368
      n->dds = rcv_ddseq;
      n->ddr = rcv_ddseq;
      n->options = rcv_options;
      n->myimms &= ~DBDES_MS;
      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 376
    if (!(rcv_imms & DBDES_I) &&
	!(rcv_imms & DBDES_MS) &&
377
	(n->rid < p->router_id) &&
378
	(n->dds == rcv_ddseq))
379
    {
380
      /* I'm master! */
381 382 383
      n->options = rcv_options;
      n->ddr = rcv_ddseq - 1;	/* It will be set corectly a few lines down */
      n->imms = rcv_imms;
384
      ospf_neigh_sm(n, INM_NEGDONE);
385
      /* Continue to the NEIGHBOR_EXCHANGE case */
386
    }
387 388
    else
    {
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 395 396
    if ((rcv_imms == n->imms) &&
	(rcv_options == n->options) &&
	(rcv_ddseq == n->ddr))
397
      goto duplicate;
398

399 400
    if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
      DROP("MS-bit mismatch", rcv_imms);
401

402 403 404 405 406
    if (rcv_imms & DBDES_I)
      DROP("I-bit mismatch", rcv_imms);

    if (rcv_options != n->options)
      DROP("options mismatch", rcv_options);
407

408 409 410 411
    n->ddr = rcv_ddseq;
    n->imms = rcv_imms;

    if (n->myimms & DBDES_MS)
412
    {
413 414 415 416
      /* MASTER */

      if (rcv_ddseq != n->dds)
	DROP("DD sequence number mismatch", rcv_ddseq);
417

418
      n->dds++;
419 420 421 422 423

      if (ospf_process_dbdes(p, pkt, n) < 0)
	return;

      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
424 425
      {
	tm_stop(n->dbdes_timer);
426
	ospf_neigh_sm(n, INM_EXDONE);
427 428 429 430 431
	break;
      }

      ospf_send_dbdes(p, n);
      tm_start(n->dbdes_timer, n->ifa->rxmtint);
432 433 434
    }
    else
    {
435 436 437 438
      /* SLAVE */

      if (rcv_ddseq != (n->dds + 1))
	DROP("DD sequence number mismatch", rcv_ddseq);
439

440 441 442 443 444 445
      n->ddr = rcv_ddseq;
      n->dds = rcv_ddseq;

      if (ospf_process_dbdes(p, pkt, n) < 0)
	return;

446
      ospf_send_dbdes(p, n);
447 448 449

      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
	ospf_neigh_sm(n, INM_EXDONE);
450
    }
451
    break;
452

453 454
  case NEIGHBOR_LOADING:
  case NEIGHBOR_FULL:
455 456 457
    if ((rcv_imms == n->imms) &&
	(rcv_options == n->options) &&
	(rcv_ddseq == n->ddr))
458 459 460
      goto duplicate;

    DROP("too late for DD exchange", n->state);
461

462
  default:
463
    bug("Undefined interface state");
464
  }
465 466 467 468 469 470 471 472 473 474 475 476 477 478
  return;

duplicate:
  OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");

  /* Slave should retransmit DBDES packet */
  if (!(n->myimms & DBDES_MS))
    ospf_rxmt_dbdes(p, n);
  return;

drop:
  LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
	  n->rid, ifa->ifname, err_dsc, err_val);

479
  ospf_neigh_sm(n, INM_SEQMIS);
480
  return;
481
}