packets.c 32.2 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 *	BIRD -- BGP Packet Processing
 *
 *	(c) 2000 Martin Mares <mj@ucw.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

Martin Mareš's avatar
Martin Mareš committed
9
#undef LOCAL_DEBUG
10

11 12 13 14
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
#include "nest/route.h"
15
#include "nest/attrs.h"
16
#include "nest/mrtdump.h"
17
#include "conf/conf.h"
18 19
#include "lib/unaligned.h"
#include "lib/socket.h"
20

Ondřej Zajíček's avatar
Ondřej Zajíček committed
21 22
#include "nest/cli.h"

23
#include "bgp.h"
24

25 26
static struct rate_limit rl_rcv_update,  rl_snd_update;

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/*
 * MRT Dump format is not semantically specified.
 * We will use these values in appropriate fields:
 *
 * Local AS, Remote AS - configured AS numbers for given BGP instance.
 * Local IP, Remote IP - IP addresses of the TCP connection (0 if no connection)
 *
 * We dump two kinds of MRT messages: STATE_CHANGE (for BGP state
 * changes) and MESSAGE (for received BGP messages).
 *
 * STATE_CHANGE uses always AS4 variant, but MESSAGE uses AS4 variant
 * only when AS4 session is established and even in that case MESSAGE
 * does not use AS4 variant for initial OPEN message. This strange
 * behavior is here for compatibility with Quagga and Bgpdump,
 */

static byte *
mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
{
  struct bgp_proto *p = conn->bgp;

  if (as4)
    {
      put_u32(buf+0, p->remote_as);
      put_u32(buf+4, p->local_as);
      buf+=8;
    }
  else
    {
      put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS);
      put_u16(buf+2, (p->local_as <= 0xFFFF)  ? p->local_as  : AS_TRANS);
      buf+=4;
    }

61
  put_u16(buf+0, p->neigh ? p->neigh->iface->index : 0);
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  put_u16(buf+2, BGP_AF);
  buf+=4;
  buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
  buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE);

  return buf;
}

static void
mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
{
  byte buf[BGP_MAX_PACKET_LENGTH + 128];
  byte *bp = buf + MRTDUMP_HDR_LENGTH;
  int as4 = conn->bgp->as4_session;

  bp = mrt_put_bgp4_hdr(bp, conn, as4);
  memcpy(bp, pkt, len);
  bp += len;
  mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE,
		   buf, bp-buf);
}

static inline u16
convert_state(unsigned state)
{
  /* Convert state from our BS_* values to values used in MRTDump */
  return (state == BS_CLOSE) ? 1 : state + 1;
}

void
mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)
{
  byte buf[128];
  byte *bp = buf + MRTDUMP_HDR_LENGTH;

  bp = mrt_put_bgp4_hdr(bp, conn, 1);
  put_u16(bp+0, convert_state(old));
  put_u16(bp+2, convert_state(new));
  bp += 4;
  mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf);
}

104 105 106
static byte *
bgp_create_notification(struct bgp_conn *conn, byte *buf)
{
Martin Mareš's avatar
Martin Mareš committed
107 108 109
  struct bgp_proto *p = conn->bgp;

  BGP_TRACE(D_PACKETS, "Sending NOTIFICATION(code=%d.%d)", conn->notify_code, conn->notify_subcode);
110 111
  buf[0] = conn->notify_code;
  buf[1] = conn->notify_subcode;
112 113
  memcpy(buf+2, conn->notify_data, conn->notify_size);
  return buf + 2 + conn->notify_size;
114 115
}

116 117 118 119 120 121 122 123 124 125 126 127
#ifdef IPV6
static byte *
bgp_put_cap_ipv6(struct bgp_conn *conn UNUSED, byte *buf)
{
  *buf++ = 1;		/* Capability 1: Multiprotocol extensions */
  *buf++ = 4;		/* Capability data length */
  *buf++ = 0;		/* We support AF IPv6 */
  *buf++ = BGP_AF_IPV6;
  *buf++ = 0;		/* RFU */
  *buf++ = 1;		/* and SAFI 1 */
  return buf;
}
128 129 130 131 132 133 134 135 136 137 138 139 140 141

#else

static byte *
bgp_put_cap_ipv4(struct bgp_conn *conn UNUSED, byte *buf)
{
  *buf++ = 1;		/* Capability 1: Multiprotocol extensions */
  *buf++ = 4;		/* Capability data length */
  *buf++ = 0;		/* We support AF IPv4 */
  *buf++ = BGP_AF_IPV4;
  *buf++ = 0;		/* RFU */
  *buf++ = 1;		/* and SAFI 1 */
  return buf;
}
142 143
#endif

144 145 146 147 148 149 150 151
static byte *
bgp_put_cap_rr(struct bgp_conn *conn UNUSED, byte *buf)
{
  *buf++ = 2;		/* Capability 2: Support for route refresh */
  *buf++ = 0;		/* Capability data length */
  return buf;
}

152 153 154 155 156 157 158 159 160
static byte *
bgp_put_cap_as4(struct bgp_conn *conn, byte *buf)
{
  *buf++ = 65;		/* Capability 65: Support for 4-octet AS number */
  *buf++ = 4;		/* Capability data length */
  put_u32(buf, conn->bgp->local_as);
  return buf + 4;
}

