1 /* $OpenBSD: init.c,v 1.37 2017/03/04 00:15:35 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 gen_cap_dynamic_tlv(struct ibuf *); 29 static int gen_cap_twcard_tlv(struct ibuf *, int); 30 static int gen_cap_unotif_tlv(struct ibuf *, int); 31 32 void 33 send_init(struct nbr *nbr) 34 { 35 struct ibuf *buf; 36 uint16_t size; 37 int err = 0; 38 39 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 40 41 size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE + 42 CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE; 43 if ((buf = ibuf_open(size)) == NULL) 44 fatal(__func__); 45 46 err |= gen_ldp_hdr(buf, size); 47 size -= LDP_HDR_SIZE; 48 err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size); 49 err |= gen_init_prms_tlv(buf, nbr); 50 err |= gen_cap_dynamic_tlv(buf); 51 err |= gen_cap_twcard_tlv(buf, 1); 52 err |= gen_cap_unotif_tlv(buf, 1); 53 if (err) { 54 ibuf_free(buf); 55 return; 56 } 57 58 evbuf_enqueue(&nbr->tcp->wbuf, buf); 59 } 60 61 int 62 recv_init(struct nbr *nbr, char *buf, uint16_t len) 63 { 64 struct ldp_msg msg; 65 struct sess_prms_tlv sess; 66 uint16_t max_pdu_len; 67 int caps_rcvd = 0; 68 69 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 70 71 memcpy(&msg, buf, sizeof(msg)); 72 buf += LDP_MSG_SIZE; 73 len -= LDP_MSG_SIZE; 74 75 if (len < SESS_PRMS_SIZE) { 76 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); 77 return (-1); 78 } 79 memcpy(&sess, buf, sizeof(sess)); 80 if (ntohs(sess.length) != SESS_PRMS_LEN) { 81 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 82 return (-1); 83 } 84 if (ntohs(sess.proto_version) != LDP_VERSION) { 85 session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type); 86 return (-1); 87 } 88 if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) { 89 session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type); 90 return (-1); 91 } 92 if (sess.lsr_id != leconf->rtr_id.s_addr || 93 ntohs(sess.lspace_id) != 0) { 94 session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type); 95 return (-1); 96 } 97 98 buf += SESS_PRMS_SIZE; 99 len -= SESS_PRMS_SIZE; 100 101 /* Optional Parameters */ 102 while (len > 0) { 103 struct tlv tlv; 104 uint16_t tlv_type; 105 uint16_t tlv_len; 106 107 if (len < sizeof(tlv)) { 108 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 109 return (-1); 110 } 111 112 memcpy(&tlv, buf, TLV_HDR_SIZE); 113 tlv_type = ntohs(tlv.type); 114 tlv_len = ntohs(tlv.length); 115 if (tlv_len + TLV_HDR_SIZE > len) { 116 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 117 return (-1); 118 } 119 buf += TLV_HDR_SIZE; 120 len -= TLV_HDR_SIZE; 121 122 /* 123 * RFC 5561 - Section 6: 124 * "The S-bit of a Capability Parameter in an Initialization 125 * message MUST be 1 and SHOULD be ignored on receipt". 126 */ 127 switch (tlv_type) { 128 case TLV_TYPE_ATMSESSIONPAR: 129 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); 130 return (-1); 131 case TLV_TYPE_FRSESSION: 132 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); 133 return (-1); 134 case TLV_TYPE_DYNAMIC_CAP: 135 if (tlv_len != CAP_TLV_DYNAMIC_LEN) { 136 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 137 msg.type); 138 return (-1); 139 } 140 141 if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) { 142 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 143 msg.type); 144 return (-1); 145 } 146 caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC; 147 148 nbr->flags |= F_NBR_CAP_DYNAMIC; 149 150 log_debug("%s: lsr-id %s announced the Dynamic " 151 "Capability Announcement capability", __func__, 152 inet_ntoa(nbr->id)); 153 break; 154 case TLV_TYPE_TWCARD_CAP: 155 if (tlv_len != CAP_TLV_TWCARD_LEN) { 156 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 157 msg.type); 158 return (-1); 159 } 160 161 if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) { 162 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 163 msg.type); 164 return (-1); 165 } 166 caps_rcvd |= F_CAP_TLV_RCVD_TWCARD; 167 168 nbr->flags |= F_NBR_CAP_TWCARD; 169 170 log_debug("%s: lsr-id %s announced the Typed Wildcard " 171 "FEC capability", __func__, inet_ntoa(nbr->id)); 172 break; 173 case TLV_TYPE_UNOTIF_CAP: 174 if (tlv_len != CAP_TLV_UNOTIF_LEN) { 175 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 176 msg.type); 177 return (-1); 178 } 179 180 if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) { 181 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 182 msg.type); 183 return (-1); 184 } 185 caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF; 186 187 nbr->flags |= F_NBR_CAP_UNOTIF; 188 189 log_debug("%s: lsr-id %s announced the Unrecognized " 190 "Notification capability", __func__, 191 inet_ntoa(nbr->id)); 192 break; 193 default: 194 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 195 send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, 196 msg.id, msg.type, tlv_type, tlv_len, buf); 197 /* ignore unknown tlv */ 198 break; 199 } 200 buf += tlv_len; 201 len -= tlv_len; 202 } 203 204 nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id), 205 ntohs(sess.keepalive_time)); 206 207 max_pdu_len = ntohs(sess.max_pdu_len); 208 /* 209 * RFC 5036 - Section 3.5.3: 210 * "A value of 255 or less specifies the default maximum length of 211 * 4096 octets". 212 */ 213 if (max_pdu_len <= 255) 214 max_pdu_len = LDP_MAX_LEN; 215 nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN); 216 217 nbr_fsm(nbr, NBR_EVT_INIT_RCVD); 218 219 return (0); 220 } 221 222 void 223 send_capability(struct nbr *nbr, uint16_t capability, int enable) 224 { 225 struct ibuf *buf; 226 uint16_t size; 227 int err = 0; 228 229 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 230 231 size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE; 232 if ((buf = ibuf_open(size)) == NULL) 233 fatal(__func__); 234 235 err |= gen_ldp_hdr(buf, size); 236 size -= LDP_HDR_SIZE; 237 err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size); 238 239 switch (capability) { 240 case TLV_TYPE_TWCARD_CAP: 241 err |= gen_cap_twcard_tlv(buf, enable); 242 break; 243 case TLV_TYPE_UNOTIF_CAP: 244 err |= gen_cap_unotif_tlv(buf, enable); 245 break; 246 case TLV_TYPE_DYNAMIC_CAP: 247 /* 248 * RFC 5561 - Section 9: 249 * "An LDP speaker MUST NOT include the Dynamic Capability 250 * Announcement Parameter in Capability messages sent to 251 * its peers". 252 */ 253 /* FALLTHROUGH */ 254 default: 255 fatalx("send_capability: unsupported capability"); 256 } 257 258 if (err) { 259 ibuf_free(buf); 260 return; 261 } 262 263 evbuf_enqueue(&nbr->tcp->wbuf, buf); 264 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 265 } 266 267 int 268 recv_capability(struct nbr *nbr, char *buf, uint16_t len) 269 { 270 struct ldp_msg msg; 271 int enable = 0; 272 int caps_rcvd = 0; 273 274 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 275 276 memcpy(&msg, buf, sizeof(msg)); 277 buf += LDP_MSG_SIZE; 278 len -= LDP_MSG_SIZE; 279 280 /* Optional Parameters */ 281 while (len > 0) { 282 struct tlv tlv; 283 uint16_t tlv_type; 284 uint16_t tlv_len; 285 uint8_t reserved; 286 287 if (len < sizeof(tlv)) { 288 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 289 return (-1); 290 } 291 292 memcpy(&tlv, buf, TLV_HDR_SIZE); 293 tlv_type = ntohs(tlv.type); 294 tlv_len = ntohs(tlv.length); 295 if (tlv_len + TLV_HDR_SIZE > len) { 296 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 297 return (-1); 298 } 299 buf += TLV_HDR_SIZE; 300 len -= TLV_HDR_SIZE; 301 302 switch (tlv_type) { 303 case TLV_TYPE_TWCARD_CAP: 304 if (tlv_len != CAP_TLV_TWCARD_LEN) { 305 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 306 msg.type); 307 return (-1); 308 } 309 310 if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) { 311 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 312 msg.type); 313 return (-1); 314 } 315 caps_rcvd |= F_CAP_TLV_RCVD_TWCARD; 316 317 memcpy(&reserved, buf, sizeof(reserved)); 318 enable = reserved & STATE_BIT; 319 if (enable) 320 nbr->flags |= F_NBR_CAP_TWCARD; 321 else 322 nbr->flags &= ~F_NBR_CAP_TWCARD; 323 324 log_debug("%s: lsr-id %s %s the Typed Wildcard FEC " 325 "capability", __func__, inet_ntoa(nbr->id), 326 (enable) ? "announced" : "withdrew"); 327 break; 328 case TLV_TYPE_UNOTIF_CAP: 329 if (tlv_len != CAP_TLV_UNOTIF_LEN) { 330 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 331 msg.type); 332 return (-1); 333 } 334 335 if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) { 336 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 337 msg.type); 338 return (-1); 339 } 340 caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF; 341 342 memcpy(&reserved, buf, sizeof(reserved)); 343 enable = reserved & STATE_BIT; 344 if (enable) 345 nbr->flags |= F_NBR_CAP_UNOTIF; 346 else 347 nbr->flags &= ~F_NBR_CAP_UNOTIF; 348 349 log_debug("%s: lsr-id %s %s the Unrecognized " 350 "Notification capability", __func__, 351 inet_ntoa(nbr->id), (enable) ? "announced" : 352 "withdrew"); 353 break; 354 case TLV_TYPE_DYNAMIC_CAP: 355 /* 356 * RFC 5561 - Section 9: 357 * "An LDP speaker that receives a Capability message 358 * from a peer that includes the Dynamic Capability 359 * Announcement Parameter SHOULD silently ignore the 360 * parameter and process any other Capability Parameters 361 * in the message". 362 */ 363 /* FALLTHROUGH */ 364 default: 365 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 366 send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, 367 msg.id, msg.type, tlv_type, tlv_len, buf); 368 /* ignore unknown tlv */ 369 break; 370 } 371 buf += tlv_len; 372 len -= tlv_len; 373 } 374 375 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 376 377 return (0); 378 } 379 380 static int 381 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr) 382 { 383 struct sess_prms_tlv parms; 384 385 memset(&parms, 0, sizeof(parms)); 386 parms.type = htons(TLV_TYPE_COMMONSESSION); 387 parms.length = htons(SESS_PRMS_LEN); 388 parms.proto_version = htons(LDP_VERSION); 389 parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id)); 390 parms.reserved = 0; 391 parms.pvlim = 0; 392 parms.max_pdu_len = 0; 393 parms.lsr_id = nbr->id.s_addr; 394 parms.lspace_id = 0; 395 396 return (ibuf_add(buf, &parms, SESS_PRMS_SIZE)); 397 } 398 399 static int 400 gen_cap_dynamic_tlv(struct ibuf *buf) 401 { 402 struct capability_tlv cap; 403 404 memset(&cap, 0, sizeof(cap)); 405 cap.type = htons(TLV_TYPE_DYNAMIC_CAP); 406 cap.length = htons(CAP_TLV_DYNAMIC_LEN); 407 /* the S-bit is always 1 for the Dynamic Capability Announcement */ 408 cap.reserved = STATE_BIT; 409 410 return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE)); 411 } 412 413 static int 414 gen_cap_twcard_tlv(struct ibuf *buf, int enable) 415 { 416 struct capability_tlv cap; 417 418 memset(&cap, 0, sizeof(cap)); 419 cap.type = htons(TLV_TYPE_TWCARD_CAP); 420 cap.length = htons(CAP_TLV_TWCARD_LEN); 421 if (enable) 422 cap.reserved = STATE_BIT; 423 424 return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE)); 425 } 426 427 static int 428 gen_cap_unotif_tlv(struct ibuf *buf, int enable) 429 { 430 struct capability_tlv cap; 431 432 memset(&cap, 0, sizeof(cap)); 433 cap.type = htons(TLV_TYPE_UNOTIF_CAP); 434 cap.length = htons(CAP_TLV_UNOTIF_LEN); 435 if (enable) 436 cap.reserved = STATE_BIT; 437 438 return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE)); 439 } 440