1*3eb03b29Srenato /* $OpenBSD: rtp.c,v 1.5 2016/02/21 18:56:49 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 1943509a12Srenato #include <stdlib.h> 2043509a12Srenato #include <string.h> 2143509a12Srenato #include <arpa/inet.h> 2243509a12Srenato 2343509a12Srenato #include "eigrpd.h" 2443509a12Srenato #include "eigrp.h" 2543509a12Srenato #include "eigrpe.h" 2643509a12Srenato #include "rde.h" 2743509a12Srenato #include "log.h" 2843509a12Srenato 2943509a12Srenato void rtp_retrans_timer(int, short, void *); 3043509a12Srenato void rtp_retrans_start_timer(struct packet *); 3143509a12Srenato void rtp_retrans_stop_timer(struct packet *); 3243509a12Srenato 3343509a12Srenato struct pbuf * 3443509a12Srenato rtp_buf_new(struct ibuf *buf) 3543509a12Srenato { 3643509a12Srenato struct pbuf *pbuf; 3743509a12Srenato 3843509a12Srenato if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL) 3943509a12Srenato fatal("rtp_buf_new"); 4043509a12Srenato pbuf->buf = buf; 4143509a12Srenato 4243509a12Srenato return (pbuf); 4343509a12Srenato } 4443509a12Srenato 4543509a12Srenato struct pbuf * 4643509a12Srenato rtp_buf_hold(struct pbuf *pbuf) 4743509a12Srenato { 4843509a12Srenato pbuf->refcnt++; 4943509a12Srenato return (pbuf); 5043509a12Srenato } 5143509a12Srenato 5243509a12Srenato void 5343509a12Srenato rtp_buf_release(struct pbuf *pbuf) 5443509a12Srenato { 5543509a12Srenato if (--pbuf->refcnt == 0) { 5643509a12Srenato ibuf_free(pbuf->buf); 5743509a12Srenato free(pbuf); 5843509a12Srenato } 5943509a12Srenato } 6043509a12Srenato 6143509a12Srenato struct packet * 6243509a12Srenato rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf) 6343509a12Srenato { 6443509a12Srenato struct packet *pkt; 6543509a12Srenato 6643509a12Srenato if ((pkt = calloc(1, sizeof(struct packet))) == NULL) 6743509a12Srenato fatal("rtp_packet_new"); 6843509a12Srenato 6943509a12Srenato pkt->nbr = nbr; 7043509a12Srenato pkt->seq_num = seq_num; 7143509a12Srenato pkt->pbuf = rtp_buf_hold(pbuf); 7243509a12Srenato pkt->attempts = 1; 7343509a12Srenato evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt); 7443509a12Srenato 7543509a12Srenato return (pkt); 7643509a12Srenato } 7743509a12Srenato 7843509a12Srenato void 7943509a12Srenato rtp_packet_del(struct packet *pkt) 8043509a12Srenato { 8143509a12Srenato TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry); 8243509a12Srenato rtp_retrans_stop_timer(pkt); 8343509a12Srenato rtp_buf_release(pkt->pbuf); 8443509a12Srenato free(pkt); 8543509a12Srenato } 8643509a12Srenato 8743509a12Srenato void 8843509a12Srenato rtp_process_ack(struct nbr *nbr, uint32_t ack_num) 8943509a12Srenato { 9043509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 9143509a12Srenato struct packet *pkt; 9243509a12Srenato 9343509a12Srenato /* window size is one */ 9443509a12Srenato pkt = TAILQ_FIRST(&nbr->retrans_list); 9543509a12Srenato if (pkt && pkt->seq_num == ack_num) { 9643509a12Srenato log_debug("%s: nbr %s ack %u", __func__, 9743509a12Srenato log_addr(eigrp->af, &nbr->addr), ack_num); 9843509a12Srenato 9943509a12Srenato /* dequeue packet from retransmission queue */ 10043509a12Srenato rtp_packet_del(pkt); 10143509a12Srenato 10243509a12Srenato /* enqueue next packet from retransmission queue */ 10343509a12Srenato pkt = TAILQ_FIRST(&nbr->retrans_list); 10443509a12Srenato if (pkt) 10543509a12Srenato rtp_send_packet(pkt); 10643509a12Srenato } 10743509a12Srenato } 10843509a12Srenato 10943509a12Srenato void 11043509a12Srenato rtp_send_packet(struct packet *pkt) 11143509a12Srenato { 11243509a12Srenato rtp_retrans_start_timer(pkt); 11343509a12Srenato send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf); 11443509a12Srenato } 11543509a12Srenato 11643509a12Srenato void 11743509a12Srenato rtp_enqueue_packet(struct packet *pkt) 11843509a12Srenato { 11943509a12Srenato /* only send packet if transmission queue is empty */ 12043509a12Srenato if (TAILQ_EMPTY(&pkt->nbr->retrans_list)) 12143509a12Srenato rtp_send_packet(pkt); 12243509a12Srenato 12343509a12Srenato TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry); 12443509a12Srenato } 12543509a12Srenato 12643509a12Srenato static void 12743509a12Srenato rtp_seq_inc(struct eigrp *eigrp) 12843509a12Srenato { 12943509a12Srenato /* automatic wraparound with unsigned arithmetic */ 13043509a12Srenato eigrp->seq_num++; 13143509a12Srenato 13243509a12Srenato /* sequence number 0 is reserved for unreliably transmission */ 13343509a12Srenato if (eigrp->seq_num == 0) 13443509a12Srenato eigrp->seq_num = 1; 13543509a12Srenato } 13643509a12Srenato 13743509a12Srenato void 13843509a12Srenato rtp_send_ucast(struct nbr *nbr, struct ibuf *buf) 13943509a12Srenato { 14043509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 14143509a12Srenato struct packet *pkt; 14243509a12Srenato struct pbuf *pbuf; 14343509a12Srenato 14443509a12Srenato pbuf = rtp_buf_new(buf); 14543509a12Srenato pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf); 14643509a12Srenato rtp_enqueue_packet(pkt); 14743509a12Srenato rtp_seq_inc(eigrp); 14843509a12Srenato } 14943509a12Srenato 15043509a12Srenato void 15143509a12Srenato rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf) 15243509a12Srenato { 15343509a12Srenato struct eigrp *eigrp = ei->eigrp; 15443509a12Srenato struct nbr *nbr; 15543509a12Srenato int total = 0, pending = 0; 15643509a12Srenato struct packet *pkt; 15743509a12Srenato struct pbuf *pbuf; 15843509a12Srenato uint32_t flags = 0; 15943509a12Srenato struct seq_addr_entry *sa; 16043509a12Srenato struct seq_addr_head seq_addr_list; 16143509a12Srenato 16243509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 16343509a12Srenato if (nbr->flags & F_EIGRP_NBR_SELF) 16443509a12Srenato continue; 16543509a12Srenato if (!TAILQ_EMPTY(&nbr->retrans_list)) 16643509a12Srenato pending++; 16743509a12Srenato total++; 16843509a12Srenato } 16943509a12Srenato if (total == 0) 17043509a12Srenato return; 17143509a12Srenato 17243509a12Srenato /* 17343509a12Srenato * send a multicast if there's at least one neighbor with an empty 17443509a12Srenato * queue on the interface. 17543509a12Srenato */ 17643509a12Srenato if (pending < total) { 17743509a12Srenato /* 17843509a12Srenato * build a hello packet with a seq tlv indicating all the 17943509a12Srenato * neighbors that have full queues. 18043509a12Srenato */ 18143509a12Srenato if (pending > 0) { 18243509a12Srenato flags |= EIGRP_HDR_FLAG_CR; 18343509a12Srenato TAILQ_INIT(&seq_addr_list); 18443509a12Srenato 18543509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 18643509a12Srenato if (TAILQ_EMPTY(&nbr->retrans_list)) 18743509a12Srenato continue; 18843509a12Srenato if ((sa = calloc(1, sizeof(*sa))) == NULL) 18943509a12Srenato fatal("rtp_send_mcast"); 19043509a12Srenato sa->af = eigrp->af; 191*3eb03b29Srenato sa->addr = nbr->addr; 19243509a12Srenato TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry); 19343509a12Srenato } 19443509a12Srenato 1950e96235eSrenato send_hello(ei, &seq_addr_list, eigrp->seq_num); 19643509a12Srenato seq_addr_list_clr(&seq_addr_list); 19743509a12Srenato } 19843509a12Srenato send_packet(ei, NULL, flags, buf); 19943509a12Srenato } 20043509a12Srenato 20143509a12Srenato /* schedule an unicast retransmission for each neighbor */ 20243509a12Srenato pbuf = rtp_buf_new(buf); 20343509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry) { 20443509a12Srenato pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf); 20543509a12Srenato TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry); 20643509a12Srenato } 20743509a12Srenato 20843509a12Srenato rtp_seq_inc(eigrp); 20943509a12Srenato } 21043509a12Srenato 21143509a12Srenato void 21243509a12Srenato rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf) 21343509a12Srenato { 21443509a12Srenato if (nbr) 21543509a12Srenato rtp_send_ucast(nbr, buf); 21643509a12Srenato else 21743509a12Srenato rtp_send_mcast(ei, buf); 21843509a12Srenato } 21943509a12Srenato 22043509a12Srenato void 22143509a12Srenato rtp_send_ack(struct nbr *nbr) 22243509a12Srenato { 22343509a12Srenato struct eigrp *eigrp = nbr->ei->eigrp; 22443509a12Srenato struct ibuf *buf; 22543509a12Srenato 22643509a12Srenato if ((buf = ibuf_dynamic(PKG_DEF_SIZE, 22743509a12Srenato IP_MAXPACKET - sizeof(struct ip))) == NULL) 22843509a12Srenato fatal("rtp_send_ack"); 22943509a12Srenato 23043509a12Srenato /* EIGRP header */ 2310cefb3adSrenato if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO, 0, 0, eigrp->as)) { 2320cefb3adSrenato log_warnx("%s: failed to send message", __func__); 2330cefb3adSrenato ibuf_free(buf); 2340cefb3adSrenato return; 2350cefb3adSrenato } 23643509a12Srenato 23743509a12Srenato /* send unreliably */ 23843509a12Srenato send_packet(nbr->ei, nbr, 0, buf); 23943509a12Srenato ibuf_free(buf); 24043509a12Srenato } 24143509a12Srenato 24243509a12Srenato /* timers */ 24343509a12Srenato 24443509a12Srenato /* ARGSUSED */ 24543509a12Srenato void 24643509a12Srenato rtp_retrans_timer(int fd, short event, void *arg) 24743509a12Srenato { 24843509a12Srenato struct packet *pkt = arg; 24943509a12Srenato struct eigrp *eigrp = pkt->nbr->ei->eigrp; 25043509a12Srenato 25143509a12Srenato pkt->attempts++; 25243509a12Srenato 25343509a12Srenato if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS) { 25443509a12Srenato log_warnx("%s: retry limit exceeded, nbr %s", __func__, 25543509a12Srenato log_addr(eigrp->af, &pkt->nbr->addr)); 25643509a12Srenato nbr_del(pkt->nbr); 25743509a12Srenato return; 25843509a12Srenato } 25943509a12Srenato 26043509a12Srenato rtp_send_packet(pkt); 26143509a12Srenato } 26243509a12Srenato 26343509a12Srenato void 26443509a12Srenato rtp_retrans_start_timer(struct packet *pkt) 26543509a12Srenato { 26643509a12Srenato struct timeval tv; 26743509a12Srenato 26843509a12Srenato timerclear(&tv); 26943509a12Srenato tv.tv_sec = RTP_RTRNS_INTERVAL; 27043509a12Srenato if (evtimer_add(&pkt->ev_timeout, &tv) == -1) 27143509a12Srenato fatal("rtp_retrans_start_timer"); 27243509a12Srenato } 27343509a12Srenato 27443509a12Srenato void 27543509a12Srenato rtp_retrans_stop_timer(struct packet *pkt) 27643509a12Srenato { 27743509a12Srenato if (evtimer_pending(&pkt->ev_timeout, NULL) && 27843509a12Srenato evtimer_del(&pkt->ev_timeout) == -1) 27943509a12Srenato fatal("rtp_retrans_stop_timer"); 28043509a12Srenato } 28143509a12Srenato 28243509a12Srenato /* ARGSUSED */ 28343509a12Srenato void 28443509a12Srenato rtp_ack_timer(int fd, short event, void *arg) 28543509a12Srenato { 28643509a12Srenato struct nbr *nbr = arg; 28743509a12Srenato 28843509a12Srenato rtp_send_ack(nbr); 28943509a12Srenato } 29043509a12Srenato 29143509a12Srenato void 29243509a12Srenato rtp_ack_start_timer(struct nbr *nbr) 29343509a12Srenato { 29443509a12Srenato struct timeval tv; 29543509a12Srenato 29643509a12Srenato timerclear(&tv); 29743509a12Srenato tv.tv_usec = RTP_ACK_TIMEOUT; 29843509a12Srenato if (evtimer_add(&nbr->ev_ack, &tv) == -1) 29943509a12Srenato fatal("rtp_ack_start_timer"); 30043509a12Srenato } 30143509a12Srenato 30243509a12Srenato void 30343509a12Srenato rtp_ack_stop_timer(struct nbr *nbr) 30443509a12Srenato { 30543509a12Srenato if (evtimer_pending(&nbr->ev_ack, NULL) && 30643509a12Srenato evtimer_del(&nbr->ev_ack) == -1) 30743509a12Srenato fatal("rtp_ack_stop_timer"); 30843509a12Srenato } 309