1 /* $OpenBSD: init.c,v 1.32 2016/07/01 23:36:38 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <arpa/inet.h> 21 #include <string.h> 22 23 #include "ldpd.h" 24 #include "ldpe.h" 25 #include "log.h" 26 27 static int gen_init_prms_tlv(struct ibuf *, struct nbr *); 28 static int tlv_decode_opt_init_prms(char *, uint16_t); 29 30 void 31 send_init(struct nbr *nbr) 32 { 33 struct ibuf *buf; 34 uint16_t size; 35 int err = 0; 36 37 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 38 39 size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE; 40 if ((buf = ibuf_open(size)) == NULL) 41 fatal(__func__); 42 43 err |= gen_ldp_hdr(buf, size); 44 size -= LDP_HDR_SIZE; 45 err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size); 46 size -= LDP_MSG_SIZE; 47 err |= gen_init_prms_tlv(buf, nbr); 48 if (err) { 49 ibuf_free(buf); 50 return; 51 } 52 53 evbuf_enqueue(&nbr->tcp->wbuf, buf); 54 } 55 56 int 57 recv_init(struct nbr *nbr, char *buf, uint16_t len) 58 { 59 struct ldp_msg msg; 60 struct sess_prms_tlv sess; 61 uint16_t max_pdu_len; 62 int r; 63 64 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 65 66 memcpy(&msg, buf, sizeof(msg)); 67 buf += LDP_MSG_SIZE; 68 len -= LDP_MSG_SIZE; 69 70 if (len < SESS_PRMS_SIZE) { 71 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); 72 return (-1); 73 } 74 memcpy(&sess, buf, sizeof(sess)); 75 if (ntohs(sess.length) != SESS_PRMS_LEN) { 76 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 77 return (-1); 78 } 79 if (ntohs(sess.proto_version) != LDP_VERSION) { 80 session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type); 81 return (-1); 82 } 83 if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) { 84 session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type); 85 return (-1); 86 } 87 if (sess.lsr_id != leconf->rtr_id.s_addr || 88 ntohs(sess.lspace_id) != 0) { 89 session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type); 90 return (-1); 91 } 92 93 buf += SESS_PRMS_SIZE; 94 len -= SESS_PRMS_SIZE; 95 96 /* just ignore all optional TLVs for now */ 97 r = tlv_decode_opt_init_prms(buf, len); 98 if (r == -1 || r != len) { 99 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); 100 return (-1); 101 } 102 103 nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id), 104 ntohs(sess.keepalive_time)); 105 106 max_pdu_len = ntohs(sess.max_pdu_len); 107 /* 108 * RFC 5036 - Section 3.5.3: 109 * "A value of 255 or less specifies the default maximum length of 110 * 4096 octets". 111 */ 112 if (max_pdu_len <= 255) 113 max_pdu_len = LDP_MAX_LEN; 114 nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN); 115 116 nbr_fsm(nbr, NBR_EVT_INIT_RCVD); 117 118 return (0); 119 } 120 121 static int 122 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr) 123 { 124 struct sess_prms_tlv parms; 125 126 memset(&parms, 0, sizeof(parms)); 127 parms.type = htons(TLV_TYPE_COMMONSESSION); 128 parms.length = htons(SESS_PRMS_LEN); 129 parms.proto_version = htons(LDP_VERSION); 130 parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id)); 131 parms.reserved = 0; 132 parms.pvlim = 0; 133 parms.max_pdu_len = 0; 134 parms.lsr_id = nbr->id.s_addr; 135 parms.lspace_id = 0; 136 137 return (ibuf_add(buf, &parms, SESS_PRMS_SIZE)); 138 } 139 140 static int 141 tlv_decode_opt_init_prms(char *buf, uint16_t len) 142 { 143 struct tlv tlv; 144 uint16_t tlv_len; 145 int total = 0; 146 147 while (len >= sizeof(tlv)) { 148 memcpy(&tlv, buf, TLV_HDR_SIZE); 149 buf += TLV_HDR_SIZE; 150 len -= TLV_HDR_SIZE; 151 total += TLV_HDR_SIZE; 152 tlv_len = ntohs(tlv.length); 153 154 switch (ntohs(tlv.type)) { 155 case TLV_TYPE_ATMSESSIONPAR: 156 log_warnx("ATM session parameter present"); 157 return (-1); 158 case TLV_TYPE_FRSESSION: 159 log_warnx("FR session parameter present"); 160 return (-1); 161 default: 162 /* if unknown flag set, ignore TLV */ 163 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 164 return (-1); 165 break; 166 } 167 buf += tlv_len; 168 len -= tlv_len; 169 total += tlv_len; 170 } 171 172 return (total); 173 } 174