예제 #1
0
파일: ospf_dump.c 프로젝트: ton31337/frr
static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length)
{
	uint32_t sp;
	uint32_t ls_type;
	struct in_addr ls_id;
	struct in_addr adv_router;

	sp = stream_get_getp(s);

	length -= OSPF_HEADER_SIZE;

	zlog_debug("Link State Request");
	zlog_debug("  # Requests %d", length / 12);

	for (; length > 0; length -= 12) {
		ls_type = stream_getl(s);
		ls_id.s_addr = stream_get_ipv4(s);
		adv_router.s_addr = stream_get_ipv4(s);

		zlog_debug("  LS type %d", ls_type);
		zlog_debug("  Link State ID %s", inet_ntoa(ls_id));
		zlog_debug("  Advertising Router %s", inet_ntoa(adv_router));
	}

	stream_set_getp(s, sp);
}
예제 #2
0
파일: ospf_dump.c 프로젝트: ton31337/frr
static void ospf_packet_db_desc_dump(struct stream *s, uint16_t length)
{
	struct ospf_db_desc *dd;
	char dd_flags[8];

	uint32_t gp;

	gp = stream_get_getp(s);
	dd = (struct ospf_db_desc *)stream_pnt(s);

	zlog_debug("Database Description");
	zlog_debug("  Interface MTU %d", ntohs(dd->mtu));
	zlog_debug("  Options %d (%s)", dd->options,
		   ospf_options_dump(dd->options));
	zlog_debug("  Flags %d (%s)", dd->flags,
		   ospf_dd_flags_dump(dd->flags, dd_flags, sizeof dd_flags));
	zlog_debug("  Sequence Number 0x%08lx",
		   (unsigned long)ntohl(dd->dd_seqnum));

	length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE;

	stream_forward_getp(s, OSPF_DB_DESC_MIN_SIZE);

	ospf_lsa_header_list_dump(s, length);

	stream_set_getp(s, gp);
}
예제 #3
0
int
isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
{

    int written = 1;
    struct sockaddr_ll sa;

    stream_set_getp (circuit->snd_stream, 0);
    memset (&sa, 0, sizeof (struct sockaddr_ll));
    sa.sll_family = AF_PACKET;
    sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
    sa.sll_ifindex = circuit->interface->ifindex;
    sa.sll_halen = ETH_ALEN;
    if (level == 1)
        memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
    else
        memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);


    /* lets try correcting the protocol */
    sa.sll_protocol = htons (0x00FE);
    written = sendto (circuit->fd, circuit->snd_stream->data,
                      stream_get_endp (circuit->snd_stream), 0,
                      (struct sockaddr *) &sa,
                      sizeof (struct sockaddr_ll));

    return ISIS_OK;
}
예제 #4
0
/*EIGRP SIA-QUERY read function*/
void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
			    struct eigrp_header *eigrph, struct stream *s,
			    struct eigrp_interface *ei, int size)
{
	struct eigrp_neighbor *nbr;
	struct TLV_IPv4_Internal_type *tlv;

	uint16_t type;

	/* increment statistics. */
	ei->siaQuery_in++;

	/* get neighbor struct */
	nbr = eigrp_nbr_get(ei, eigrph, iph);

	/* neighbor must be valid, eigrp_nbr_get creates if none existed */
	assert(nbr);

	nbr->recv_sequence_number = ntohl(eigrph->sequence);

