/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *bula) { struct ctl_conn *c; struct imsg imsg; ssize_t n; unsigned int ifidx; int verbose; if ((c = control_connbyfd(fd)) == NULL) { log_warn("control_dispatch_imsg: fd %d: not found", fd); return; } if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd); return; } } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) == -1) { control_close(fd); return; } } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd); return; } if (n == 0) break; switch (imsg.hdr.type) { case IMSG_CTL_FIB_COUPLE: case IMSG_CTL_FIB_DECOUPLE: ospfe_fib_update(imsg.hdr.type); /* FALLTHROUGH */ case IMSG_CTL_FIB_RELOAD: case IMSG_CTL_RELOAD: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); break; case IMSG_CTL_KROUTE: case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_IFINFO: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_INTERFACE: if (imsg.hdr.len == IMSG_HEADER_SIZE + sizeof(ifidx)) { memcpy(&ifidx, imsg.data, sizeof(ifidx)); ospfe_iface_ctl(c, ifidx); imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } break; case IMSG_CTL_SHOW_DATABASE: case IMSG_CTL_SHOW_DB_EXT: case IMSG_CTL_SHOW_DB_NET: case IMSG_CTL_SHOW_DB_RTR: case IMSG_CTL_SHOW_DB_SELF: case IMSG_CTL_SHOW_DB_SUM: case IMSG_CTL_SHOW_DB_ASBR: case IMSG_CTL_SHOW_DB_OPAQ: case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_SUM: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_NBR: ospfe_nbr_ctl(c); break; case IMSG_CTL_LOG_VERBOSE: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(verbose)) break; /* forward to other processes */ ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: log_debug("control_dispatch_imsg: " "error handling imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } imsg_event_add(&c->iev); }
void recv_db_description(struct nbr *nbr, char *buf, u_int16_t len) { struct db_dscrp_hdr dd_hdr; int dupe = 0; if (len < sizeof(dd_hdr)) { log_warnx("recv_db_description: " "bad packet size, neighbor ID %s", inet_ntoa(nbr->id)); return; } memcpy(&dd_hdr, buf, sizeof(dd_hdr)); buf += sizeof(dd_hdr); len -= sizeof(dd_hdr); /* db description packet sanity checks */ if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) { log_warnx("recv_db_description: invalid MTU %d sent by " "neighbor ID %s, expected %d", ntohs(dd_hdr.iface_mtu), inet_ntoa(nbr->id), nbr->iface->mtu); return; } if (nbr->last_rx_options == dd_hdr.opts && nbr->last_rx_bits == dd_hdr.bits && ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ? 1 : 0) { log_debug("recv_db_description: dupe from ID %s", inet_ntoa(nbr->id)); dupe = 1; } switch (nbr->state) { case NBR_STA_DOWN: case NBR_STA_ATTEMPT: case NBR_STA_2_WAY: case NBR_STA_SNAP: log_debug("recv_db_description: packet ignored in state %s, " "neighbor ID %s", nbr_state_name(nbr->state), inet_ntoa(nbr->id)); return; case NBR_STA_INIT: /* evaluate dr and bdr after issuing a 2-Way event */ nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); if_fsm(nbr->iface, IF_EVT_NBR_CHNG); if (nbr->state != NBR_STA_XSTRT) return; /* FALLTHROUGH */ case NBR_STA_XSTRT: if (dupe) return; /* * check bits: either I,M,MS or only M */ if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) { /* if nbr Router ID is larger than own -> slave */ if ((ntohl(nbr->id.s_addr)) > ntohl(ospfe_router_id())) { /* slave */ nbr->dd_master = 0; nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); /* event negotiation done */ nbr_fsm(nbr, NBR_EVT_NEG_DONE); } } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) { /* M only case: we are master */ if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { log_warnx("recv_db_description: invalid " "seq num, mine %x his %x", nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); return; } nbr->dd_seq_num++; /* event negotiation done */ nbr_fsm(nbr, NBR_EVT_NEG_DONE); /* this packet may already have data so pass it on */ if (len > 0) { nbr->dd_pending++; ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0, buf, len); } } else { /* ignore packet */ log_debug("recv_db_description: packet ignored in " "state %s (bad flags), neighbor ID %s", nbr_state_name(nbr->state), inet_ntoa(nbr->id)); } break; case NBR_STA_XCHNG: case NBR_STA_LOAD: case NBR_STA_FULL: if (dd_hdr.bits & OSPF_DBD_I || !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) { log_warnx("recv_db_description: seq num mismatch, " "bad flags"); nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); return; } if (nbr->last_rx_options != dd_hdr.opts) { log_warnx("recv_db_description: seq num mismatch, " "bad options"); nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); return; } if (dupe) { if (!nbr->dd_master) /* retransmit */ start_db_tx_timer(nbr); return; } if (nbr->state != NBR_STA_XCHNG) { log_warnx("recv_db_description: invalid " "seq num, mine %x his %x", nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); return; } /* sanity check dd seq number */ if (nbr->dd_master) { /* master */ if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { log_warnx("recv_db_description: invalid " "seq num, mine %x his %x", nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); return; } nbr->dd_seq_num++; } else { /* slave */ if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) { log_warnx("recv_db_description: invalid " "seq num, mine %x his %x", nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); return; } nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); } /* forward to RDE and let it decide which LSAs to request */ if (len > 0) { nbr->dd_pending++; ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0, buf, len); } /* next packet */ db_sum_list_next(nbr); start_db_tx_timer(nbr); if (!(dd_hdr.bits & OSPF_DBD_M) && TAILQ_EMPTY(&nbr->db_sum_list)) if (!nbr->dd_master || !nbr->dd_more) nbr_fsm(nbr, NBR_EVT_XCHNG_DONE); break; default: fatalx("recv_db_description: unknown neighbor state"); } nbr->last_rx_options = dd_hdr.opts; nbr->last_rx_bits = dd_hdr.bits; }