xref: /openbsd-src/usr.sbin/ldpd/init.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: init.c,v 1.33 2016/07/16 19:20:16 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 
29 void
30 send_init(struct nbr *nbr)
31 {
32 	struct ibuf		*buf;
33 	uint16_t		 size;
34 	int			 err = 0;
35 
36 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
37 
38 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
39 	if ((buf = ibuf_open(size)) == NULL)
40 		fatal(__func__);
41 
42 	err |= gen_ldp_hdr(buf, size);
43 	size -= LDP_HDR_SIZE;
44 	err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
45 	size -= LDP_MSG_SIZE;
46 	err |= gen_init_prms_tlv(buf, nbr);
47 	if (err) {
48 		ibuf_free(buf);
49 		return;
50 	}
51 
52 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
53 }
54 
55 int
56 recv_init(struct nbr *nbr, char *buf, uint16_t len)
57 {
58 	struct ldp_msg		msg;
59 	struct sess_prms_tlv	sess;
60 	uint16_t		max_pdu_len;
61 
62 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
63 
64 	memcpy(&msg, buf, sizeof(msg));
65 	buf += LDP_MSG_SIZE;
66 	len -= LDP_MSG_SIZE;
67 
68 	if (len < SESS_PRMS_SIZE) {
69 		session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
70 		return (-1);
71 	}
72 	memcpy(&sess, buf, sizeof(sess));
73 	if (ntohs(sess.length) != SESS_PRMS_LEN) {
74 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
75 		return (-1);
76 	}
77 	if (ntohs(sess.proto_version) != LDP_VERSION) {
78 		session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type);
79 		return (-1);
80 	}
81 	if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) {
82 		session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);
83 		return (-1);
84 	}
85 	if (sess.lsr_id != leconf->rtr_id.s_addr ||
86 	    ntohs(sess.lspace_id) != 0) {
87 		session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);
88 		return (-1);
89 	}
90 
91 	buf += SESS_PRMS_SIZE;
92 	len -= SESS_PRMS_SIZE;
93 
94 	/* Optional Parameters */
95 	while (len > 0) {
96 		struct tlv 	tlv;
97 		uint16_t	tlv_len;
98 
99 		if (len < sizeof(tlv)) {
100 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
101 			return (-1);
102 		}
103 
104 		memcpy(&tlv, buf, TLV_HDR_SIZE);
105 		tlv_len = ntohs(tlv.length);
106 		if (tlv_len + TLV_HDR_SIZE > len) {
107 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
108 			return (-1);
109 		}
110 		buf += TLV_HDR_SIZE;
111 		len -= TLV_HDR_SIZE;
112 
113 		switch (ntohs(tlv.type)) {
114 		case TLV_TYPE_ATMSESSIONPAR:
115 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
116 			return (-1);
117 		case TLV_TYPE_FRSESSION:
118 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
119 			return (-1);
120 		default:
121 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
122 				send_notification_nbr(nbr, S_UNKNOWN_TLV,
123 				    msg.id, msg.type);
124 			/* ignore unknown tlv */
125 			break;
126 		}
127 		buf += tlv_len;
128 		len -= tlv_len;
129 	}
130 
131 	nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
132 	    ntohs(sess.keepalive_time));
133 
134 	max_pdu_len = ntohs(sess.max_pdu_len);
135 	/*
136 	 * RFC 5036 - Section 3.5.3:
137 	 * "A value of 255 or less specifies the default maximum length of
138 	 * 4096 octets".
139 	 */
140 	if (max_pdu_len <= 255)
141 		max_pdu_len = LDP_MAX_LEN;
142 	nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
143 
144 	nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
145 
146 	return (0);
147 }
148 
149 static int
150 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
151 {
152 	struct sess_prms_tlv	parms;
153 
154 	memset(&parms, 0, sizeof(parms));
155 	parms.type = htons(TLV_TYPE_COMMONSESSION);
156 	parms.length = htons(SESS_PRMS_LEN);
157 	parms.proto_version = htons(LDP_VERSION);
158 	parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id));
159 	parms.reserved = 0;
160 	parms.pvlim = 0;
161 	parms.max_pdu_len = 0;
162 	parms.lsr_id = nbr->id.s_addr;
163 	parms.lspace_id = 0;
164 
165 	return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
166 }
167