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