161 162 163
static byte *
bgp_create_open(struct bgp_conn *conn, byte *buf)
{
Martin Mareš's avatar
Martin Mareš committed
164
  struct bgp_proto *p = conn->bgp;
165 166
  byte *cap;
  int cap_len;
Martin Mareš's avatar
Martin Mareš committed
167 168 169

  BGP_TRACE(D_PACKETS, "Sending OPEN(ver=%d,as=%d,hold=%d,id=%08x)",
	    BGP_VERSION, p->local_as, p->cf->hold_time, p->local_id);
170
  buf[0] = BGP_VERSION;
171
  put_u16(buf+1, (p->local_as < 0xFFFF) ? p->local_as : AS_TRANS);
Martin Mareš's avatar
Martin Mareš committed
172 173
  put_u16(buf+3, p->cf->hold_time);
  put_u32(buf+5, p->local_id);
174 175 176 177 178 179 180 181

  if (conn->start_state == BSS_CONNECT_NOCAP)
    {
      BGP_TRACE(D_PACKETS, "Skipping capabilities");
      buf[9] = 0;
      return buf + 10;
    }

182 183 184
  /* Skipped 3 B for length field and Capabilities parameter header */
  cap = buf + 12;

185 186 187 188 189
#ifndef IPV6
  if (p->cf->advertise_ipv4)
    cap = bgp_put_cap_ipv4(conn, cap);
#endif

190 191
#ifdef IPV6
  cap = bgp_put_cap_ipv6(conn, cap);
192
#endif
193

194 195 196
  if (p->cf->enable_refresh)
    cap = bgp_put_cap_rr(conn, cap);

197
  if (conn->want_as4_support)
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    cap = bgp_put_cap_as4(conn, cap);

  cap_len = cap - buf - 12;
  if (cap_len > 0)
    {
      buf[9]  = cap_len + 2;	/* Optional params len */
      buf[10] = 2;		/* Option: Capability list */
      buf[11] = cap_len;	/* Option length */
      return cap;
    }
  else
    {
      buf[9] = 0;		/* No optional parameters */
      return buf + 10;
    }
213 214
}

215 216 217 218 219 220 221
static unsigned int
bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains)
{
  byte *start = w;
  ip_addr a;
  int bytes;

222
  while (!EMPTY_LIST(buck->prefixes) && remains >= (1+sizeof(ip_addr)))
223 224 225 226 227 228 229 230 231
    {
      struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
      DBG("\tDequeued route %I/%d\n", px->n.prefix, px->n.pxlen);
      *w++ = px->n.pxlen;
      bytes = (px->n.pxlen + 7) / 8;
      a = px->n.prefix;
      ipa_hton(a);
      memcpy(w, &a, bytes);
      w += bytes;
232
      remains -= bytes + 1;
233 234 235 236 237 238
      rem_node(&px->bucket_node);
      fib_delete(&p->prefix_fib, px);
    }
  return w - start;
}

239 240 241 242 243 244 245 246 247 248 249 250
static void
bgp_flush_prefixes(struct bgp_proto *p, struct bgp_bucket *buck)
{
  while (!EMPTY_LIST(buck->prefixes))
    {
      struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
      log(L_ERR "%s: - route %I/%d skipped", p->p.name, px->n.prefix, px->n.pxlen);
      rem_node(&px->bucket_node);
      fib_delete(&p->prefix_fib, px);
    }
}

Martin Mareš's avatar
Martin Mareš committed
251 252
#ifndef IPV6		/* IPv4 version */

253 254 255
static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
Martin Mareš's avatar
Martin Mareš committed
256
  struct bgp_proto *p = conn->bgp;
257 258
  struct bgp_bucket *buck;
  int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
259
  byte *w;
260 261
  int wd_size = 0;
  int r_size = 0;
262
  int a_size = 0;
263 264

  w = buf+2;
Martin Mareš's avatar
Martin Mareš committed
265
  if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
266 267
    {
      DBG("Withdrawn routes:\n");
Martin Mareš's avatar
Martin Mareš committed
268
      wd_size = bgp_encode_prefixes(p, w, buck, remains);
269 270 271 272
      w += wd_size;
      remains -= wd_size;
    }
  put_u16(buf, wd_size);
273

274
  if (remains >= 3072)
275
    {
Martin Mareš's avatar
Martin Mareš committed
276
      while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next)
277 278 279 280 281
	{
	  if (EMPTY_LIST(buck->prefixes))
	    {
	      DBG("Deleting empty bucket %p\n", buck);
	      rem_node(&buck->send_node);
Martin Mareš's avatar
Martin Mareš committed
282
	      bgp_free_bucket(p, buck);
283 284
	      continue;
	    }
285

286
	  DBG("Processing bucket %p\n", buck);
287 288 289 290
	  a_size = bgp_encode_attrs(p, w+2, buck->eattrs, 2048);

	  if (a_size < 0)
	    {
291
	      log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
292 293 294 295 296 297
	      bgp_flush_prefixes(p, buck);
	      rem_node(&buck->send_node);
	      bgp_free_bucket(p, buck);
	      continue;
	    }

298 299 300
	  put_u16(w, a_size);
	  w += a_size + 2;
	  r_size = bgp_encode_prefixes(p, w, buck, remains - a_size);
301 302 303 304
	  w += r_size;
	  break;
	}
    }
305
  if (!a_size)				/* Attributes not already encoded */
306 307 308 309
    {
      put_u16(w, 0);
      w += 2;
    }
310 311
  if (wd_size || r_size)
    {
312
      BGP_TRACE_RL(&rl_snd_update, D_PACKETS, "Sending UPDATE");
313 314 315 316
      return w;
    }
  else
    return NULL;
317 318
}

Martin Mareš's avatar
Martin Mareš committed
319 320 321 322 323
#else		/* IPv6 version */

static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
324 325
  struct bgp_proto *p = conn->bgp;
  struct bgp_bucket *buck;
326
  int size, second, rem_stored;
327
  int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
328
  byte *w, *w_stored, *tmp, *tstart;
329
  ip_addr *ipp, ip, ip_ll;
330 331 332 333 334 335 336 337 338 339
  ea_list *ea;
  eattr *nh;
  neighbor *n;

  put_u16(buf, 0);
  w = buf+4;

  if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
    {
      DBG("Withdrawn routes:\n");
340
      tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8);
341 342 343
      *tmp++ = 0;
      *tmp++ = BGP_AF_IPV6;
      *tmp++ = 1;
