1*ab786365Srenato /* $OpenBSD: rtp.c,v 1.7 2016/09/02 16:44:33 renato Exp $ */ 243509a12Srenato 343509a12Srenato /* 443509a12Srenato * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 543509a12Srenato * 643509a12Srenato * Permission to use, copy, modify, and distribute this software for any 743509a12Srenato * purpose with or without fee is hereby granted, provided that the above 843509a12Srenato * copyright notice and this permission notice appear in all copies. 943509a12Srenato * 1043509a12Srenato * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1143509a12Srenato * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1243509a12Srenato * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1343509a12Srenato * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1443509a12Srenato * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1543509a12Srenato * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1643509a12Srenato * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1743509a12Srenato */ 1843509a12Srenato 198072de9bSrenato #include <sys/types.h> 208072de9bSrenato #include <netinet/in.h> 218072de9bSrenato #include <netinet/ip.h> 228072de9bSrenato 2343509a12Srenato #include <stdlib.h> 2443509a12Srenato 2543509a12Srenato #include "eigrpd.h" 2643509a12Srenato #include "eigrpe.h" 2743509a12Srenato #include "log.h" 2843509a12Srenato 29*ab786365Srenato static struct pbuf *rtp_buf_new(struct ibuf *); 30*ab786365Srenato static struct pbuf *rtp_buf_hold(struct pbuf *); 31*ab786365Srenato static void rtp_buf_release(struct pbuf *); 32*ab786365Srenato static struct packet *rtp_packet_new(struct nbr *, uint32_t, struct pbuf *); 33*ab786365Srenato static void rtp_send_packet(struct packet *); 34*ab786365Srenato static void rtp_enqueue_packet(struct packet *); 35*ab786365Srenato static void rtp_send_mcast(struct eigrp_iface *, struct ibuf *); 36*ab786365Srenato static void rtp_retrans_timer(int, short, void *); 37*ab786365Srenato static void rtp_retrans_start_timer(struct packet *); 38*ab786365Srenato static void rtp_retrans_stop_timer(struct packet *); 3943509a12Srenato 40*ab786365Srenato static struct pbuf * 4143509a12Srenato rtp_buf_new(struct ibuf *buf) 4243509a12Srenato { 4343509a12Srenato struct pbuf *pbuf; 4443509a12Srenato 4543509a12Srenato if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL) 4643509a12Srenato fatal("rtp_buf_new"); 4743509a12Srenato pbuf->buf = buf; 4843509a12Srenato 4943509a12Srenato return (pbuf); 5043509a12Srenato } 5143509a12Srenato 52*ab786365Srenato static struct pbuf * 5343509a12Srenato rtp_buf_hold(struct pbuf *pbuf) 5443509a12Srenato { 5543509a12Srenato pbuf->refcnt++; 5643509a12Srenato return (pbuf); 5743509a12Srenato } 5843509a12Srenato 59*ab786365Srenato static void 6043509a12Srenato rtp_buf_release(struct pbuf *pbuf) 6143509a12Srenato { 6243509a12Srenato if (--pbuf->refcnt == 0) { 6343509a12Srenato ibuf_free(pbuf->buf); 6443509a12Srenato free(pbuf); 6543509a12Srenato } 6643509a12Srenato } 6743509a12Srenato 68*ab786365Srenato static struct packet * 6943509a12Srenato rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf) 7043509a12Srenato { 7143509a12Srenato struct packet *pkt; 7243509a12Srenato 7343509a12Srenato if ((pkt = calloc(1, sizeof(struct packet))) == NULL) 7443509a12Srenato fatal("rtp_packet_new"); 7543509a12Srenato 7643509a12Srenato pkt->nbr = nbr; 7743509a12Srenato pkt->seq_num = seq_num; 7843509a12Srenato pkt->pbuf = rtp_buf_hold(pbuf); 7943509a12Srenato pkt->attempts = 1; 8043509a12Srenato evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt); 8143509a12Srenato 8243509a12Srenato return (pkt); 8343509a12Srenato } 8443509a12Srenato 8543509a12Srenato void 8643509a12Srenato rtp_packet_del(struct packet *pkt) 8743509a12Srenato { 8843509a12Srenato TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry); 8943509a12Srenato rtp_retrans_stop_timer(pkt); 9043509a12Srenato rtp_buf_release(pkt->pbuf); 9143509a12Srenato free(pkt); 9243509a12Srenato } 9343509a12Srenato 9443509a12Srenato void 9543509a12Srenato rtp_process_ack(struct nbr *nbr, uint32_t ack_num) 9643509a12Srenato { 9743509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 9843509a12Srenato struct packet *pkt; 9943509a12Srenato 10043509a12Srenato /* window size is one */ 10143509a12Srenato pkt = TAILQ_FIRST(&nbr->retrans_list); 10243509a12Srenato if (pkt && pkt->seq_num == ack_num) { 10343509a12Srenato log_debug("%s: nbr %s ack %u", __func__, 10443509a12Srenato log_addr(eigrp->af, &nbr->addr), ack_num); 10543509a12Srenato 10643509a12Srenato /* dequeue packet from retransmission queue */ 10743509a12Srenato rtp_packet_del(pkt); 10843509a12Srenato 10943509a12Srenato /* enqueue next packet from retransmission queue */ 11043509a12Srenato pkt = TAILQ_FIRST(&nbr->retrans_list); 11143509a12Srenato if (pkt) 11243509a12Srenato rtp_send_packet(pkt); 11343509a12Srenato } 11443509a12Srenato } 11543509a12Srenato 116*ab786365Srenato static void 11743509a12Srenato rtp_send_packet(struct packet *pkt) 11843509a12Srenato { 11943509a12Srenato rtp_retrans_start_timer(pkt); 12043509a12Srenato send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf); 12143509a12Srenato } 12243509a12Srenato 123*ab786365Srenato static void 12443509a12Srenato rtp_enqueue_packet(struct packet *pkt) 12543509a12Srenato { 12643509a12Srenato /* only send packet if transmission queue is empty */ 12743509a12Srenato if (TAILQ_EMPTY(&pkt->nbr->retrans_list)) 12843509a12Srenato rtp_send_packet(pkt); 12943509a12Srenato 13043509a12Srenato TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry); 13143509a12Srenato } 13243509a12Srenato 13343509a12Srenato static void 13443509a12Srenato rtp_seq_inc(struct eigrp *eigrp) 13543509a12Srenato { 13643509a12Srenato /* automatic wraparound with unsigned arithmetic */ 13743509a12Srenato eigrp->seq_num++; 13843509a12Srenato 13943509a12Srenato /* sequence number 0 is reserved for unreliably transmission */ 14043509a12Srenato if (eigrp->seq_num == 0) 14143509a12Srenato eigrp->seq_num = 1; 14243509a12Srenato } 14343509a12Srenato 14443509a12Srenato void 14543509a12Srenato rtp_send_ucast(struct nbr *nbr, struct ibuf *buf) 14643509a12Srenato { 14743509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 14843509a12Srenato struct packet *pkt; 14943509a12Srenato struct pbuf *pbuf; 15043509a12Srenato 15143509a12Srenato pbuf = rtp_buf_new(buf); 15243509a12Srenato pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf); 15343509a12Srenato rtp_enqueue_packet(pkt); 15443509a12Srenato rtp_seq_inc(eigrp); 15543509a12Srenato } 15643509a12Srenato 157*ab786365Srenato static void 15843509a12Srenato rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf) 15943509a12Srenato { 16043509a12Srenato struct eigrp *eigrp = ei->eigrp; 16143509a12Srenato struct nbr *nbr; 16243509a12Srenato int total = 0, pending = 0; 16343509a12Srenato struct packet *pkt; 16443509a12Srenato struct pbuf *pbuf; 16543509a12Srenato uint32_t flags = 0; 16643509a12Srenato struct seq_addr_entry *sa; 16743509a12Srenato struct seq_addr_head seq_addr_list; 16843509a12Srenato 16943509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 17043509a12Srenato if (nbr->flags & F_EIGRP_NBR_SELF) 17143509a12Srenato continue; 17243509a12Srenato if (!TAILQ_EMPTY(&nbr->retrans_list)) 17343509a12Srenato pending++; 17443509a12Srenato total++; 17543509a12Srenato } 17643509a12Srenato if (total == 0) 17743509a12Srenato return; 17843509a12Srenato 17943509a12Srenato /* 18043509a12Srenato * send a multicast if there's at least one neighbor with an empty 18143509a12Srenato * queue on the interface. 18243509a12Srenato */ 18343509a12Srenato if (pending < total) { 18443509a12Srenato /* 18543509a12Srenato * build a hello packet with a seq tlv indicating all the 18643509a12Srenato * neighbors that have full queues. 18743509a12Srenato */ 18843509a12Srenato if (pending > 0) { 18943509a12Srenato flags |= EIGRP_HDR_FLAG_CR; 19043509a12Srenato TAILQ_INIT(&seq_addr_list); 19143509a12Srenato 19243509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 19343509a12Srenato if (TAILQ_EMPTY(&nbr->retrans_list)) 19443509a12Srenato continue; 19543509a12Srenato if ((sa = calloc(1, sizeof(*sa))) == NULL) 19643509a12Srenato fatal("rtp_send_mcast"); 19743509a12Srenato sa->af = eigrp->af; 1983eb03b29Srenato sa->addr = nbr->addr; 19943509a12Srenato TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry); 20043509a12Srenato } 20143509a12Srenato 2020e96235eSrenato send_hello(ei, &seq_addr_list, eigrp->seq_num); 20343509a12Srenato seq_addr_list_clr(&seq_addr_list); 20443509a12Srenato } 20543509a12Srenato send_packet(ei, NULL, flags, buf); 20643509a12Srenato } 20743509a12Srenato 20843509a12Srenato /* schedule an unicast retransmission for each neighbor */ 20943509a12Srenato pbuf = rtp_buf_new(buf); 21043509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 21143509a12Srenato pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf); 21243509a12Srenato TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry); 21343509a12Srenato } 21443509a12Srenato 21543509a12Srenato rtp_seq_inc(eigrp); 21643509a12Srenato } 21743509a12Srenato 21843509a12Srenato void 21943509a12Srenato rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf) 22043509a12Srenato { 22143509a12Srenato if (nbr) 22243509a12Srenato rtp_send_ucast(nbr, buf); 22343509a12Srenato else 22443509a12Srenato rtp_send_mcast(ei, buf); 22543509a12Srenato } 22643509a12Srenato 22743509a12Srenato void 22843509a12Srenato rtp_send_ack(struct nbr *nbr) 22943509a12Srenato { 23043509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 23143509a12Srenato struct ibuf *buf; 23243509a12Srenato 23343509a12Srenato if ((buf = ibuf_dynamic(PKG_DEF_SIZE, 23443509a12Srenato IP_MAXPACKET - sizeof(struct ip))) == NULL) 23543509a12Srenato fatal("rtp_send_ack"); 23643509a12Srenato 23743509a12Srenato /* EIGRP header */ 2380cefb3adSrenato if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO, 0, 0, eigrp->as)) { 2390cefb3adSrenato log_warnx("%s: failed to send message", __func__); 2400cefb3adSrenato ibuf_free(buf); 2410cefb3adSrenato return; 2420cefb3adSrenato } 24343509a12Srenato 24443509a12Srenato /* send unreliably */ 24543509a12Srenato send_packet(nbr->ei, nbr, 0, buf); 24643509a12Srenato ibuf_free(buf); 24743509a12Srenato } 24843509a12Srenato 24943509a12Srenato /* timers */ 25043509a12Srenato 25143509a12Srenato /* ARGSUSED */ 252*ab786365Srenato static void 25343509a12Srenato rtp_retrans_timer(int fd, short event, void *arg) 25443509a12Srenato { 25543509a12Srenato struct packet *pkt = arg; 25643509a12Srenato struct eigrp *eigrp = pkt->nbr->ei->eigrp; 25743509a12Srenato 25843509a12Srenato pkt->attempts++; 25943509a12Srenato 26043509a12Srenato if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS) { 26143509a12Srenato log_warnx("%s: retry limit exceeded, nbr %s", __func__, 26243509a12Srenato log_addr(eigrp->af, &pkt->nbr->addr)); 26343509a12Srenato nbr_del(pkt->nbr); 26443509a12Srenato return; 26543509a12Srenato } 26643509a12Srenato 26743509a12Srenato rtp_send_packet(pkt); 26843509a12Srenato } 26943509a12Srenato 270*ab786365Srenato static void 27143509a12Srenato rtp_retrans_start_timer(struct packet *pkt) 27243509a12Srenato { 27343509a12Srenato struct timeval tv; 27443509a12Srenato 27543509a12Srenato timerclear(&tv); 27643509a12Srenato tv.tv_sec = RTP_RTRNS_INTERVAL; 27743509a12Srenato if (evtimer_add(&pkt->ev_timeout, &tv) == -1) 27843509a12Srenato fatal("rtp_retrans_start_timer"); 27943509a12Srenato } 28043509a12Srenato 281*ab786365Srenato static void 28243509a12Srenato rtp_retrans_stop_timer(struct packet *pkt) 28343509a12Srenato { 28443509a12Srenato if (evtimer_pending(&pkt->ev_timeout, NULL) && 28543509a12Srenato evtimer_del(&pkt->ev_timeout) == -1) 28643509a12Srenato fatal("rtp_retrans_stop_timer"); 28743509a12Srenato } 28843509a12Srenato 28943509a12Srenato /* ARGSUSED */ 29043509a12Srenato void 29143509a12Srenato rtp_ack_timer(int fd, short event, void *arg) 29243509a12Srenato { 29343509a12Srenato struct nbr *nbr = arg; 29443509a12Srenato 29543509a12Srenato rtp_send_ack(nbr); 29643509a12Srenato } 29743509a12Srenato 29843509a12Srenato void 29943509a12Srenato rtp_ack_start_timer(struct nbr *nbr) 30043509a12Srenato { 30143509a12Srenato struct timeval tv; 30243509a12Srenato 30343509a12Srenato timerclear(&tv); 30443509a12Srenato tv.tv_usec = RTP_ACK_TIMEOUT; 30543509a12Srenato if (evtimer_add(&nbr->ev_ack, &tv) == -1) 30643509a12Srenato fatal("rtp_ack_start_timer"); 30743509a12Srenato } 30843509a12Srenato 30943509a12Srenato void 31043509a12Srenato rtp_ack_stop_timer(struct nbr *nbr) 31143509a12Srenato { 31243509a12Srenato if (evtimer_pending(&nbr->ev_ack, NULL) && 31343509a12Srenato evtimer_del(&nbr->ev_ack) == -1) 31443509a12Srenato fatal("rtp_ack_stop_timer"); 31543509a12Srenato } 316