	while (s->endp > s->getp) {
		type = stream_getw(s);
		if (type == EIGRP_TLV_IPv4_INT) {
			struct prefix dest_addr;

			stream_set_getp(s, s->getp - sizeof(uint16_t));

			tlv = eigrp_read_ipv4_tlv(s);

			dest_addr.family = AFI_IP;
			dest_addr.u.prefix4 = tlv->destination;
			dest_addr.prefixlen = tlv->prefix_length;
			struct eigrp_prefix_entry *dest =
				eigrp_topology_table_lookup_ipv4(
					eigrp->topology_table, &dest_addr);

			/* If the destination exists (it should, but one never
			 * know)*/
			if (dest != NULL) {
				struct eigrp_fsm_action_message msg;
				struct eigrp_nexthop_entry *entry =
					eigrp_prefix_entry_lookup(dest->entries,
								  nbr);
				msg.packet_type = EIGRP_OPC_SIAQUERY;
				msg.eigrp = eigrp;
				msg.data_type = EIGRP_INT;
				msg.adv_router = nbr;
				msg.metrics = tlv->metric;
				msg.entry = entry;
				msg.prefix = dest;
				eigrp_fsm_event(&msg);
			}
			eigrp_IPv4_InternalTLV_free(tlv);
		}
	}
	eigrp_hello_send_ack(nbr);
}
예제 #5
0
int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
{
	dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl;
	char *dstaddr;
	unsigned short *dstsap;
	int buflen;
	int rv;

	buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN;
	if ((size_t)buflen > sizeof(sock_buff)) {
		zlog_warn(
			"isis_send_pdu_bcast: sock_buff size %zu is less than "
			"output pdu size %d on circuit %s",
			sizeof(sock_buff), buflen, circuit->interface->name);
		return ISIS_WARNING;
	}

	stream_set_getp(circuit->snd_stream, 0);

	memset(dur, 0, sizeof(*dur));
	dur->dl_primitive = DL_UNITDATA_REQ;
	dur->dl_dest_addr_length = ETHERADDRL + 2;
	dur->dl_dest_addr_offset = sizeof(*dur);

	dstaddr = (char *)(dur + 1);
	if (circuit->sap_length < 0) {
		dstsap = (unsigned short *)(dstaddr + ETHERADDRL);
	} else {
		dstsap = (unsigned short *)dstaddr;
		dstaddr += circuit->sap_length;
	}
	if (level == 1)
		memcpy(dstaddr, ALL_L1_ISS, ETHERADDRL);
	else
		memcpy(dstaddr, ALL_L2_ISS, ETHERADDRL);
	/* Note: DLPI SAP values are in host byte order */
	*dstsap = buflen;

	sock_buff[0] = ISO_SAP;
	sock_buff[1] = ISO_SAP;
	sock_buff[2] = 0x03;
	memcpy(sock_buff + LLC_LEN, circuit->snd_stream->data,
	       stream_get_endp(circuit->snd_stream));
	rv = dlpisend(circuit->fd, dur, sizeof(*dur) + dur->dl_dest_addr_length,
		      sock_buff, buflen, 0);
	if (rv < 0) {
		zlog_warn("IS-IS dlpi: could not transmit packet on %s: %s",
			  circuit->interface->name, safe_strerror(errno));
		if (ERRNO_IO_RETRY(errno))
			return ISIS_WARNING;
		return ISIS_ERROR;
	}

	return ISIS_OK;
}
예제 #6
0
파일: ospf_dump.c 프로젝트: ton31337/frr
static void ospf_packet_ls_ack_dump(struct stream *s, uint16_t length)
{
	uint32_t sp;

	length -= OSPF_HEADER_SIZE;
	sp = stream_get_getp(s);

	zlog_debug("Link State Acknowledgment");
	ospf_lsa_header_list_dump(s, length);

	stream_set_getp(s, sp);
}
예제 #7
0
/* basic parsing test */
static void
parse_test (struct peer *peer, struct test_segment *t, int type)
{
  int ret;
  int oldfailed = failed;
  struct attr attr;
  struct bgp_nlri nlri;
#define RANDOM_FUZZ 35
  
  stream_reset (peer->ibuf);
  stream_put (peer->ibuf, NULL, RANDOM_FUZZ);
  stream_set_getp (peer->ibuf, RANDOM_FUZZ);
  
  stream_write (peer->ibuf, t->data, t->len);
  
  printf ("%s: %s\n", t->name, t->desc);

  if (type == BGP_ATTR_MP_REACH_NLRI)
    ret = bgp_mp_reach_parse (peer, t->len, &attr, BGP_ATTR_FLAG_OPTIONAL, BGP_INPUT_PNT (peer), &nlri);
  else
    ret = bgp_mp_unreach_parse (peer, t->len, BGP_ATTR_FLAG_OPTIONAL, BGP_INPUT_PNT (peer), &nlri);

  if (!ret)
    {
      safi_t safi = t->safi;
      
      if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid)
        failed++;
      
      printf ("MP: %u/%u (%u): recv %u, nego %u\n",
              t->afi, t->safi, safi,
              peer->afc_recv[t->afi][safi],
              peer->afc_nego[t->afi][safi]);
    }
  
  printf ("parsed?: %s\n", ret ? "no" : "yes");
  
  if (ret != t->parses)
    failed++;
  
  if (tty)
    printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET 
                                         : VT100_GREEN "OK" VT100_RESET);
  else
    printf ("%s", (failed > oldfailed) ? "failed!" : "OK" );
  
  if (failed)
    printf (" (%u)", failed);
  
  printf ("\n\n");
}
예제 #8
0
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
  struct msghdr msg;
  struct iovec iov[2];

  /* we need to do the LLC in here because of P2P circuits, which will
   * not need it
   */
  int written = 1;
  struct sockaddr_ll sa;

  stream_set_getp (circuit->snd_stream, 0);
  memset (&sa, 0, sizeof (struct sockaddr_ll));
  sa.sll_family = AF_PACKET;
  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  sa.sll_ifindex = circuit->interface->ifindex;
  sa.sll_halen = ETH_ALEN;
  /* RFC5309 section 4.1 recommends ALL_ISS */
  if (circuit->circ_type == CIRCUIT_T_P2P)
    memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
  else if (level == 1)
    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  else
    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);

  /* on a broadcast circuit */
  /* first we put the LLC in */
  sock_buff[0] = 0xFE;
  sock_buff[1] = 0xFE;
  sock_buff[2] = 0x03;

  memset (&msg, 0, sizeof (msg));
  msg.msg_name = &sa;
  msg.msg_namelen = sizeof (struct sockaddr_ll);
  msg.msg_iov = iov;
  msg.msg_iovlen = 2;
  iov[0].iov_base = sock_buff;
  iov[0].iov_len = LLC_LEN;
  iov[1].iov_base = circuit->snd_stream->data;
  iov[1].iov_len = stream_get_endp (circuit->snd_stream);

  written = sendmsg (circuit->fd, &msg, 0);

  return ISIS_OK;
}
예제 #9
0
int
isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
{
    int bytesread = 0, bytestoread, offset, one = 1;
    struct bpf_hdr *bpf_hdr;

    assert (circuit->fd > 0);

    if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0)
    {
        zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno));
    }

    if (bytestoread)
    {
        bytesread = read (circuit->fd, readbuff, readblen);
    }
    if (bytesread < 0)
    {
        zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s",
                   safe_strerror (errno));
        return ISIS_WARNING;
    }

    if (bytesread == 0)
        return ISIS_WARNING;

    bpf_hdr = (struct bpf_hdr *) readbuff;

    assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);

    offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;

    /* then we lose the BPF, LLC and ethernet headers */
    stream_write (circuit->rcv_stream, readbuff + offset,
                  bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
    stream_set_getp (circuit->rcv_stream, 0);

    memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
            ETHER_ADDR_LEN);

    if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0)
        zlog_warn ("Flushing failed: %s", safe_strerror (errno));

    return ISIS_OK;
}
예제 #10
0
파일: isis_bpf.c 프로젝트: AsherBond/quagga
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
  struct ether_header *eth;
  int written, buflen;

  buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
  if (buflen > sizeof (sock_buff))
    {
      zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than "
		 "output pdu size %d on circuit %s",
		 sizeof (sock_buff), buflen, circuit->interface->name);
      return ISIS_WARNING;
    }

  stream_set_getp (circuit->snd_stream, 0);

  /*
   * First the eth header
   */
  eth = (struct ether_header *) sock_buff;
  if (level == 1)
    memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
  else
    memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
  memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
  eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);

  /*
   * Then the LLC
   */
  sock_buff[ETHER_HDR_LEN] = ISO_SAP;
  sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
  sock_buff[ETHER_HDR_LEN + 2] = 0x03;

  /* then we copy the data */
  memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
	  stream_get_endp (circuit->snd_stream));

  /* now we can send this */
  written = write (circuit->fd, sock_buff, buflen);

  return ISIS_OK;
}
예제 #11
0
파일: ospf_dump.c 프로젝트: ton31337/frr
void ospf_packet_dump(struct stream *s)
{
	struct ospf_header *ospfh;
	unsigned long gp;

	/* Preserve pointer. */
	gp = stream_get_getp(s);

	/* OSPF Header dump. */
	ospfh = (struct ospf_header *)stream_pnt(s);

	/* Until detail flag is set, return. */
	if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL))
		return;

	/* Show OSPF header detail. */
	ospf_header_dump(ospfh);
	stream_forward_getp(s, OSPF_HEADER_SIZE);

	switch (ospfh->type) {
	case OSPF_MSG_HELLO:
		ospf_packet_hello_dump(s, ntohs(ospfh->length));
		break;
	case OSPF_MSG_DB_DESC:
		ospf_packet_db_desc_dump(s, ntohs(ospfh->length));
		break;
	case OSPF_MSG_LS_REQ:
		ospf_packet_ls_req_dump(s, ntohs(ospfh->length));
		break;
	case OSPF_MSG_LS_UPD:
		ospf_packet_ls_upd_dump(s, ntohs(ospfh->length));
		break;
	case OSPF_MSG_LS_ACK:
		ospf_packet_ls_ack_dump(s, ntohs(ospfh->length));
		break;
	default:
		break;
	}

	stream_set_getp(s, gp);
}
예제 #12
0
static void
print_stream (struct stream *s)
{
  size_t getp = stream_get_getp (s);
  
  printf ("endp: %zu, readable: %zu, writeable: %zu\n",
          stream_get_endp (s),
          STREAM_READABLE (s),
          STREAM_WRITEABLE (s));
  
  while (STREAM_READABLE (s))
    {
      printf ("0x%x ", *stream_pnt (s));
      stream_forward_getp (s, 1);
    }
  
  printf ("\n");
  
  /* put getp back to where it was */
  stream_set_getp (s, getp);
}
예제 #13
0
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
    struct ether_header *eth;
    int written;

    stream_set_getp (circuit->snd_stream, 0);

    /*
     * First the eth header
     */
    eth = (struct ether_header *) sock_buff;
    if (level == 1)
        memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
    else
        memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
    memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
    eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);

    /*
     * Then the LLC
     */
    sock_buff[ETHER_HDR_LEN] = ISO_SAP;
    sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
    sock_buff[ETHER_HDR_LEN + 2] = 0x03;

    /* then we copy the data */
    memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
            stream_get_endp (circuit->snd_stream));

    /* now we can send this */
    written = write (circuit->fd, sock_buff,
                     stream_get_endp (circuit->snd_stream)
                     + LLC_LEN + ETHER_HDR_LEN);

    return ISIS_OK;
}
예제 #14
0
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
    /* we need to do the LLC in here because of P2P circuits, which will
     * not need it
     */
    int written = 1;
    struct sockaddr_ll sa;

    stream_set_getp (circuit->snd_stream, 0);
    memset (&sa, 0, sizeof (struct sockaddr_ll));
    sa.sll_family = AF_PACKET;
    sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
    sa.sll_ifindex = circuit->interface->ifindex;
    sa.sll_halen = ETH_ALEN;
    if (level == 1)
        memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
    else
        memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);

    /* on a broadcast circuit */
    /* first we put the LLC in */
    sock_buff[0] = 0xFE;
    sock_buff[1] = 0xFE;
    sock_buff[2] = 0x03;

    /* then we copy the data */
    memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
            stream_get_endp (circuit->snd_stream));

    /* now we can send this */
    written = sendto (circuit->fd, sock_buff,
                      stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
                      (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));

    return ISIS_OK;
}
예제 #15
0
파일: zserv.c 프로젝트: MichaelQQ/Quagga-PE
/* Handler of zebra service request. */
static int
zebra_client_read (struct thread *thread)
{
  int sock;
  struct zserv *client;
  size_t already;
  uint16_t length, command;
  uint8_t marker, version;

  /* Get thread data.  Reset reading thread because I'm running. */
  sock = THREAD_FD (thread);
  client = THREAD_ARG (thread);
  client->t_read = NULL;

  if (client->t_suicide)
    {
      zebra_client_close(client);
      return -1;
    }

  /* Read length and command (if we don't have it already). */
  if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE)
    {
      ssize_t nbyte;
      if (((nbyte = stream_read_try (client->ibuf, sock,
				     ZEBRA_HEADER_SIZE-already)) == 0) ||
	  (nbyte == -1))
	{
	  if (IS_ZEBRA_DEBUG_EVENT)
	    zlog_debug ("connection closed socket [%d]", sock);
	  zebra_client_close (client);
	  return -1;
	}
      if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already))
	{
	  /* Try again later. */
	  zebra_event (ZEBRA_READ, sock, client);
	  return 0;
	}
      already = ZEBRA_HEADER_SIZE;
    }

  /* Reset to read from the beginning of the incoming packet. */
  stream_set_getp(client->ibuf, 0);

  /* Fetch header values */
  length = stream_getw (client->ibuf);
  marker = stream_getc (client->ibuf);
  version = stream_getc (client->ibuf);
  command = stream_getw (client->ibuf);

  if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION)
    {
      zlog_err("%s: socket %d version mismatch, marker %d, version %d",
               __func__, sock, marker, version);
      zebra_client_close (client);
      return -1;
    }
  if (length < ZEBRA_HEADER_SIZE) 
    {
      zlog_warn("%s: socket %d message length %u is less than header size %d",
	        __func__, sock, length, ZEBRA_HEADER_SIZE);
      zebra_client_close (client);
      return -1;
    }
  if (length > STREAM_SIZE(client->ibuf))
    {
      zlog_warn("%s: socket %d message length %u exceeds buffer size %lu",
	        __func__, sock, length, (u_long)STREAM_SIZE(client->ibuf));
      zebra_client_close (client);
      return -1;
    }

  /* Read rest of data. */
  if (already < length)
    {
      ssize_t nbyte;
      if (((nbyte = stream_read_try (client->ibuf, sock,
				     length-already)) == 0) ||
	  (nbyte == -1))
	{
	  if (IS_ZEBRA_DEBUG_EVENT)
	    zlog_debug ("connection closed [%d] when reading zebra data", sock);
	  zebra_client_close (client);
	  return -1;
	}
      if (nbyte != (ssize_t)(length-already))
        {
	  /* Try again later. */
	  zebra_event (ZEBRA_READ, sock, client);
	  return 0;
	}
    }

  length -= ZEBRA_HEADER_SIZE;

  /* Debug packet information. */
  if (IS_ZEBRA_DEBUG_EVENT)
    zlog_debug ("zebra message comes from socket [%d]", sock);

  if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
    zlog_debug ("zebra message received [%s] %d", 
	       zserv_command_string (command), length);

  switch (command) 
    {
    case ZEBRA_ROUTER_ID_ADD:
      zread_router_id_add (client, length);
      break;
    case ZEBRA_ROUTER_ID_DELETE:
      zread_router_id_delete (client, length);
      break;
    case ZEBRA_INTERFACE_ADD:
      zread_interface_add (client, length);
      break;
    case ZEBRA_INTERFACE_DELETE:
      zread_interface_delete (client, length);
      break;
    case ZEBRA_IPV4_ROUTE_ADD:
      zread_ipv4_add (client, length);
      break;
    case ZEBRA_IPV4_ROUTE_DELETE:
      zread_ipv4_delete (client, length);
      break;
#ifdef HAVE_IPV6
    case ZEBRA_IPV6_ROUTE_ADD:
      zread_ipv6_add (client, length);
      break;
    case ZEBRA_IPV6_ROUTE_DELETE:
      zread_ipv6_delete (client, length);
      break;
#endif /* HAVE_IPV6 */
    case ZEBRA_REDISTRIBUTE_ADD:
      zebra_redistribute_add (command, client, length);
      break;
    case ZEBRA_REDISTRIBUTE_DELETE:
      zebra_redistribute_delete (command, client, length);
      break;
    case ZEBRA_REDISTRIBUTE_DEFAULT_ADD:
      zebra_redistribute_default_add (command, client, length);
      break;
    case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE:
      zebra_redistribute_default_delete (command, client, length);
      break;
    case ZEBRA_IPV4_NEXTHOP_LOOKUP:
      zread_ipv4_nexthop_lookup (client, length);
      break;
#ifdef HAVE_IPV6
    case ZEBRA_IPV6_NEXTHOP_LOOKUP:
      zread_ipv6_nexthop_lookup (client, length);
      break;
#endif /* HAVE_IPV6 */
    case ZEBRA_IPV4_IMPORT_LOOKUP:
      zread_ipv4_import_lookup (client, length);
      break;
    case ZEBRA_HELLO:
      zread_hello (client);
      break;
    default:
      zlog_info ("Zebra received unknown command %d", command);
      break;
    }

  if (client->t_suicide)
    {
      /* No need to wait for thread callback, just kill immediately. */
      zebra_client_close(client);
      return -1;
    }

  stream_reset (client->ibuf);
  zebra_event (ZEBRA_READ, sock, client);
  return 0;
}
예제 #16
0
파일: ospf_dump.c 프로젝트: ton31337/frr
static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length)
{
	uint32_t sp;
	struct lsa_header *lsa;
	int lsa_len;
	uint32_t count;

	length -= OSPF_HEADER_SIZE;

	sp = stream_get_getp(s);

	count = stream_getl(s);
	length -= 4;

	zlog_debug("Link State Update");
	zlog_debug("  # LSAs %d", count);

	while (length > 0 && count > 0) {
		if (length < OSPF_HEADER_SIZE || length % 4 != 0) {
			zlog_debug("  Remaining %d bytes; Incorrect length.",
				   length);
			break;
		}

		lsa = (struct lsa_header *)stream_pnt(s);
		lsa_len = ntohs(lsa->length);
		ospf_lsa_header_dump(lsa);

		switch (lsa->type) {
		case OSPF_ROUTER_LSA:
			ospf_router_lsa_dump(s, length);
			break;
		case OSPF_NETWORK_LSA:
			ospf_network_lsa_dump(s, length);
			break;
		case OSPF_SUMMARY_LSA:
		case OSPF_ASBR_SUMMARY_LSA:
			ospf_summary_lsa_dump(s, length);
			break;
		case OSPF_AS_EXTERNAL_LSA:
			ospf_as_external_lsa_dump(s, length);
			break;
		case OSPF_AS_NSSA_LSA:
			ospf_as_external_lsa_dump(s, length);
			break;
		case OSPF_OPAQUE_LINK_LSA:
		case OSPF_OPAQUE_AREA_LSA:
		case OSPF_OPAQUE_AS_LSA:
			ospf_opaque_lsa_dump(s, length);
			break;
		default:
			break;
		}

		stream_forward_getp(s, lsa_len);
		length -= lsa_len;
		count--;
	}

	stream_set_getp(s, sp);
}
예제 #17
0
파일: sv_sisis.c 프로젝트: ecks/sis-is
int
shim_sisis_read(struct thread * thread)
{
  struct sisis_listener *listener;
  int sisis_sock;
  uint16_t length, command, checksum;
  int already;
  u_int ifindex;
  struct shim_interface * si;
  struct in6_addr src;
  char src_buf[INET6_ADDRSTRLEN];
  struct in6_addr dst;
  char dst_buf[INET6_ADDRSTRLEN];

  zlog_notice("Reading packet from SISIS connection!\n");

  /* first of all get listener pointer. */
  listener = THREAD_ARG (thread);
  sisis_sock = THREAD_FD (thread);

  if ((already = stream_get_endp(listener->ibuf)) < SV_HEADER_SIZE)
  {
    ssize_t nbytes;
    if (((nbytes = stream_read_try (listener->ibuf, sisis_sock, SV_HEADER_SIZE-already)) == 0) || (nbytes == -1))
    {
      return -1;
    }

    if(nbytes != (SV_HEADER_SIZE - already))
    {
      listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);
      return 0;
    }
    already = SV_HEADER_SIZE;
  }

  stream_set_getp(listener->ibuf, 0);

  /* read header packet. */
  length = stream_getw (listener->ibuf);
  command = stream_getw (listener->ibuf);

  // will be 0 so may be discarded
  stream_get (&src, listener->ibuf, sizeof (struct in6_addr));
  stream_get (&dst, listener->ibuf, sizeof (struct in6_addr));

  ifindex = stream_getl(listener->ibuf);
  checksum = stream_getw(listener->ibuf);

  inet_ntop(AF_INET6, &src, src_buf, sizeof(src_buf));
  inet_ntop(AF_INET6, &dst, dst_buf, sizeof(dst_buf));

  zlog_debug("SISIS: length: %d, command: %d, ifindex: %d, checksum: %d sock %d, src: %s, dst: %s\n", length, command, ifindex, checksum, sisis_sock, src_buf, dst_buf);

  if(length > STREAM_SIZE(listener->ibuf))
  {
    struct stream * ns;
    zlog_warn("message size exceeds buffer size");
    ns = stream_new(length);
    stream_copy(ns, listener->ibuf);
    stream_free(listener->ibuf);
    listener->ibuf = ns;
  }

  if(already < length)
  {
    ssize_t nbytes;
    if(((nbytes = stream_read_try(listener->ibuf, sisis_sock, length-already)) == 0) || nbytes == -1)
    {
      return -1;
    }
    if(nbytes != (length-already))
    {
      listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);
      return 0;
    }
  }

  length -= SV_HEADER_SIZE;

  switch(command)
  {
    case SV_JOIN_ALLSPF:
      zlog_debug("join allspf received");
      shim_join_allspfrouters (ifindex);
      break;
    case SV_LEAVE_ALLSPF:
      zlog_debug("leave allspf received");
      shim_leave_allspfrouters (ifindex);
      zlog_debug("index: %d\n", ifindex);
      break;
    case SV_JOIN_ALLD:
      zlog_debug("join alld received");
      shim_join_alldrouters (ifindex);
      zlog_debug("index: %d", ifindex);
      break;
    case SV_LEAVE_ALLD:
      zlog_debug("leave alld received");
      shim_leave_alldrouters (ifindex);
      zlog_debug("index: %d", ifindex);
      break;
    case SV_MESSAGE:
      zlog_debug("SISIS message received");
      unsigned int num_of_addrs = number_of_sisis_addrs_for_process_type(SISIS_PTYPE_RIBCOMP_OSPF6);
      unsigned int num_of_listeners = number_of_listeners();
      zlog_debug("num of listeners: %d, num of addrs: %d", num_of_listeners, num_of_addrs);
      float received_ratio = num_of_listeners/num_of_addrs;
      listener->chksum = checksum;
      if(received_ratio > (1/2))
      {
        if(are_checksums_same())
        {
          si = shim_interface_lookup_by_ifindex (ifindex);
          reset_checksums();
          shim_send(&src, &dst, si, listener->ibuf, length);
//          shim_send(si->linklocal_addr, &dst, si, listener->ibuf, length);
        }
        else
        {
          zlog_notice("Checksums are not all the same");
        }
      }
      else
      {
        zlog_notice("Not enough processes have sent their data: buffering ...");
      }
      break;
    default:
      break;
  }

  if (sisis_sock < 0)
    /* Connection was closed during packet processing. */
    return -1;

  /* Register read thread. */
  stream_reset(listener->ibuf);

  /* prepare for next packet. */
  listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);

  return 0;
}
예제 #18
0
파일: svz_tunnel.c 프로젝트: ecks/sis-is
static int
svz_tunnel_read(struct thread * thread)
{
  uint16_t length, command;
  uint8_t marker, version;
  struct stream * dbuf;
  int ret;
  size_t already;
  struct tclient * tclient;

  zlog_notice("Reading packet from Zebra!");

  /* Get socket to zebra. */
  tclient = THREAD_ARG (thread);
  tclient->t_read = NULL;

  stream_reset(tclient->ibuf);

  /* Read zebra header (if we don't have it already). */
  if ((already = stream_get_endp(tclient->ibuf)) < ZEBRA_HEADER_SIZE)
  {
    ssize_t nbyte;
    if (((nbyte = stream_read_try(tclient->ibuf, tclient->sock,
                                   ZEBRA_HEADER_SIZE-already)) == 0) ||
        (nbyte == -1))
    {
      return svz_tunnel_failed(tclient);
    }
    if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already))
    {
      /* Try again later. */
      svz_tunnel_event (TCLIENT_READ, tclient);
      return 0;
    }
    already = ZEBRA_HEADER_SIZE;   
  }

  dbuf = stream_dup(tclient->ibuf);

  stream_set_getp(dbuf, 0);

  length = stream_getw(dbuf);
  marker = stream_getc(dbuf);
  version = stream_getc(dbuf);
  command = stream_getw(dbuf);
 
  if(already < length)
  {
    ssize_t nbyte;
    if (((nbyte = stream_read_try(tclient->ibuf, tclient->sock,
                                  length-already)) == 0) ||
       (nbyte == -1)) 
     {       
         zlog_debug("zebra connection closed socket [%d].", tclient->sock);
         return svz_tunnel_failed(tclient);
     }        
     if (nbyte != (ssize_t)(length-already))
     {        
       /* Try again later. */
       svz_tunnel_event (TCLIENT_READ, tclient);
       return 0;
     }
  }

  stream_free(dbuf);

  shim_receive(tclient);

  svz_tunnel_event(TCLIENT_READ, tclient);

  return 0;
}
예제 #19
0
파일: svz_sisis.c 프로젝트: ecks/sis-is
int
shim_sisis_read(struct thread * thread)
{
  struct sisis_listener *listener;
  int sisis_sock;
  uint16_t length, checksum;
  int already;
  u_int ifindex;
  struct shim_interface * si;
  struct in6_addr src;
  char src_buf[INET6_ADDRSTRLEN];
  struct in6_addr dst;
  char dst_buf[INET6_ADDRSTRLEN];

  zlog_notice("Reading packet from SISIS connection!");

  /* first of all get listener pointer. */
  listener = THREAD_ARG (thread);
  sisis_sock = THREAD_FD (thread);

  stream_reset(listener->ibuf);

  if ((already = stream_get_endp(listener->ibuf)) < SVZ_OUT_HEADER_SIZE)
  {
    ssize_t nbytes;
    if (((nbytes = stream_read_try (listener->ibuf, sisis_sock, SVZ_OUT_HEADER_SIZE-already)) == 0) || (nbytes == -1))
    {
      return -1;
    }

    if(nbytes != (SVZ_OUT_HEADER_SIZE - already))
    {
      listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);
      return 0;
    }

    already = SVZ_OUT_HEADER_SIZE;
  }

  stream_set_getp(listener->ibuf, 0);

  length = stream_getw(listener->ibuf);
  checksum = stream_getw(listener->ibuf);

  if(length > STREAM_SIZE(listener->ibuf))
  {
    struct stream * ns; 
    zlog_warn("message size exceeds buffer size");
    ns = stream_new(length);
    stream_copy(ns, listener->ibuf);
    stream_free(listener->ibuf);
    listener->ibuf = ns; 
  }

  if(already < length)
  {
    ssize_t nbytes;
    if(((nbytes = stream_read_try(listener->ibuf, sisis_sock, length-already)) == 0) || nbytes == -1) 
    {   
      return -1; 
    }   
    if(nbytes != (length-already))
    {   
      listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);
      return 0;
    }   
  } 

  unsigned int num_of_addrs = number_of_sisis_addrs_for_process_type(SISIS_PTYPE_RIBCOMP_OSPF6);
  unsigned int num_of_listeners = number_of_listeners();
 
  zlog_notice("Number of addr: %d", num_of_addrs);
  zlog_notice("Number of listeners: %d", num_of_listeners);

  pthread_mutex_lock(&bmap_mutex);
  struct bmap * bmap = bmap_set(checksum);

  // if we added initially
  // set timer at which to recycle bmap 
  // if there are no more processes sending data
  if(bmap->count == 0)
  {
    uint16_t * chcksum_ptr = malloc(sizeof(uint16_t));
    *chcksum_ptr = checksum;
  
    listener->bmap_thread = thread_add_timer_msec (master, svz_sisis_clean_bmap, chcksum_ptr, 100);
  }

  bmap->count++;
  zlog_notice("# of streams %d for checksum %d with length %d", bmap->count, checksum, length);
 
  float received_ratio = (float)bmap->count/(float)num_of_addrs;
  stream_putw(listener->chksum_stream, checksum);
  if((received_ratio > 1.0/2.0) && !bmap->sent)
  {
    if(are_checksums_same())
    {
      zlog_notice("Checksums are all the same");

    if(primary_listener == NULL)
      primary_listener = listener;

    reset_checksum_streams();
    svz_send(listener->ibuf);
    bmap->sent = 1;
    }
    else
    {
      zlog_notice("Checksums are not all the same");
      stream_fifo_push(listener->dif, listener->ibuf);
      listener->dif_size++;
    }
  }
  else if(!bmap->sent)
  {
    zlog_notice("Not enough processes have sent their data; buffering...");
  }
  else
  {
    zlog_notice("Data has already been sent...");
  }

  if((bmap->count == num_of_addrs) && (bmap->sent))
  {
    zlog_notice("Bmap no longer needed, freeing...");

    bmap->count = 0;
    bmap->sent = 0;

    clear_checksum_streams(checksum);
    bmap_unset(checksum);
  } 
  pthread_mutex_unlock(&bmap_mutex);

  if (sisis_sock < 0) 
    /* Connection was closed during packet processing. */
    return -1; 

  /* Register read thread. */