344
      ea->attrs[0].u.ptr->length = 3 + bgp_encode_prefixes(p, tmp, buck, remains-11);
345
      size = bgp_encode_attrs(p, w, ea, remains);
346
      ASSERT(size >= 0);
347 348 349 350
      w += size;
      remains -= size;
    }

351
  if (remains >= 3072)
352 353 354 355 356 357 358 359 360 361
    {
      while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next)
	{
	  if (EMPTY_LIST(buck->prefixes))
	    {
	      DBG("Deleting empty bucket %p\n", buck);
	      rem_node(&buck->send_node);
	      bgp_free_bucket(p, buck);
	      continue;
	    }
362

363
	  DBG("Processing bucket %p\n", buck);
364 365
	  rem_stored = remains;
	  w_stored = w;
366

367
	  size = bgp_encode_attrs(p, w, buck->eattrs, 2048);
368 369
	  if (size < 0)
	    {
370
	      log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
371 372 373 374 375
	      bgp_flush_prefixes(p, buck);
	      rem_node(&buck->send_node);
	      bgp_free_bucket(p, buck);
	      continue;
	    }
376 377
	  w += size;
	  remains -= size;
378

379
	  /* We have two addresses here in NEXT_HOP eattr. Really.
380
	     Unless NEXT_HOP was modified by filter */
381 382
	  nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
	  ASSERT(nh);
383
	  second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
384 385 386 387
	  ipp = (ip_addr *) nh->u.ptr->data;
	  ip = ipp[0];
	  ip_ll = IPA_NONE;

388
	  if (ipa_equal(ip, p->source_addr))
389
	    ip_ll = p->local_link;
390 391
	  else
	    {
392 393 394 395
	      /* If we send a route with 'third party' next hop destinated 
	       * in the same interface, we should also send a link local 
	       * next hop address. We use the received one (stored in the 
	       * other part of BA_NEXT_HOP eattr). If we didn't received
396 397 398 399 400 401
	       * it (for example it is a static route), we can't use
	       * 'third party' next hop and we have to use local IP address
	       * as next hop. Sending original next hop address without
	       * link local address seems to be a natural way to solve that
	       * problem, but it is contrary to RFC 2545 and Quagga does not
	       * accept such routes.
402 403
	       */

404
	      n = neigh_find(&p->p, &ip, 0);
405
	      if (n && p->neigh && n->iface == p->neigh->iface)
406
		{
407
		  if (second && ipa_nonzero(ipp[1]))
408 409 410
		    ip_ll = ipp[1];
		  else
		    {
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
		      switch (p->cf->missing_lladdr)
			{
			case MLL_SELF:
			  ip = p->source_addr;
			  ip_ll = p->local_link;
			  break;
			case MLL_DROP:
			  log(L_ERR "%s: Missing link-local next hop address, skipping corresponding routes", p->p.name);
			  w = w_stored;
			  remains = rem_stored;
			  bgp_flush_prefixes(p, buck);
			  rem_node(&buck->send_node);
			  bgp_free_bucket(p, buck);
			  continue;
			case MLL_IGNORE:
			  break;
			}
428 429
		    }
		}
430
	    }
431

432 433 434 435 436
	  tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
	  *tmp++ = 0;
	  *tmp++ = BGP_AF_IPV6;
	  *tmp++ = 1;

437
	  if (ipa_nonzero(ip_ll))
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
	    {
	      *tmp++ = 32;
	      ipa_hton(ip);
	      memcpy(tmp, &ip, 16);
	      ipa_hton(ip_ll);
	      memcpy(tmp+16, &ip_ll, 16);
	      tmp += 32;
	    }
	  else
	    {
	      *tmp++ = 16;
	      ipa_hton(ip);
	      memcpy(tmp, &ip, 16);
	      tmp += 16;
	    }
453

454 455 456
	  *tmp++ = 0;			/* No SNPA information */
	  tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1));
	  ea->attrs[0].u.ptr->length = tmp - tstart;
457 458 459
	  size = bgp_encode_attrs(p, w, ea, remains);
	  ASSERT(size >= 0);
	  w += size;
460 461 462 463 464 465 466
	  break;
	}
    }

  size = w - (buf+4);
  put_u16(buf+2, size);
  lp_flush(bgp_linpool);
467 468
  if (size)
    {
469
      BGP_TRACE_RL(&rl_snd_update, D_PACKETS, "Sending UPDATE");
470 471 472 473
      return w;
    }
  else
    return NULL;
Martin Mareš's avatar
Martin Mareš committed
474 475 476 477
}

#endif

478 479 480 481 482 483
static byte *
bgp_create_route_refresh(struct bgp_conn *conn, byte *buf)
{
  struct bgp_proto *p = conn->bgp;
  BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH");

484 485
  *buf++ = 0;
  *buf++ = BGP_AF;
486 487 488 489 490
  *buf++ = 0;		/* RFU */
  *buf++ = 1;		/* and SAFI 1 */
  return buf;
}

491 492 493 494 495 496 497 498
static void
bgp_create_header(byte *buf, unsigned int len, unsigned int type)
{
  memset(buf, 0xff, 16);		/* Marker */
  put_u16(buf+16, len);
  buf[18] = type;
}

Martin Mareš's avatar
Martin Mareš committed
499 500 501 502 503 504 505 506 507 508
/**
 * bgp_fire_tx - transmit packets
 * @conn: connection
 *
 * Whenever the transmit buffers of the underlying TCP connection
 * are free and we have any packets queued for sending, the socket functions
 * call bgp_fire_tx() which takes care of selecting the highest priority packet
 * queued (Notification > Keepalive > Open > Update), assembling its header
 * and body and sending it to the connection.
 */
