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