//  stream_reset(listener->ibuf);

  /* prepare for next packet. */
  listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock);

  return 0;
}
예제 #20
0
/*EIGRP QUERY read function*/
void
eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
                     struct stream * s, struct eigrp_interface *ei, int size)
{
  struct eigrp_neighbor *nbr;
  struct TLV_IPv4_Internal_type *tlv;
  struct eigrp_prefix_entry *temp_tn;
  struct eigrp_neighbor_entry *temp_te;

  u_int16_t type;

  /* increment statistics. */
  ei->query_in++;

  /* get neighbor struct */
  nbr = eigrp_nbr_get(ei, eigrph, iph);

  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
  assert(nbr);

  nbr->recv_sequence_number = ntohl(eigrph->sequence);

  while (s->endp > s->getp)
    {
      type = stream_getw(s);
      if (type == EIGRP_TLV_IPv4_INT)
        {
          stream_set_getp(s, s->getp - sizeof(u_int16_t));

          tlv = eigrp_read_ipv4_tlv(s);

          struct prefix_ipv4 *dest_addr;
          dest_addr = prefix_ipv4_new();
          dest_addr->prefix = tlv->destination;
          dest_addr->prefixlen = tlv->prefix_length;
          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
              eigrp->topology_table, dest_addr);

          /* If the destination exists (it should, but one never know)*/
          if (dest != NULL)
            {
              struct eigrp_fsm_action_message *msg;
              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
                  sizeof(struct eigrp_fsm_action_message));
              struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
                  dest->entries, nbr);
              msg->packet_type = EIGRP_OPC_QUERY;
              msg->eigrp = eigrp;
              msg->data_type = EIGRP_TLV_IPv4_INT;
              msg->adv_router = nbr;
              msg->data.ipv4_int_type = tlv;
              msg->entry = entry;
              msg->prefix = dest;
              int event = eigrp_get_fsm_event(msg);
              eigrp_fsm_event(msg, event);
            }
          eigrp_IPv4_InternalTLV_free (tlv);
        }
    }
  eigrp_hello_send_ack(nbr);
  eigrp_query_send_all(eigrp);
  eigrp_update_send_all(eigrp,nbr->ei);
}
예제 #21
0
/* basic parsing test */
static void
parse_test (struct peer *peer, struct test_segment *t, int type)
{
  int ret;
  int capability = 0;
  as_t as4 = 0;
  int oldfailed = failed;
  int len = t->len;
#define RANDOM_FUZZ 35
  
  stream_reset (peer->ibuf);
  stream_put (peer->ibuf, NULL, RANDOM_FUZZ);
  stream_set_getp (peer->ibuf, RANDOM_FUZZ);
  
  switch (type)
    {
      case CAPABILITY:
        stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP);
        stream_putc (peer->ibuf, t->len);
        break;
      case DYNCAP:
/*        for (i = 0; i < BGP_MARKER_SIZE; i++)
          stream_putc (peer->, 0xff);
        stream_putw (s, 0);
        stream_putc (s, BGP_MSG_CAPABILITY);*/
        break;
    }
  stream_write (peer->ibuf, t->data, t->len);
  
  printf ("%s: %s\n", t->name, t->desc);

  switch (type)
    {
      case CAPABILITY:
        len += 2; /* to cover the OPT-Param header */
      case OPT_PARAM:
        printf ("len: %u\n", len);
        /* peek_for_as4 wants getp at capibility*/
        as4 = peek_for_as4_capability (peer, len);
        printf ("peek_for_as4: as4 is %u\n", as4);
        /* and it should leave getp as it found it */
        assert (stream_get_getp (peer->ibuf) == RANDOM_FUZZ);
        
        ret = bgp_open_option_parse (peer, len, &capability);
        break;
      case DYNCAP:
        ret = bgp_capability_receive (peer, t->len);
        break;
      default:
        printf ("unknown type %u\n", type);
        exit(1);
    }
  
  if (!ret && t->validate_afi)
    {
      safi_t safi = t->safi;
      
      if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid)
        failed++;
      
      printf ("MP: %u/%u (%u): recv %u, nego %u\n",
              t->afi, t->safi, safi,
              peer->afc_recv[t->afi][safi],
              peer->afc_nego[t->afi][safi]);
        
      if (t->afi_valid == VALID_AFI)
        {
        
          if (!peer->afc_recv[t->afi][safi])
            failed++;
          if (!peer->afc_nego[t->afi][safi])
            failed++;
        }
    }
  
  if (as4 != t->peek_for)
    {
      printf ("as4 %u != %u\n", as4, t->peek_for);
      failed++;
    }
  
  printf ("parsed?: %s\n", ret ? "no" : "yes");
  
  if (ret != t->parses)
    failed++;
  
  if (tty)
    printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET 
                                         : VT100_GREEN "OK" VT100_RESET);
  else
    printf ("%s", (failed > oldfailed) ? "failed!" : "OK" );
  
  if (failed)
    printf (" (%u)", failed);
  
  printf ("\n\n");
}
예제 #22
0
/* basic parsing test */
static void
parse_test (struct peer *peer, struct test_segment *t, int type)
{
  int parse_ret = 0, nlri_ret = 0;
  struct attr attr = { };
  struct bgp_nlri nlri = { };
  struct bgp_attr_parser_args attr_args = {
    .peer = peer,
    .length = t->len,
    .total = 1,
    .attr = &attr,
    .type = type,
    .flags = BGP_ATTR_FLAG_OPTIONAL, 
    .startp = BGP_INPUT_PNT (peer),
  };
#define RANDOM_FUZZ 35
  
  stream_reset (peer->ibuf);
  stream_put (peer->ibuf, NULL, RANDOM_FUZZ);
  stream_set_getp (peer->ibuf, RANDOM_FUZZ);
  
  stream_write (peer->ibuf, t->data, t->len);
  
  printf ("%s: %s\n", t->name, t->desc);
  
  if (type == BGP_ATTR_MP_REACH_NLRI)
    parse_ret = bgp_mp_reach_parse (&attr_args, &nlri);
  else
    parse_ret = bgp_mp_unreach_parse (&attr_args, &nlri);
  
  if (parse_ret == 0 && t->afi_valid == VALID_AFI)
    assert (nlri.afi == t->afi && nlri.safi == t->safi);
  
  if (!parse_ret)
    {
      if (type == BGP_ATTR_MP_REACH_NLRI)
        nlri_ret = bgp_nlri_parse (peer, &attr, &nlri);
      else
        nlri_ret = bgp_nlri_parse (peer, NULL, &nlri);
    }
  
  handle_result (peer, t, parse_ret, nlri_ret);
}

