dbdes.c 10.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 7 8 9 10
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

#ifdef OSPFv2
struct ospf_dbdes_packet
{
  struct ospf_packet ospf_packet;
  u16 iface_mtu;
  u8 options;
  union imms imms;		/* I, M, MS bits */
  u32 ddseq;
};

#define hton_opt(X) X
#define ntoh_opt(X) X
#endif


#ifdef OSPFv3
struct ospf_dbdes_packet
{
  struct ospf_packet ospf_packet;
  u32 options;
  u16 iface_mtu;
  u8 padding;
  union imms imms;		/* I, M, MS bits */
  u32 ddseq;
};

#define hton_opt(X) htonl(X)
#define ntoh_opt(X) ntohl(X)
#endif

42 43 44 45 46 47 48 49 50 51 52 53 54 55
  
static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
{
  struct ospf_packet *op = &pkt->ospf_packet;

  ASSERT(op->type == DBDES_P);
  ospf_dump_common(p, op);
  log(L_TRACE "%s:     imms     %s%s%s",
      p->name, pkt->imms.bit.ms ? "MS " : "",
      pkt->imms.bit.m ? "M " : "",
      pkt->imms.bit.i ? "I " : "" );
  log(L_TRACE "%s:     ddseq    %u", p->name, ntohl(pkt->ddseq));

  struct ospf_lsa_header *plsa = (void *) (pkt + 1);
56
  unsigned int i, j;
57 58 59 60 61 62 63 64 65

  j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
    sizeof(struct ospf_lsa_header);

  for (i = 0; i < j; i++)
    ospf_dump_lsahdr(p, plsa + i);
}


Ondřej Filip's avatar
Doc  
Ondřej Filip committed
66
/**
Ondřej Filip's avatar
Ondřej Filip committed
67
 * ospf_dbdes_send - transmit database description packet
Ondřej Filip's avatar
Doc  
Ondřej Filip committed
68
 * @n: neighbor
69
 * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
Ondřej Filip's avatar
Doc  
Ondřej Filip committed
70
 *
71
 * Sending of a database description packet is described in 10.8 of RFC 2328.
Ondřej Filip's avatar
Ondřej Filip committed
72 73 74 75
 * 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
Doc  
Ondřej Filip committed
76
 */