509
static int
510 511
bgp_fire_tx(struct bgp_conn *conn)
{
Martin Mareš's avatar
Martin Mareš committed
512
  struct bgp_proto *p = conn->bgp;
513 514
  unsigned int s = conn->packets_to_send;
  sock *sk = conn->sk;
515
  byte *buf, *pkt, *end;
516 517
  int type;

518 519 520 521 522 523 524 525
  if (!sk)
    {
      conn->packets_to_send = 0;
      return 0;
    }
  buf = sk->tbuf;
  pkt = buf + BGP_HEADER_LENGTH;

526 527
  if (s & (1 << PKT_SCHEDULE_CLOSE))
    {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
528 529
      /* We can finally close connection and enter idle state */
      bgp_conn_enter_idle_state(conn);
530
      return 0;
531 532 533 534 535 536 537 538 539 540 541 542
    }
  if (s & (1 << PKT_NOTIFICATION))
    {
      s = 1 << PKT_SCHEDULE_CLOSE;
      type = PKT_NOTIFICATION;
      end = bgp_create_notification(conn, pkt);
    }
  else if (s & (1 << PKT_KEEPALIVE))
    {
      s &= ~(1 << PKT_KEEPALIVE);
      type = PKT_KEEPALIVE;
      end = pkt;			/* Keepalives carry no data */
Martin Mareš's avatar
Martin Mareš committed
543
      BGP_TRACE(D_PACKETS, "Sending KEEPALIVE");
544
      bgp_start_timer(conn->keepalive_timer, conn->keepalive_time);
545 546 547 548 549 550 551
    }
  else if (s & (1 << PKT_OPEN))
    {
      s &= ~(1 << PKT_OPEN);
      type = PKT_OPEN;
      end = bgp_create_open(conn, pkt);
    }
552 553 554 555 556 557
  else if (s & (1 << PKT_ROUTE_REFRESH))
    {
      s &= ~(1 << PKT_ROUTE_REFRESH);
      type = PKT_ROUTE_REFRESH;
      end = bgp_create_route_refresh(conn, pkt);
    }
558 559 560 561 562 563 564
  else if (s & (1 << PKT_UPDATE))
    {
      end = bgp_create_update(conn, pkt);
      type = PKT_UPDATE;
      if (!end)
	{
	  conn->packets_to_send = 0;
565
	  return 0;
566 567 568
	}
    }
  else
569
    return 0;
570 571
  conn->packets_to_send = s;
  bgp_create_header(buf, end - buf, type);
572
  return sk_send(sk, end - buf);
573 574
}

Martin Mareš's avatar
Martin Mareš committed
575 576 577 578 579 580 581
/**
 * bgp_schedule_packet - schedule a packet for transmission
 * @conn: connection
 * @type: packet type
 *
 * Schedule a packet of type @type to be sent as soon as possible.
 */
582 583 584 585 586
void
bgp_schedule_packet(struct bgp_conn *conn, int type)
{
  DBG("BGP: Scheduling packet type %d\n", type);
  conn->packets_to_send |= 1 << type;
587
  if (conn->sk && conn->sk->tpos == conn->sk->tbuf)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
588 589 590 591 592 593 594 595 596
    ev_schedule(conn->tx_ev);
}

void
bgp_kick_tx(void *vconn)
{
  struct bgp_conn *conn = vconn;

  DBG("BGP: kicking TX\n");
597
  while (bgp_fire_tx(conn) > 0)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
598
    ;
599 600 601 602 603 604 605 606
}

void
bgp_tx(sock *sk)
{
  struct bgp_conn *conn = sk->data;

  DBG("BGP: TX hook\n");
607
  while (bgp_fire_tx(conn) > 0)
608 609 610
    ;
}

611 612 613 614 615
/* Capatibility negotiation as per RFC 2842 */

void
bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
{
616
  // struct bgp_proto *p = conn->bgp;
617 618 619 620 621 622 623 624 625 626 627
  int cl;

  while (len > 0)
    {
      if (len < 2 || len < 2 + opt[1])
	goto err;
      
      cl = opt[1];

      switch (opt[0])
	{
628
	case 2:	/* Route refresh capability, RFC 2918 */
629 630 631 632
	  if (cl != 0)
	    goto err;
	  conn->peer_refresh_support = 1;
	  break;
633 634

	case 65: /* AS4 capability, RFC 4893 */ 
635 636
	  if (cl != 4)
	    goto err;
637 638
	  conn->peer_as4_support = 1;
	  if (conn->want_as4_support)
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
	    conn->advertised_as = get_u32(opt + 2);
	  break;

	  /* We can safely ignore all other capabilities */
	}
      len -= 2 + cl;
      opt += 2 + cl;
    }
  return;

    err:
  bgp_error(conn, 2, 0, NULL, 0);
  return;
}

654 655 656
static int
bgp_parse_options(struct bgp_conn *conn, byte *opt, int len)
{
657
  struct bgp_proto *p = conn->bgp;
658 659
  int ol;

660 661 662
  while (len > 0)
    {
      if (len < 2 || len < 2 + opt[1])
663
	{ bgp_error(conn, 2, 0, NULL, 0); return 0; }
664 665 666 667 668 669 670 671 672
#ifdef LOCAL_DEBUG
      {
	int i;
	DBG("\tOption %02x:", opt[0]);
	for(i=0; i<opt[1]; i++)
	  DBG(" %02x", opt[2+i]);
	DBG("\n");
      }
#endif
673 674

      ol = opt[1];
675 676 677
      switch (opt[0])
	{
	case 2:
678 679 680 681
	  if (conn->start_state == BSS_CONNECT_NOCAP)
	    BGP_TRACE(D_PACKETS, "Ignoring received capabilities");
	  else
	    bgp_parse_capabilities(conn, opt + 2, ol);
682
	  break;
683

684 685 686 687 688 689 690
	default:
	  /*
	   *  BGP specs don't tell us to send which option
	   *  we didn't recognize, but it's common practice
	   *  to do so. Also, capability negotiation with
	   *  Cisco routers doesn't work without that.
	   */
691
	  bgp_error(conn, 2, 4, opt, ol);
692 693
	  return 0;
	}
694 695
      len -= 2 + ol;
      opt += 2 + ol;
696 697 698 699
    }
  return 0;
}