static struct bgp *bgp;
static as_t asn = 100;

int
main (void)
{
  struct peer *peer;
  int i, j;
  
  conf_bgp_debug_fsm = -1UL;
  conf_bgp_debug_events = -1UL;
  conf_bgp_debug_packet = -1UL;
  conf_bgp_debug_normal = -1UL;
  conf_bgp_debug_as4 = -1UL;
  term_bgp_debug_fsm = -1UL;
  term_bgp_debug_events = -1UL;
  term_bgp_debug_packet = -1UL;
  term_bgp_debug_normal = -1UL;
  term_bgp_debug_as4 = -1UL;
  
  master = thread_master_create ();
  bgp_master_init ();
  bgp_option_set (BGP_OPT_NO_LISTEN);
  bgp_attr_init ();
  bgp_address_init ();
  
  if (fileno (stdout) >= 0) 
    tty = isatty (fileno (stdout));
  
  if (bgp_get (&bgp, &asn, NULL))
    return -1;
  
  peer = peer_create_accept (bgp);
  peer->host = (char *)"foo";
  peer->status = Established;
  
  for (i = AFI_IP; i < AFI_MAX; i++)
    for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
      {
        peer->afc[i][j] = 1;
        peer->afc_adv[i][j] = 1;
      }
  
  i = 0;
  while (mp_reach_segments[i].name)
    parse_test (peer, &mp_reach_segments[i++], BGP_ATTR_MP_REACH_NLRI);

  i = 0;
  while (mp_unreach_segments[i].name)
    parse_test (peer, &mp_unreach_segments[i++], BGP_ATTR_MP_UNREACH_NLRI);

  printf ("failures: %d\n", failed);
  return failed;
}
예제 #23
0
/* Zebra client message read function. */
static int
zclient_read (struct thread *thread)
{
  size_t already;
  uint16_t length, command;
  uint8_t marker, version;
  struct zclient *zclient;

  /* Get socket to zebra. */
  zclient = THREAD_ARG (thread);
  zclient->t_read = NULL;

  /* Read zebra header (if we don't have it already). */
  if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE)
    {
      ssize_t nbyte;
      if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock,
				     ZEBRA_HEADER_SIZE-already)) == 0) ||
	  (nbyte == -1))
	{
	  if (zclient_debug)
	   zlog_debug ("zclient connection closed socket [%d].", zclient->sock);
	  return zclient_failed(zclient);
	}
      if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already))
	{
	  /* Try again later. */
	  zclient_event (ZCLIENT_READ, zclient);
	  return 0;
	}
      already = ZEBRA_HEADER_SIZE;
    }

  /* Reset to read from the beginning of the incoming packet. */
  stream_set_getp(zclient->ibuf, 0);

  /* Fetch header values. */
  length = stream_getw (zclient->ibuf);
  marker = stream_getc (zclient->ibuf);
  version = stream_getc (zclient->ibuf);
  command = stream_getw (zclient->ibuf);
  
  if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION)
    {
      zlog_err("%s: socket %d version mismatch, marker %d, version %d",
               __func__, zclient->sock, marker, version);
      return zclient_failed(zclient);
    }
  
  if (length < ZEBRA_HEADER_SIZE) 
    {
      zlog_err("%s: socket %d message length %u is less than %d ",
	       __func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
      return zclient_failed(zclient);
    }

  /* Length check. */
  if (length > STREAM_SIZE(zclient->ibuf))
    {
      struct stream *ns;
      zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...",
	        __func__, length, (u_long)STREAM_SIZE(zclient->ibuf));
      ns = stream_new(length);
      stream_copy(ns, zclient->ibuf);
      stream_free (zclient->ibuf);
      zclient->ibuf = ns;
    }

  /* Read rest of zebra packet. */
  if (already < length)
    {
      ssize_t nbyte;
      if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock,
				     length-already)) == 0) ||
	  (nbyte == -1))
	{
	  if (zclient_debug)
	    zlog_debug("zclient connection closed socket [%d].", zclient->sock);
	  return zclient_failed(zclient);
	}
      if (nbyte != (ssize_t)(length-already))
	{
	  /* Try again later. */
	  zclient_event (ZCLIENT_READ, zclient);
	  return 0;
	}
    }

  length -= ZEBRA_HEADER_SIZE;

  if (zclient_debug)
    zlog_debug("zclient 0x%p command 0x%x \n", (void *)zclient, command);

  switch (command)
    {
    case ZEBRA_ROUTER_ID_UPDATE:
      if (zclient->router_id_update)
	(*zclient->router_id_update) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_ADD:
      if (zclient->interface_add)
	(*zclient->interface_add) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_DELETE:
      if (zclient->interface_delete)
	(*zclient->interface_delete) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_ADDRESS_ADD:
      if (zclient->interface_address_add)
	(*zclient->interface_address_add) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_ADDRESS_DELETE:
      if (zclient->interface_address_delete)
	(*zclient->interface_address_delete) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_UP:
      if (zclient->interface_up)
	(*zclient->interface_up) (command, zclient, length);
      break;
    case ZEBRA_INTERFACE_DOWN:
      if (zclient->interface_down)
	(*zclient->interface_down) (command, zclient, length);
      break;
    case ZEBRA_IPV4_ROUTE_ADD:
      if (zclient->ipv4_route_add)
	(*zclient->ipv4_route_add) (command, zclient, length);
      break;
    case ZEBRA_IPV4_ROUTE_DELETE:
      if (zclient->ipv4_route_delete)
	(*zclient->ipv4_route_delete) (command, zclient, length);
      break;
    case ZEBRA_IPV6_ROUTE_ADD:
      if (zclient->ipv6_route_add)
	(*zclient->ipv6_route_add) (command, zclient, length);
      break;
    case ZEBRA_IPV6_ROUTE_DELETE:
      if (zclient->ipv6_route_delete)
	(*zclient->ipv6_route_delete) (command, zclient, length);
      break;
    default:
      break;
    }

  if (zclient->sock < 0)
    /* Connection was closed during packet processing. */
    return -1;

  /* Register read thread. */
  stream_reset(zclient->ibuf);
  zclient_event (ZCLIENT_READ, zclient);

  return 0;
}
예제 #24
0
int isis_recv_pdu_bcast(struct isis_circuit *circuit, uint8_t *ssnpa)
{
	struct pollfd fds[1];
	struct strbuf ctlbuf, databuf;
	int flags, retv;
	dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl;

	memset(fds, 0, sizeof(fds));
	fds[0].fd = circuit->fd;
	fds[0].events = POLLIN | POLLPRI;
	if (poll(fds, 1, 0) <= 0)
		return ISIS_WARNING;

	memset(&ctlbuf, 0, sizeof(ctlbuf));
	memset(&databuf, 0, sizeof(databuf));
	ctlbuf.maxlen = sizeof(dlpi_ctl);
	ctlbuf.buf = (void *)dlpi_ctl;
	databuf.maxlen = sizeof(sock_buff);
	databuf.buf = (void *)sock_buff;
	flags = 0;
	retv = getmsg(circuit->fd, &ctlbuf, &databuf, &flags);

	if (retv < 0) {
		zlog_warn("isis_recv_pdu_bcast: getmsg failed: %s",
			  safe_strerror(errno));
		return ISIS_WARNING;
	}

	if (retv & (MORECTL | MOREDATA)) {
		while (retv & (MORECTL | MOREDATA)) {
			flags = 0;
			retv = getmsg(circuit->fd, &ctlbuf, &databuf, &flags);
		}
		return ISIS_WARNING;
	}

	if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE
	    || dui->dl_primitive != DL_UNITDATA_IND)
		return ISIS_WARNING;

	if (dui->dl_src_addr_length != ETHERADDRL + 2
	    || dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE
	    || dui->dl_src_addr_offset + dui->dl_src_addr_length
		       > (size_t)ctlbuf.len)
		return ISIS_WARNING;

	memcpy(ssnpa,
	       (char *)dui + dui->dl_src_addr_offset
		       + (circuit->sap_length > 0 ? circuit->sap_length : 0),
	       ETHERADDRL);

	if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP
	    || sock_buff[1] != ISO_SAP || sock_buff[2] != 3)
		return ISIS_WARNING;

	stream_write(circuit->rcv_stream, sock_buff + LLC_LEN,
		     databuf.len - LLC_LEN);
	stream_set_getp(circuit->rcv_stream, 0);

	return ISIS_OK;
}
예제 #25
0
/**
 * Parse given capability.
 * XXX: This is reading into a stream, but not using stream API
 *
 * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol
 *                           capabilities were encountered.
 */
