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
send_init(struct nbr * nbr)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
recv_init(struct nbr * nbr,char * buf,uint16_t len)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
send_capability(struct nbr * nbr,uint16_t capability,int enable)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
recv_capability(struct nbr * nbr,char * buf,uint16_t len)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
gen_init_prms_tlv(struct ibuf * buf,struct nbr * nbr)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
gen_cap_dynamic_tlv(struct ibuf * buf)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
gen_cap_twcard_tlv(struct ibuf * buf,int enable)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
gen_cap_unotif_tlv(struct ibuf * buf,int enable)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