77
void
78
ospf_dbdes_send(struct ospf_neighbor *n, int next)
79 80 81
{
  struct ospf_dbdes_packet *pkt;
  struct ospf_packet *op;
Ondřej Filip's avatar
Ondřej Filip committed
82 83
  struct ospf_iface *ifa = n->ifa;
  struct ospf_area *oa = ifa->oa;
84 85 86
  struct proto_ospf *po = oa->po;
  struct proto *p = &po->proto;
  u16 length, i, j;
87

88
  /* FIXME ??? */
89
  if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
90
    update_rt_lsa(oa);
91

Ondřej Filip's avatar
Ondřej Filip committed
92
  switch (n->state)
93
  {
Ondřej Filip's avatar
Ondřej Filip committed
94 95
  case NEIGHBOR_EXSTART:	/* Send empty packets */
    n->myimms.bit.i = 1;
96
    pkt = (struct ospf_dbdes_packet *) (ifa->sk->tbuf);
Ondřej Filip's avatar
Ondřej Filip committed
97
    op = (struct ospf_packet *) pkt;
98
    ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
Ondřej Filip's avatar
Ondřej Filip committed
99
    pkt->iface_mtu = htons(ifa->iface->mtu);
100
    pkt->options = hton_opt(oa->options);
Ondřej Filip's avatar
Ondřej Filip committed
101 102 103 104
    pkt->imms = n->myimms;
    pkt->ddseq = htonl(n->dds);
    length = sizeof(struct ospf_dbdes_packet);
    op->length = htons(length);
105 106

    OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
107
    ospf_send_to(ifa, n->ip);
Ondřej Filip's avatar
Ondřej Filip committed
108 109 110 111 112
    break;

  case NEIGHBOR_EXCHANGE:
    n->myimms.bit.i = 0;

113
    if (next)
Ondřej Filip's avatar
Ondřej Filip committed
114
    {
115
      snode *sn;
Ondřej Filip's avatar
Ondřej Filip committed
116 117 118 119 120
      struct ospf_lsa_header *lsa;

      pkt = n->ldbdes;
      op = (struct ospf_packet *) pkt;

121
      ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
Ondřej Filip's avatar
Ondřej Filip committed
122 123
      pkt->iface_mtu = htons(ifa->iface->mtu);
      pkt->ddseq = htonl(n->dds);
124
      pkt->options = hton_opt(oa->options);
125

126
      j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header);	/* Number of possible lsaheaders to send */
Ondřej Filip's avatar
Ondřej Filip committed
127
      lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
128

Ondřej Filip's avatar
Ondřej Filip committed
129
      if (n->myimms.bit.m)
130
      {
Ondřej Filip's avatar
Ondřej Filip committed
131 132 133 134
	sn = s_get(&(n->dbsi));

	DBG("Number of LSA: %d\n", j);
	for (; i > 0; i--)
135
	{
136
	  struct top_hash_entry *en= (struct top_hash_entry *) sn;
Ondřej Filip's avatar
Ondřej Filip committed
137

138
          if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
Ondřej Filip's avatar
Ondřej Filip committed
139 140 141
          {
	    htonlsah(&(en->lsa), lsa);
	    DBG("Working on: %d\n", i);
142
	    DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
Ondřej Filip's avatar
Ondřej Filip committed
143 144 145 146

	    lsa++;
          }
          else i++;	/* No lsa added */
147

148
	  if (sn == STAIL(po->lsal))
Ondřej Filip's avatar
Ondřej Filip committed
149 150 151 152 153
          {
            i--;
	    break;
          }

Ondřej Filip's avatar
Ondřej Filip committed
154
	  sn = sn->next;
155
	}
156

157
	if (sn == STAIL(po->lsal))
Ondřej Filip's avatar
Ondřej Filip committed
158 159 160 161 162
	{
	  DBG("Number of LSA NOT sent: %d\n", i);
	  DBG("M bit unset.\n");
	  n->myimms.bit.m = 0;	/* Unset more bit */
	}
163 164

	s_put(&(n->dbsi), sn);
165 166
      }

Ondřej Filip's avatar
Ondřej Filip committed
167
      pkt->imms.byte = n->myimms.byte;
168

Ondřej Filip's avatar
Ondřej Filip committed
169 170 171 172 173 174 175 176 177
      length = (j - i) * sizeof(struct ospf_lsa_header) +
	sizeof(struct ospf_dbdes_packet);
      op->length = htons(length);

      DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
    }

  case NEIGHBOR_LOADING:
  case NEIGHBOR_FULL:
Ondřej Filip's avatar
Ondřej Filip committed
178
    length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
Ondřej Filip's avatar
Ondřej Filip committed
179

Ondřej Filip's avatar
Ondřej Filip committed
180
    if (!length)
181 182 183
    {
      OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
      ospf_neigh_sm(n, INM_KILLNBR);
Ondřej Filip's avatar
Ondřej Filip committed
184
      return;
185 186
    }

Ondřej Filip's avatar
Ondřej Filip committed
187
    /* Copy last sent packet again */
188
    memcpy(ifa->sk->tbuf, n->ldbdes, length);
189

190
    OSPF_PACKET(ospf_dump_dbdes, (struct ospf_dbdes_packet *) ifa->sk->tbuf,
191
		"DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
192
    ospf_send_to(ifa, n->ip);
193 194 195

    if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint);		/* Restart timer */

Ondřej Filip's avatar
Ondřej Filip committed
196 197 198 199
    if (!n->myimms.bit.ms)
    {
      if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
	  (n->state == NEIGHBOR_EXCHANGE))
200
      {
Ondřej Filip's avatar
Ondřej Filip committed
201
	ospf_neigh_sm(n, INM_EXDONE);
202
      }
Ondřej Filip's avatar
Ondřej Filip committed
203 204
    }
    break;
205

Ondřej Filip's avatar
Ondřej Filip committed
206 207
  default:			/* Ignore it */
    break;
208 209 210
  }
}