static int
bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
		      u_char **error)
{
  int ret;
  struct stream *s = BGP_INPUT (peer);
  size_t end = stream_get_getp (s) + length;
  
  assert (STREAM_READABLE (s) >= length);
  
  while (stream_get_getp (s) < end)
    {
      size_t start;
      u_char *sp = stream_pnt (s);
      struct capability_header caphdr;
      
      /* We need at least capability code and capability length. */
      if (stream_get_getp(s) + 2 > end)
	{
	  zlog_info ("%s Capability length error (< header)", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}
      
      caphdr.code = stream_getc (s);
      caphdr.length = stream_getc (s);
      start = stream_get_getp (s);
      
      /* Capability length check sanity check. */
      if (start + caphdr.length > end)
	{
	  zlog_info ("%s Capability length error (< length)", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}
      
      if (BGP_DEBUG (normal, NORMAL))
	zlog_debug ("%s OPEN has %s capability (%u), length %u",
		   peer->host,
		   LOOKUP (capcode_str, caphdr.code),
		   caphdr.code, caphdr.length);
      
      /* Length sanity check, type-specific, for known capabilities */
      switch (caphdr.code)
        {
          case CAPABILITY_CODE_MP:
          case CAPABILITY_CODE_REFRESH:
          case CAPABILITY_CODE_REFRESH_OLD:
          case CAPABILITY_CODE_ORF:
          case CAPABILITY_CODE_ORF_OLD:
          case CAPABILITY_CODE_RESTART:
          case CAPABILITY_CODE_AS4:
          case CAPABILITY_CODE_DYNAMIC:
              /* Check length. */
              if (caphdr.length < cap_minsizes[caphdr.code])
                {
                  zlog_info ("%s %s Capability length error: got %u,"
                             " expected at least %u",
                             peer->host, 
                             LOOKUP (capcode_str, caphdr.code),
                             caphdr.length, 
			     (unsigned) cap_minsizes[caphdr.code]);
                  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
                  return -1;
                }
          /* we deliberately ignore unknown codes, see below */
          default:
            break;
        }
      
      switch (caphdr.code)
        {
          case CAPABILITY_CODE_MP:
            {
	      *mp_capability = 1;

              /* Ignore capability when override-capability is set. */
              if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
                {
                  /* Set negotiated value. */
                  ret = bgp_capability_mp (peer, &caphdr);

                  /* Unsupported Capability. */
                  if (ret < 0)
                    {
                      /* Store return data. */
                      memcpy (*error, sp, caphdr.length + 2);
                      *error += caphdr.length + 2;
                    }
                }
            }
            break;
          case CAPABILITY_CODE_REFRESH:
          case CAPABILITY_CODE_REFRESH_OLD:
            {
              /* BGP refresh capability */
              if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
                SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
              else
                SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
            }
            break;
          case CAPABILITY_CODE_ORF:
          case CAPABILITY_CODE_ORF_OLD:
            if (bgp_capability_orf (peer, &caphdr))
              return -1;
            break;
          case CAPABILITY_CODE_RESTART:
            if (bgp_capability_restart (peer, &caphdr))
              return -1;
            break;
          case CAPABILITY_CODE_DYNAMIC:
            SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
            break;
          case CAPABILITY_CODE_AS4:
              /* Already handled as a special-case parsing of the capabilities
               * at the beginning of OPEN processing. So we care not a jot
               * for the value really, only error case.
               */
              if (!bgp_capability_as4 (peer, &caphdr))
                return -1;
              break;            
          default:
            if (caphdr.code > 128)
              {
                /* We don't send Notification for unknown vendor specific
                   capabilities.  It seems reasonable for now...  */
                zlog_warn ("%s Vendor specific capability %d",
                           peer->host, caphdr.code);
              }
            else
              {
                zlog_warn ("%s unrecognized capability code: %d - ignored",
                           peer->host, caphdr.code);
                memcpy (*error, sp, caphdr.length + 2);
                *error += caphdr.length + 2;
              }
          }
      if (stream_get_getp(s) != (start + caphdr.length))
        {
          if (stream_get_getp(s) > (start + caphdr.length))
            zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
                       peer->host, LOOKUP (capcode_str, caphdr.code),
                       caphdr.length);
          stream_set_getp (s, start + caphdr.length);
        }
    }
  return 0;
}
예제 #26
0
/*
 * EIGRP UPDATE read function
 */
void
eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
                      struct stream * s, struct eigrp_interface *ei, int size)
{
  struct eigrp_neighbor *nbr;
  struct TLV_IPv4_Internal_type *tlv;
  struct eigrp_prefix_entry *pe;
  struct eigrp_neighbor_entry *ne;
  u_int32_t flags;
  u_int16_t type;
  uint16_t  length;
  u_char same;
  struct access_list *alist;
  struct prefix_list *plist;
  struct eigrp *e;
  u_char graceful_restart;
  u_char graceful_restart_final;
  struct list *nbr_prefixes;
  int ret;