700 701 702
static void
bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
{
703
  struct bgp_conn *other;
704
  struct bgp_proto *p = conn->bgp;
705
  unsigned hold;
706
  u16 base_as;
707 708 709 710
  u32 id;

  /* Check state */
  if (conn->state != BS_OPENSENT)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
711
    { bgp_error(conn, 5, 0, NULL, 0); return; }
712 713 714

  /* Check message contents */
  if (len < 29 || len != 29 + pkt[28])
715
    { bgp_error(conn, 1, 2, pkt+16, 2); return; }
716
  if (pkt[19] != BGP_VERSION)
717
    { bgp_error(conn, 2, 1, pkt+19, 1); return; } /* RFC 1771 says 16 bits, draft-09 tells to use 8 */
718
  conn->advertised_as = base_as = get_u16(pkt+20);
719 720
  hold = get_u16(pkt+22);
  id = get_u32(pkt+24);
721 722
  BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%08x)", conn->advertised_as, hold, id);

723 724
  if (bgp_parse_options(conn, pkt+29, pkt[28]))
    return;
725 726 727 728

  if (hold > 0 && hold < 3)
    { bgp_error(conn, 2, 6, pkt+22, 2); return; }

729
  if (!id || id == 0xffffffff || id == p->local_id)
730
    { bgp_error(conn, 2, 3, pkt+24, -4); return; }
731

732 733 734
  if ((conn->advertised_as != base_as) && (base_as != AS_TRANS))
    log(L_WARN "%s: Peer advertised inconsistent AS numbers", p->p.name);

735
  if (conn->advertised_as != p->remote_as)
736 737 738 739 740 741 742 743 744 745 746
    {
      if (conn->peer_as4_support)
	{
	  u32 val = htonl(conn->advertised_as);
	  bgp_error(conn, 2, 2, (byte *) &val, 4);
	}
      else
	bgp_error(conn, 2, 2, pkt+20, 2);

      return;
    }
747

748 749 750 751 752 753 754 755
  /* Check the other connection */
  other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
  switch (other->state)
    {
    case BS_IDLE:
    case BS_CONNECT:
    case BS_ACTIVE:
    case BS_OPENSENT:
Ondřej Zajíček's avatar
Ondřej Zajíček committed
756
    case BS_CLOSE:
757 758 759 760 761
      break;
    case BS_OPENCONFIRM:
      if ((p->local_id < id) == (conn == &p->incoming_conn))
	{
	  /* Should close the other connection */
Martin Mareš's avatar
Martin Mareš committed
762
	  BGP_TRACE(D_EVENTS, "Connection collision, giving up the other connection");
763
	  bgp_error(other, 6, 7, NULL, 0);
764 765 766 767 768
	  break;
	}
      /* Fall thru */
    case BS_ESTABLISHED:
      /* Should close this connection */
Martin Mareš's avatar
Martin Mareš committed
769
      BGP_TRACE(D_EVENTS, "Connection collision, giving up this connection");
770
      bgp_error(conn, 6, 7, NULL, 0);
771 772 773 774 775
      return;
    default:
      bug("bgp_rx_open: Unknown state");
    }

776
  /* Update our local variables */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
777
  conn->hold_time = MIN(hold, p->cf->hold_time);
778 779
  conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
  p->remote_id = id;
780 781
  p->as4_session = conn->want_as4_support && conn->peer_as4_support;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
782
  DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);
783 784 785

  bgp_schedule_packet(conn, PKT_KEEPALIVE);
  bgp_start_timer(conn->hold_timer, conn->hold_time);
786
  bgp_conn_enter_openconfirm_state(conn);
787 788
}

789 790 791 792
#define DECODE_PREFIX(pp, ll) do {		\
  int b = *pp++;				\
  int q;					\
  ll--;						\
Martin Mareš's avatar
Martin Mareš committed
793
  if (b > BITS_PER_IP_ADDRESS) { err=10; goto bad; } \
794
  q = (b+7) / 8;				\
Martin Mareš's avatar
Martin Mareš committed
795
  if (ll < q) { err=1; goto bad; }		\
796
  memcpy(&prefix, pp, q);			\
797 798
  pp += q;					\
  ll -= q;					\
799 800
  ipa_ntoh(prefix);				\
  prefix = ipa_and(prefix, ipa_mkmask(b));	\
801
  pxlen = b;					\
802 803
} while (0)

Martin Mareš's avatar
Martin Mareš committed
804
static inline int
805
bgp_set_next_hop(struct bgp_proto *p, rta *a)
Martin Mareš's avatar
Martin Mareš committed
806 807
{
  struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
808 809 810 811 812 813 814
  ip_addr *nexthop = (ip_addr *) nh->u.ptr->data;

#ifdef IPV6
  int second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
#else
  int second = 0;
#endif
815

816
  if (p->cf->gw_mode == GW_DIRECT)
Martin Mareš's avatar
Martin Mareš committed
817
    {
818
      neighbor *ng = neigh_find(&p->p, nexthop, 0) ? : p->neigh;
819 820 821 822 823 824 825
      if (ng->scope == SCOPE_HOST)
	return 0;

      a->dest = RTD_ROUTER;
      a->gw = ng->addr;
      a->iface = ng->iface;
      a->hostentry = NULL;
826
      a->igp_metric = 0;
Martin Mareš's avatar
Martin Mareš committed
827
    }
828
  else /* GW_RECURSIVE */
829
    rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second);
830

Martin Mareš's avatar
Martin Mareš committed
831 832 833 834 835
  return 1;
}

#ifndef IPV6		/* IPv4 version */

836
static void
Martin Mareš's avatar
Martin Mareš committed
837 838 839 840
bgp_do_rx_update(struct bgp_conn *conn,
		 byte *withdrawn, int withdrawn_len,
		 byte *nlri, int nlri_len,
		 byte *attrs, int attr_len)
