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); }
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); }
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; }
/*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); }
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; }
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); }
/* 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"); }
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; }
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; }
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; }
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); }
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); }
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; }
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; }
/* 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; }
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); }
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; }
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; }
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; }
/*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); }
/* 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"); }
/* 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; }
/* 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; }
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; }
/** * 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; }
/* * 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); }
/* 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; }