  /* increment statistics. */
  ei->update_in++;

  /* get neighbor struct */
  nbr = eigrp_nbr_get(ei, eigrph, iph);

  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
  assert(nbr);

  flags = ntohl(eigrph->flags);

  if (flags & EIGRP_CR_FLAG)
    {
      return;
    }

  same = 0;
  graceful_restart = 0;
  graceful_restart_final = 0;
  if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
      same = 1;

  nbr->recv_sequence_number = ntohl(eigrph->sequence);
  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
    zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
               size, ifindex2ifname(nbr->ei->ifp->ifindex),
               inet_ntoa(nbr->src),
               nbr->recv_sequence_number, flags);


    if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same))
    {
    	/* Graceful restart Update received with all routes */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	graceful_restart = 1;
    	graceful_restart_final = 1;
    }
    else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same))
    {
    	/* Graceful restart Update received, routes also in next packet */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	/* save prefixes to neighbor for later use */
    	nbr->nbr_gr_prefixes = nbr_prefixes;
    	graceful_restart = 1;
    	graceful_restart_final = 0;
    }
    else if((flags == (EIGRP_EOT_FLAG)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR EOT */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is final packet of GR */
			nbr_prefixes = nbr->nbr_gr_prefixes;
			nbr->nbr_gr_prefixes = NULL;

			graceful_restart = 1;
			graceful_restart_final = 1;
		}

	}
    else if((flags == (0)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR not final packet */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is GR not final route packet */
			nbr_prefixes = nbr->nbr_gr_prefixes;

			graceful_restart = 1;
			graceful_restart_final = 0;
		}

	}
    else if((flags & EIGRP_INIT_FLAG) && (!same))
    {   /* When in pending state, send INIT update only if it wasn't
        already sent before (only if init_sequence is 0) */
        if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0))
          eigrp_update_send_init(nbr);

        if (nbr->state == EIGRP_NEIGHBOR_UP)
          {
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
            eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr);
            nbr->recv_sequence_number = ntohl(eigrph->sequence);
            zlog_info("Neighbor %s (%s) is down: peer restarted",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
            zlog_info("Neighbor %s (%s) is pending: new adjacency",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_update_send_init(nbr);
          }
    }

  /*If there is topology information*/
  while (s->endp > s->getp)
    {
      type = stream_getw(s);
      if (type == EIGRP_TLV_IPv4_INT)
        {
          stream_set_getp(s, s->getp - sizeof(u_int16_t));

          tlv = eigrp_read_ipv4_tlv(s);

          /*searching if destination exists */
          struct prefix_ipv4 *dest_addr;
          dest_addr = prefix_ipv4_new();
          dest_addr->prefix = tlv->destination;
          dest_addr->prefixlen = tlv->prefix_length;
          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
              eigrp->topology_table, dest_addr);

          /*if exists it comes to DUAL*/
          if (dest != NULL)
            {
        	  /* remove received prefix from neighbor prefix list if in GR */
        	  if(graceful_restart)
        		  remove_received_prefix_gr(nbr_prefixes, dest);

              struct eigrp_fsm_action_message *msg;
              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
                  sizeof(struct eigrp_fsm_action_message));
              struct eigrp_neighbor_entry *entry =
                  eigrp_prefix_entry_lookup(dest->entries, nbr);

              msg->packet_type = EIGRP_OPC_UPDATE;
              msg->eigrp = eigrp;
              msg->data_type = EIGRP_TLV_IPv4_INT;
              msg->adv_router = nbr;
              msg->data.ipv4_int_type = tlv;
              msg->entry = entry;
              msg->prefix = dest;
              int event = eigrp_get_fsm_event(msg);
              eigrp_fsm_event(msg, event);
            }
          else
            {
              /*Here comes topology information save*/
              pe = eigrp_prefix_entry_new();
              pe->serno = eigrp->serno;
              pe->destination_ipv4 = dest_addr;
              pe->af = AF_INET;
              pe->state = EIGRP_FSM_STATE_PASSIVE;
              pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;

              ne = eigrp_neighbor_entry_new();
              ne->ei = ei;
              ne->adv_router = nbr;
              ne->reported_metric = tlv->metric;
              ne->reported_distance = eigrp_calculate_metrics(eigrp,
                  &tlv->metric);

              //TODO: Work in progress
              /*
               * Filtering
               */
        	  e = eigrp_lookup();
        	  /* get access-list from eigrp process */
        	  alist = e->list[EIGRP_FILTER_IN];
			  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  if (alist) {
				  zlog_info ("ALIST PROC IN: %s", alist->name);
			  } else {
				  zlog_info("ALIST PROC IN je prazdny");
			  }

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PROC alist IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PROC alist IN: NENastavujem metriku ");
			  }

			  plist = e->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST PROC IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST PROC IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST PROC IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST PROC IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (e->routemap[EIGRP_FILTER_IN])
			  {
			  	 ret = route_map_apply (e->routemap[EIGRP_FILTER_IN],
			  				   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

			  	 if (ret == RMAP_DENYMATCH)
			  	 {
			  	    zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
			  	    continue;
			  	 }
			  }*/

			  /*Get access-list from current interface */
			  zlog_info("Checking access_list on interface: %s",ei->ifp->name);
			  alist = ei->list[EIGRP_FILTER_IN];
			  if (alist) {
			  	  zlog_info ("ALIST INT IN: %s", alist->name);
			  } else {
			  	  zlog_info("ALIST INT IN je prazdny");
			  	}

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
			  	  zlog_info("INT alist IN: Skipping");
			  	  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
			  	  zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  	  eigrp_IPv4_InternalTLV_free (tlv);
			  	  continue;
			  	} else {
			  	  zlog_info("INT IN: NENastavujem metriku ");
			  }

			  plist = ei->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST INT IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST INT IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST INT IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST INT IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (ei->routemap[EIGRP_FILTER_IN])
			  {
				 ret = route_map_apply (ei->routemap[EIGRP_FILTER_IN],
							   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

				 if (ret == RMAP_DENYMATCH)
				 {
					zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
					continue;
				 }
			  }*/
			  /*
			   * End of filtering
			   */

			  ne->distance = eigrp_calculate_total_metrics(eigrp, ne);

			  zlog_info("<DEBUG PROC IN Distance: %x", ne->distance);
			  zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay);

              pe->fdistance = pe->distance = pe->rdistance =
                  ne->distance;
              ne->prefix = pe;
              ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;

              eigrp_prefix_entry_add(eigrp->topology_table, pe);
              eigrp_neighbor_entry_add(pe, ne);
              pe->distance = pe->fdistance = pe->rdistance = ne->distance;
              pe->reported_metric = ne->total_metric;
              eigrp_topology_update_node_flags(pe);

              pe->req_action |= EIGRP_FSM_NEED_UPDATE;
              listnode_add(eigrp->topology_changes_internalIPV4, pe);
            }
          eigrp_IPv4_InternalTLV_free (tlv);
        }
    }

    /* ask about prefixes not present in GR update,
     * if this is final GR packet */
    if(graceful_restart_final)
    {
    	eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
    }

  /*
   * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update.
   */
  if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG))
    {
      eigrp_hello_send_ack(nbr);
    }

  eigrp_query_send_all(eigrp);
  eigrp_update_send_all(eigrp, ei);
}
예제 #27
0
/* peek into option, stores ASN to *as4 if the AS4 capability was found.
 * Returns  0 if no as4 found, as4cap value otherwise.
 */
