xref: /openbsd-src/usr.sbin/ldpd/init.c (revision fb8aa7497fded39583f40e800732f9c046411717)
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