841
{
Martin Mareš's avatar
Martin Mareš committed
842
  struct bgp_proto *p = conn->bgp;
Martin Mareš's avatar
Martin Mareš committed
843 844
  rta *a0;
  rta *a = NULL;
845 846
  ip_addr prefix;
  net *n;
Martin Mareš's avatar
Martin Mareš committed
847
  int err = 0, pxlen;
848 849 850 851 852

  /* Withdraw routes */
  while (withdrawn_len)
    {
      DECODE_PREFIX(withdrawn, withdrawn_len);
853
      DBG("Withdraw %I/%d\n", prefix, pxlen);
Martin Mareš's avatar
Martin Mareš committed
854
      if (n = net_find(p->p.table, prefix, pxlen))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
855
	rte_update(p->p.table, n, &p->p, &p->p, NULL);
856 857
    }

858 859 860
  if (!attr_len && !nlri_len)		/* shortcut */
    return;

861
  a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, nlri_len);
862
  if (a0 && nlri_len && bgp_set_next_hop(p, a0))
863
    {
864
      a = rta_lookup(a0);
865
      while (nlri_len)
866
	{
867
	  rte *e;
868
	  DECODE_PREFIX(nlri, nlri_len);
869
	  DBG("Add %I/%d\n", prefix, pxlen);
870
	  e = rte_get_temp(rta_clone(a));
Martin Mareš's avatar
Martin Mareš committed
871
	  n = net_get(p->p.table, prefix, pxlen);
872 873
	  e->net = n;
	  e->pflags = 0;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
874
	  rte_update(p->p.table, n, &p->p, &p->p, e);
875 876
	  if (bgp_apply_limits(p) < 0)
	    goto bad2;
877
	}
878
      rta_free(a);
879
    }
880 881 882 883 884 885

  return;

 bad:
  bgp_error(conn, 3, err, NULL, 0);
 bad2:
Martin Mareš's avatar
Martin Mareš committed
886 887
  if (a)
    rta_free(a);
888
  return;
Martin Mareš's avatar
Martin Mareš committed
889
}
890

Martin Mareš's avatar
Martin Mareš committed
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
#else			/* IPv6 version */

#define DO_NLRI(name)					\
  start = x = p->name##_start;				\
  len = len0 = p->name##_len;				\
  if (len)						\
    {							\
      if (len < 3) goto bad;				\
      af = get_u16(x);					\
      sub = x[2];					\
      x += 3;						\
      len -= 3;						\
      DBG("\tNLRI AF=%d sub=%d len=%d\n", af, sub, len);\
    }							\
  else							\
    af = 0;						\
  if (af == BGP_AF_IPV6)

static void
bgp_do_rx_update(struct bgp_conn *conn,
		 byte *withdrawn, int withdrawn_len,
		 byte *nlri, int nlri_len,
		 byte *attrs, int attr_len)
{
  struct bgp_proto *p = conn->bgp;
  byte *start, *x;
  int len, len0;
  unsigned af, sub;
  rta *a0;
  rta *a = NULL;
  ip_addr prefix;
  net *n;
  int err = 0, pxlen;

  p->mp_reach_len = 0;
  p->mp_unreach_len = 0;
  a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, 0);
  if (!a0)
    return;

  DO_NLRI(mp_unreach)
    {
      while (len)
	{
	  DECODE_PREFIX(x, len);
	  DBG("Withdraw %I/%d\n", prefix, pxlen);
	  if (n = net_find(p->p.table, prefix, pxlen))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
938
	    rte_update(p->p.table, n, &p->p, &p->p, NULL);
Martin Mareš's avatar
Martin Mareš committed
939 940 941 942 943 944 945 946 947
	}
    }

  DO_NLRI(mp_reach)
    {
      /* Create fake NEXT_HOP attribute */
      if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
	goto bad;

948
      ip_addr *nh = (ip_addr *) bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
949
      memcpy(nh, x+1, 16);
950 951 952 953 954 955 956 957 958 959
      ipa_ntoh(nh[0]);

      /* We store received link local address in the other part of BA_NEXT_HOP eattr. */
      if (*x == 32)
	{
	  memcpy(nh+1, x+17, 16);
	  ipa_ntoh(nh[1]);
	}
      else
	nh[1] = IPA_NONE;
960 961 962 963

      /* Also ignore one reserved byte */
      len -= *x + 2;
      x += *x + 2;
Martin Mareš's avatar
Martin Mareš committed
964

Ondřej Zajíček's avatar
Ondřej Zajíček committed
965
      if (bgp_set_next_hop(p, a0))
Martin Mareš's avatar
Martin Mareš committed
966 967 968 969 970 971 972 973 974 975 976
	{
	  a = rta_lookup(a0);
	  while (len)
	    {
	      rte *e;
	      DECODE_PREFIX(x, len);
	      DBG("Add %I/%d\n", prefix, pxlen);
	      e = rte_get_temp(rta_clone(a));
	      n = net_get(p->p.table, prefix, pxlen);
	      e->net = n;
	      e->pflags = 0;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
977
	      rte_update(p->p.table, n, &p->p, &p->p, e);
978 979
	      if (bgp_apply_limits(p) < 0)
		goto bad2;
Martin Mareš's avatar
Martin Mareš committed
980 981 982 983 984 985 986
	    }
	  rta_free(a);
	}
    }

  return;

987
 bad:
Martin Mareš's avatar
Martin Mareš committed
988
  bgp_error(conn, 3, 9, start, len0);
989
 bad2:
990 991
  if (a)
    rta_free(a);
Martin Mareš's avatar
Martin Mareš committed
992 993 994 995 996 997 998 999 1000 1001 1002 1003
  return;
}

#endif

