1 /* $OpenBSD: init.c,v 1.14 2013/10/15 20:21:25 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 <sys/socket.h> 21 #include <sys/uio.h> 22 23 #include <netinet/in.h> 24 #include <netinet/in_systm.h> 25 #include <netinet/ip.h> 26 #include <arpa/inet.h> 27 #include <net/if_dl.h> 28 #include <unistd.h> 29 30 #include <errno.h> 31 #include <event.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "ldpd.h" 36 #include "ldp.h" 37 #include "log.h" 38 #include "ldpe.h" 39 40 extern struct ldpd_conf *leconf; 41 42 int gen_init_prms_tlv(struct ibuf *, struct nbr *, u_int16_t); 43 int tlv_decode_opt_init_prms(char *, u_int16_t); 44 45 void 46 send_init(struct nbr *nbr) 47 { 48 struct ibuf *buf; 49 u_int16_t size; 50 51 log_debug("send_init: neighbor ID %s", inet_ntoa(nbr->id)); 52 53 if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) 54 fatal("send_init"); 55 56 size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + SESS_PRMS_SIZE; 57 58 gen_ldp_hdr(buf, size); 59 60 size -= LDP_HDR_SIZE; 61 62 gen_msg_tlv(buf, MSG_TYPE_INIT, size); 63 64 size -= sizeof(struct ldp_msg); 65 66 gen_init_prms_tlv(buf, nbr, size); 67 68 evbuf_enqueue(&nbr->tcp->wbuf, buf); 69 } 70 71 int 72 recv_init(struct nbr *nbr, char *buf, u_int16_t len) 73 { 74 struct ldp_msg init; 75 struct sess_prms_tlv sess; 76 77 log_debug("recv_init: neighbor ID %s", inet_ntoa(nbr->id)); 78 79 bcopy(buf, &init, sizeof(init)); 80 81 buf += sizeof(struct ldp_msg); 82 len -= sizeof(struct ldp_msg); 83 84 if (len < SESS_PRMS_SIZE) { 85 session_shutdown(nbr, S_BAD_MSG_LEN, init.msgid, init.type); 86 return (-1); 87 } 88 bcopy(buf, &sess, sizeof(sess)); 89 90 if (ntohs(sess.length) != SESS_PRMS_SIZE - TLV_HDR_LEN || 91 ntohs(sess.length) > len - TLV_HDR_LEN) { 92 session_shutdown(nbr, S_BAD_TLV_LEN, init.msgid, init.type); 93 return (-1); 94 } 95 96 if (ntohs(sess.proto_version) != LDP_VERSION) { 97 session_shutdown(nbr, S_BAD_PROTO_VER, init.msgid, init.type); 98 return (-1); 99 } 100 101 buf += SESS_PRMS_SIZE; 102 len -= SESS_PRMS_SIZE; 103 104 /* just ignore all optional TLVs for now */ 105 if (tlv_decode_opt_init_prms(buf, len) == -1) { 106 session_shutdown(nbr, S_BAD_TLV_VAL, init.msgid, init.type); 107 return (-1); 108 } 109 110 nbr->keepalive = min(leconf->keepalive, ntohs(sess.keepalive_time)); 111 112 if (!nbr_pending_idtimer(nbr)) 113 nbr_fsm(nbr, NBR_EVT_INIT_RCVD); 114 115 return (ntohs(init.length)); 116 } 117 118 int 119 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr, u_int16_t size) 120 { 121 struct sess_prms_tlv parms; 122 123 /* We want just the size of the value */ 124 size -= TLV_HDR_LEN; 125 126 bzero(&parms, sizeof(parms)); 127 parms.type = htons(TLV_TYPE_COMMONSESSION); 128 parms.length = htons(size); 129 parms.proto_version = htons(LDP_VERSION); 130 parms.keepalive_time = htons(leconf->keepalive); 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 int 141 tlv_decode_opt_init_prms(char *buf, u_int16_t len) 142 { 143 struct tlv tlv; 144 int cons = 0; 145 u_int16_t tlv_len; 146 147 while (len >= sizeof(tlv)) { 148 bcopy(buf, &tlv, sizeof(tlv)); 149 tlv_len = ntohs(tlv.length); 150 switch (ntohs(tlv.type)) { 151 case TLV_TYPE_ATMSESSIONPAR: 152 log_warnx("ATM session parameter present"); 153 return (-1); 154 case TLV_TYPE_FRSESSION: 155 log_warnx("FR session parameter present"); 156 return (-1); 157 default: 158 /* if unknown flag set, ignore TLV */ 159 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 160 return (-1); 161 break; 162 } 163 buf += TLV_HDR_LEN + tlv_len; 164 len -= TLV_HDR_LEN + tlv_len; 165 cons += TLV_HDR_LEN + tlv_len; 166 } 167 168 return (cons); 169 } 170