as_t
peek_for_as4_capability (struct peer *peer, u_char length)
{
  struct stream *s = BGP_INPUT (peer);
  size_t orig_getp = stream_get_getp (s);
  size_t end = orig_getp + length;
  as_t as4 = 0;
  
  /* The full capability parser will better flag the error.. */
  if (STREAM_READABLE(s) < length)
    return 0;

  if (BGP_DEBUG (as4, AS4))
    zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
                " peeking for as4",
	        peer->host, length);
  /* the error cases we DONT handle, we ONLY try to read as4 out of
   * correctly formatted options.
   */
  while (stream_get_getp(s) < end) 
    {
      u_char opt_type;
      u_char opt_length;
      
      /* Check the length. */
      if (stream_get_getp (s) + 2 > end)
        goto end;
      
      /* Fetch option type and length. */
      opt_type = stream_getc (s);
      opt_length = stream_getc (s);
      
      /* Option length check. */
      if (stream_get_getp (s) + opt_length > end)
        goto end;
      
      if (opt_type == BGP_OPEN_OPT_CAP)
        {
          unsigned long capd_start = stream_get_getp (s);
          unsigned long capd_end = capd_start + opt_length;
          
          assert (capd_end <= end);
          
	  while (stream_get_getp (s) < capd_end)
	    {
	      struct capability_header hdr;
	      
	      if (stream_get_getp (s) + 2 > capd_end)
                goto end;
              
              hdr.code = stream_getc (s);
              hdr.length = stream_getc (s);
              
	      if ((stream_get_getp(s) +  hdr.length) > capd_end)
		goto end;

	      if (hdr.code == CAPABILITY_CODE_AS4)
	        {
	          if (BGP_DEBUG (as4, AS4))
	            zlog_info ("[AS4] found AS4 capability, about to parse");
	          as4 = bgp_capability_as4 (peer, &hdr);
	          
	          goto end;
                }
              stream_forward_getp (s, hdr.length);
	    }
	}
    }

end:
  stream_set_getp (s, orig_getp);
  return as4;
}