static void
bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
{
  struct bgp_proto *p = conn->bgp;
  byte *withdrawn, *attrs, *nlri;
  int withdrawn_len, attr_len, nlri_len;

1004 1005
  BGP_TRACE_RL(&rl_rcv_update, D_PACKETS, "Got UPDATE");

1006 1007 1008 1009
  /* Workaround for some BGP implementations that skip initial KEEPALIVE */
  if (conn->state == BS_OPENCONFIRM)
    bgp_conn_enter_established_state(conn);

Martin Mareš's avatar
Martin Mareš committed
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
  if (conn->state != BS_ESTABLISHED)
    { bgp_error(conn, 5, 0, NULL, 0); return; }
  bgp_start_timer(conn->hold_timer, conn->hold_time);

  /* Find parts of the packet and check sizes */
  if (len < 23)
    {
      bgp_error(conn, 1, 2, pkt+16, 2);
      return;
    }
  withdrawn = pkt + 21;
  withdrawn_len = get_u16(pkt + 19);
  if (withdrawn_len + 23 > len)
    goto malformed;
  attrs = withdrawn + withdrawn_len + 2;
  attr_len = get_u16(attrs - 2);
  if (withdrawn_len + attr_len + 23 > len)
    goto malformed;
  nlri = attrs + attr_len;
  nlri_len = len - withdrawn_len - attr_len - 23;
  if (!attr_len && nlri_len)
    goto malformed;
  DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len);

  lp_flush(bgp_linpool);

  bgp_do_rx_update(conn, withdrawn, withdrawn_len, nlri, nlri_len, attrs, attr_len);
  return;

malformed:
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
  bgp_error(conn, 3, 1, NULL, 0);
}

static struct {
  byte major, minor;
  byte *msg;
} bgp_msg_table[] = {
  { 1, 0, "Invalid message header" },
  { 1, 1, "Connection not synchronized" },
  { 1, 2, "Bad message length" },
  { 1, 3, "Bad message type" },
  { 2, 0, "Invalid OPEN message" },
  { 2, 1, "Unsupported version number" },
  { 2, 2, "Bad peer AS" },
  { 2, 3, "Bad BGP identifier" },
  { 2, 4, "Unsupported optional parameter" },
  { 2, 5, "Authentication failure" },
  { 2, 6, "Unacceptable hold time" },
1058
  { 2, 7, "Required capability missing" }, /* [RFC3392] */
1059
  { 2, 8, "No supported AFI/SAFI" }, /* This error msg is nonstandard */
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
  { 3, 0, "Invalid UPDATE message" },
  { 3, 1, "Malformed attribute list" },
  { 3, 2, "Unrecognized well-known attribute" },
  { 3, 3, "Missing mandatory attribute" },
  { 3, 4, "Invalid attribute flags" },
  { 3, 5, "Invalid attribute length" },
  { 3, 6, "Invalid ORIGIN attribute" },
  { 3, 7, "AS routing loop" },		/* Deprecated */
  { 3, 8, "Invalid NEXT_HOP attribute" },
  { 3, 9, "Optional attribute error" },
  { 3, 10, "Invalid network field" },
  { 3, 11, "Malformed AS_PATH" },
  { 4, 0, "Hold timer expired" },
  { 5, 0, "Finite state machine error" },
1074 1075 1076 1077 1078 1079 1080 1081 1082
  { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */
  { 6, 1, "Maximum number of prefixes reached" },
  { 6, 2, "Administrative shutdown" },
  { 6, 3, "Peer de-configured" },
  { 6, 4, "Administrative reset" },
  { 6, 5, "Connection rejected" },
  { 6, 6, "Other configuration change" },
  { 6, 7, "Connection collision resolution" },
  { 6, 8, "Out of Resources" }
1083 1084
};

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1085 1086 1087 1088 1089 1090 1091 1092
/**
 * bgp_error_dsc - return BGP error description
 * @code: BGP error code
 * @subcode: BGP error subcode
 *
 * bgp_error_dsc() returns error description for BGP errors
 * which might be static string or given temporary buffer.
 */
1093 1094
const char *
bgp_error_dsc(unsigned code, unsigned subcode)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1095
{
1096
  static char buff[32];
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
  unsigned i;
  for (i=0; i < ARRAY_SIZE(bgp_msg_table); i++)
    if (bgp_msg_table[i].major == code && bgp_msg_table[i].minor == subcode)
      {
	return bgp_msg_table[i].msg;
      }

  bsprintf(buff, "Unknown error %d.%d", code, subcode);
  return buff;
}

1108
void
1109
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len)
1110
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1111
  const byte *name;
1112 1113 1114
  byte *t, argbuf[36];
  unsigned i;

1115 1116
  /* Don't report Cease messages generated by myself */
  if (code == 6 && class == BE_BGP_TX)
1117 1118
    return;

1119
  name = bgp_error_dsc(code, subcode);
1120 1121 1122 1123 1124
  t = argbuf;
  if (len)
    {
      *t++ = ':';
      *t++ = ' ';
1125 1126 1127 1128 1129 1130 1131

      if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))
	{
	  /* Bad peer AS - we would like to print the AS */
	  t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data));
	  goto done;
	}
1132 1133 1134 1135 1136
      if (len > 16)
	len = 16;
      for (i=0; i<len; i++)
	t += bsprintf(t, "%02x", data[i]);
    }
1137
 done:
1138 1139
  *t = 0;
  log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);
1140 1141 1142 1143 1144
}