211
static void
Ondřej Filip's avatar
Ondřej Filip committed
212
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
213
{
Ondřej Filip's avatar
Ondřej Filip committed
214 215
  struct ospf_lsa_header *plsa, lsa;
  struct top_hash_entry *he, *sn;
216 217
  struct ospf_area *oa = n->ifa->oa;
  struct top_graph *gr = oa->po->gr;
Ondřej Filip's avatar
Ondřej Filip committed
218
  struct ospf_packet *op;
Ondřej Filip's avatar
Ondřej Filip committed
219
  int i, j;
220

Ondřej Filip's avatar
Ondřej Filip committed
221
  op = (struct ospf_packet *) ps;
222

Ondřej Filip's avatar
Ondřej Filip committed
223
  plsa = (void *) (ps + 1);
Ondřej Filip's avatar
Ondřej Filip committed
224

Ondřej Filip's avatar
Ondřej Filip committed
225 226
  j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
    sizeof(struct ospf_lsa_header);
Ondřej Filip's avatar
Ondřej Filip committed
227

Ondřej Filip's avatar
Ondřej Filip committed
228
  for (i = 0; i < j; i++)
Ondřej Filip's avatar
Ondřej Filip committed
229
  {
Ondřej Filip's avatar
Ondřej Filip committed
230
    ntohlsah(plsa + i, &lsa);
231 232
    u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
    if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
Ondřej Filip's avatar
Ondřej Filip committed
233
	(lsa_comp(&lsa, &(he->lsa)) == 1))
234
    {
235
      /* Is this condition necessary? */
236
      if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
237
      {
238
	sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
Ondřej Filip's avatar
Ondřej Filip committed
239 240
	ntohlsah(plsa + i, &(sn->lsa));
	s_add_tail(&(n->lsrql), SNODE sn);
241 242
      }
    }
Ondřej Filip's avatar
Ondřej Filip committed
243
  }
244 245 246
}

void
247 248
ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
		   struct ospf_neighbor *n)
249
{
250 251
  struct proto_ospf *po = ifa->oa->po;
  struct proto *p = &po->proto;
252

253 254 255 256 257 258 259 260
  unsigned int size = ntohs(ps_i->length);
  if (size < sizeof(struct ospf_dbdes_packet))
  {
    log(L_ERR "Bad OSPF DBDES packet from %I -  too short (%u B)", n->ip, size);
    return;
  }

  struct ospf_dbdes_packet *ps = (void *) ps_i;
261 262 263
  u32 ps_ddseq = ntohl(ps->ddseq);
  u32 ps_options = ntoh_opt(ps->options);
  
264
  OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
265

266
  ospf_neigh_sm(n, INM_HELLOREC);
Ondřej Filip's avatar
Ondřej Filip committed
267

Ondřej Filip's avatar
Ondřej Filip committed
268
  switch (n->state)
269
  {
Ondřej Filip's avatar
Ondřej Filip committed
270 271 272 273 274 275 276 277 278 279 280
  case NEIGHBOR_DOWN:
  case NEIGHBOR_ATTEMPT:
  case NEIGHBOR_2WAY:
    return;
    break;
  case NEIGHBOR_INIT:
    ospf_neigh_sm(n, INM_2WAYREC);
    if (n->state != NEIGHBOR_EXSTART)
      return;
  case NEIGHBOR_EXSTART:
    if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
281
	&& (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
Ondřej Filip's avatar
Ondřej Filip committed
282 283
    {
      /* I'm slave! */
284 285 286
      n->dds = ps_ddseq;
      n->ddr = ps_ddseq;
      n->options = ps_options;
Ondřej Filip's avatar
Ondřej Filip committed
287 288 289 290
      n->myimms.bit.ms = 0;
      n->imms.byte = ps->imms.byte;
      OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
      ospf_neigh_sm(n, INM_NEGDONE);
291
      ospf_dbdes_send(n, 1);
292
      break;
Ondřej Filip's avatar
Ondřej Filip committed
293
    }
294 295

    if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
296
        (n->rid < po->router_id) && (n->dds == ps_ddseq))
Ondřej Filip's avatar
Ondřej Filip committed
297
    {
298
      /* I'm master! */
299 300
      n->options = ps_options;
      n->ddr = ps_ddseq - 1;	/* It will be set corectly a few lines down */
301 302 303
      n->imms.byte = ps->imms.byte;
      OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
      ospf_neigh_sm(n, INM_NEGDONE);
Ondřej Filip's avatar
Ondřej Filip committed
304
    }
305 306 307 308
    else
    {
      DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip,
          ps->imms.byte);
Ondřej Filip's avatar
Ondřej Filip committed
309
      break;
310
    }
Ondřej Filip's avatar
Ondřej Filip committed
311
  case NEIGHBOR_EXCHANGE:
312 313
    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
	(ps_ddseq == n->ddr))