static void
bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
{
1145
  struct bgp_proto *p = conn->bgp;
1146 1147
  if (len < 21)
    {
1148
      bgp_error(conn, 1, 2, pkt+16, 2);
1149 1150
      return;
    }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1151 1152 1153

  unsigned code = pkt[19];
  unsigned subcode = pkt[20];
1154
  int err = (code != 6);
1155

1156 1157
  bgp_log_error(p, BE_BGP_RX, "Received", code, subcode, pkt+21, len-21);
  bgp_store_error(p, conn, BE_BGP_RX, (code << 16) | subcode);
1158

1159
#ifndef IPV6
1160
  if ((code == 2) && ((subcode == 4) || (subcode == 7))
1161 1162 1163 1164
      /* Error related to capability:
       * 4 - Peer does not support capabilities at all.
       * 7 - Peer request some capability. Strange unless it is IPv6 only peer.
       */
1165 1166 1167 1168 1169 1170 1171 1172 1173
      && (p->cf->capabilities == 2)
      /* Capabilities are not explicitly enabled or disabled, therefore heuristic is used */
      && (conn->start_state == BSS_CONNECT)
      /* Failed connection attempt have used capabilities */
      && (p->cf->remote_as <= 0xFFFF))
      /* Not possible with disabled capabilities */
    {
      /* We try connect without capabilities */
      log(L_WARN "%s: Capability related error received, retry with capabilities disabled", p->p.name);
1174 1175
      p->start_state = BSS_CONNECT_NOCAP;
      err = 0;
1176 1177 1178
    }
#endif

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1179
  bgp_conn_enter_close_state(conn);
1180
  bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE);
1181 1182 1183 1184 1185 1186

  if (err) 
    {
      bgp_update_startup_delay(p);
      bgp_stop(p, 0);
    }
1187 1188 1189
}

static void
Martin Mareš's avatar
Martin Mareš committed
1190
bgp_rx_keepalive(struct bgp_conn *conn)
1191
{
Martin Mareš's avatar
Martin Mareš committed
1192 1193 1194
  struct bgp_proto *p = conn->bgp;

  BGP_TRACE(D_PACKETS, "Got KEEPALIVE");
1195 1196 1197 1198
  bgp_start_timer(conn->hold_timer, conn->hold_time);
  switch (conn->state)
    {
    case BS_OPENCONFIRM:
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1199
      bgp_conn_enter_established_state(conn);
1200 1201 1202 1203
      break;
    case BS_ESTABLISHED:
      break;
    default:
1204
      bgp_error(conn, 5, 0, NULL, 0);
1205 1206 1207
    }
}

1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
static void
bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len)
{
  struct bgp_proto *p = conn->bgp;

  BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");

  if (conn->state != BS_ESTABLISHED)
    { bgp_error(conn, 5, 0, NULL, 0); return; }

  if (!p->cf->enable_refresh)
    { bgp_error(conn, 1, 3, pkt+18, 1); return; }

  if (len != (BGP_HEADER_LENGTH + 4))
    { bgp_error(conn, 1, 2, pkt+16, 2); return; }

  /* FIXME - we ignore AFI/SAFI values, as we support
     just one value and even an error code for an invalid
     request is not defined */

  proto_request_feeding(&p->p);
}


Martin Mareš's avatar
Martin Mareš committed
1232 1233 1234 1235 1236 1237 1238 1239 1240
/**
 * bgp_rx_packet - handle a received packet
 * @conn: BGP connection
 * @pkt: start of the packet
 * @len: packet size
 *
 * bgp_rx_packet() takes a newly received packet and calls the corresponding
 * packet handler according to the packet type.
 */
1241 1242 1243
static void
bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
{
1244 1245 1246 1247 1248 1249 1250 1251
  byte type = pkt[18];

  DBG("BGP: Got packet %02x (%d bytes)\n", type, len);

  if (conn->bgp->p.mrtdump & MD_MESSAGES)
    mrt_dump_bgp_packet(conn, pkt, len);

  switch (type)
1252 1253 1254 1255
    {
    case PKT_OPEN:		return bgp_rx_open(conn, pkt, len);
    case PKT_UPDATE:		return bgp_rx_update(conn, pkt, len);
    case PKT_NOTIFICATION:      return bgp_rx_notification(conn, pkt, len);
Martin Mareš's avatar
Martin Mareš committed
1256
    case PKT_KEEPALIVE:		return bgp_rx_keepalive(conn);
1257
    case PKT_ROUTE_REFRESH:	return bgp_rx_route_refresh(conn, pkt, len);
1258
    default:			bgp_error(conn, 1, 3, pkt+18, 1);
1259
    }
1260 1261
}

Martin Mareš's avatar
Martin Mareš committed
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
/**
 * bgp_rx - handle received data
 * @sk: socket
 * @size: amount of data received
 *
 * bgp_rx() is called by the socket layer whenever new data arrive from
 * the underlying TCP connection. It assembles the data fragments to packets,
 * checks their headers and framing and passes complete packets to
 * bgp_rx_packet().
 */
1272 1273 1274 1275 1276 1277
int
bgp_rx(sock *sk, int size)
{
  struct bgp_conn *conn = sk->data;
  byte *pkt_start = sk->rbuf;
  byte *end = pkt_start + size;
1278
  unsigned i, len;
1279 1280 1281 1282

  DBG("BGP: RX hook: Got %d bytes\n", size);
  while (end >= pkt_start + BGP_HEADER_LENGTH)
    {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1283 1284
      if ((conn->state == BS_CLOSE) || (conn->sk != sk))
	return 0;
1285 1286 1287
      for(i=0; i<16; i++)
	if (pkt_start[i] != 0xff)
	  {
1288
	    bgp_error(conn, 1, 1, NULL, 0);
1289 1290 1291 1292 1293
	    break;
	  }
      len = get_u16(pkt_start+16);
      if (len < BGP_HEADER_LENGTH || len > BGP_MAX_PACKET_LENGTH)
	{
1294
	  bgp_error(conn, 1, 2, pkt_start+16, 2);
1295 1296
	  break;
	}
1297 1298 1299 1300
      if (end < pkt_start + len)
	break;
      bgp_rx_packet(conn, pkt_start, len);
      pkt_start += len;
1301 1302 1303 1304 1305 1306 1307 1308
    }
  if (pkt_start != sk->rbuf)
    {
      memmove(sk->rbuf, pkt_start, end - pkt_start);
      sk->rpos = sk->rbuf + (end - pkt_start);
    }
  return 0;
}