Ondřej Filip's avatar
Ondřej Filip committed
314 315 316
    {
      /* Duplicate packet */
      OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
317
      if (n->myimms.bit.ms == 0)
Ondřej Filip's avatar
Ondřej Filip committed
318
      {
319
	/* Slave should retransmit dbdes packet */
320
	ospf_dbdes_send(n, 0);
Ondřej Filip's avatar
Ondřej Filip committed
321 322 323
      }
      return;
    }
324

325
    n->ddr = ps_ddseq;
326

Ondřej Filip's avatar
Ondřej Filip committed
327 328 329 330 331
    if (ps->imms.bit.ms != n->imms.bit.ms)	/* M/S bit differs */
    {
      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
		 n->ip);
      ospf_neigh_sm(n, INM_SEQMIS);
332
      break;
Ondřej Filip's avatar
Ondřej Filip committed
333 334 335 336 337 338 339
    }

    if (ps->imms.bit.i)		/* I bit is set */
    {
      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)",
		 n->ip);
      ospf_neigh_sm(n, INM_SEQMIS);
340
      break;
Ondřej Filip's avatar
Ondřej Filip committed
341 342 343 344
    }

    n->imms.byte = ps->imms.byte;

345
    if (ps_options != n->options)	/* Options differs */
Ondřej Filip's avatar
Ondřej Filip committed
346 347 348 349
    {
      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
		 n->ip);
      ospf_neigh_sm(n, INM_SEQMIS);
350
      break;
Ondřej Filip's avatar
Ondřej Filip committed
351
    }
352

Ondřej Filip's avatar
Ondřej Filip committed
353 354
    if (n->myimms.bit.ms)
    {
355
      if (ps_ddseq != n->dds)	/* MASTER */
Ondřej Filip's avatar
Ondřej Filip committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
      {
	OSPF_TRACE(D_PACKETS,
		   "dbdes - sequence mismatch neighbor %I (master)", n->ip);
	ospf_neigh_sm(n, INM_SEQMIS);
	break;
      }
      n->dds++;
      DBG("Incrementing dds\n");
      ospf_dbdes_reqladd(ps, n);
      if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
      {
	ospf_neigh_sm(n, INM_EXDONE);
      }
      else
      {
371
	ospf_dbdes_send(n, 1);
Ondřej Filip's avatar
Ondřej Filip committed
372 373 374 375 376
      }

    }
    else
    {
377
      if (ps_ddseq != (n->dds + 1))	/* SLAVE */
Ondřej Filip's avatar
Ondřej Filip committed
378 379 380 381 382 383
      {
	OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
		   n->ip);
	ospf_neigh_sm(n, INM_SEQMIS);
	break;
      }
384 385
      n->ddr = ps_ddseq;
      n->dds = ps_ddseq;
Ondřej Filip's avatar
Ondřej Filip committed
386
      ospf_dbdes_reqladd(ps, n);
387
      ospf_dbdes_send(n, 1);
Ondřej Filip's avatar
Ondřej Filip committed
388 389 390 391 392
    }

    break;
  case NEIGHBOR_LOADING:
  case NEIGHBOR_FULL:
393 394
    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
	&& (ps_ddseq == n->ddr))
Ondřej Filip's avatar
Ondřej Filip committed
395 396 397
      /* Only duplicate are accepted */
    {
      OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
398 399 400
      if (n->myimms.bit.ms == 0)
      {
	/* Slave should retransmit dbdes packet */
401
	ospf_dbdes_send(n, 0);
402
      }
Ondřej Filip's avatar
Ondřej Filip committed
403 404 405 406 407 408
      return;
    }
    else
    {
      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
		 n->ip);
409
      DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
Ondřej Filip's avatar
Ondřej Filip committed
410 411 412
      ospf_neigh_sm(n, INM_SEQMIS);
    }
    break;
Martin Mareš's avatar
Martin Mareš committed
413
  default:
Ondřej Filip's avatar
Ondřej Filip committed
414 415 416
    bug("Received dbdes from %I in undefined state.", n->ip);
  }
}