]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/init.c
Zebra: Data structures for RMAC processing in FPM
[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 %s", inet_ntoa(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 %s", inet_ntoa(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 %s announced the Dynamic "
150 "Capability Announcement capability", __func__,
151 inet_ntoa(nbr->id));
152 break;
153 case TLV_TYPE_TWCARD_CAP:
154 if (tlv_len != CAP_TLV_TWCARD_LEN) {
155 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
156 msg.type);
157 return (-1);
158 }
159
160 if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
161 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
162 msg.type);
163 return (-1);
164 }
165 caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
166
167 nbr->flags |= F_NBR_CAP_TWCARD;
168
169 log_debug("%s: lsr-id %s announced the Typed Wildcard "
170 "FEC capability", __func__, inet_ntoa(nbr->id));
171 break;
172 case TLV_TYPE_UNOTIF_CAP:
173 if (tlv_len != CAP_TLV_UNOTIF_LEN) {
174 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
175 msg.type);
176 return (-1);
177 }
178
179 if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
180 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
181 msg.type);
182 return (-1);
183 }
184 caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
185
186 nbr->flags |= F_NBR_CAP_UNOTIF;
187
188 log_debug("%s: lsr-id %s announced the Unrecognized "
189 "Notification capability", __func__,
190 inet_ntoa(nbr->id));
191 break;
192 default:
193 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
194 send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
195 msg.id, msg.type, tlv_type, tlv_len, buf);
196 /* ignore unknown tlv */
197 break;
198 }
199 buf += tlv_len;
200 len -= tlv_len;
201 }
202
203 nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
204 ntohs(sess.keepalive_time));
205
206 max_pdu_len = ntohs(sess.max_pdu_len);
207 /*
208 * RFC 5036 - Section 3.5.3:
209 * "A value of 255 or less specifies the default maximum length of
210 * 4096 octets".
211 */
212 if (max_pdu_len <= 255)
213 max_pdu_len = LDP_MAX_LEN;
214 nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
215
216 nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
217
218 return (0);
219 }
220
221 void
222 send_capability(struct nbr *nbr, uint16_t capability, int enable)
223 {
224 struct ibuf *buf;
225 uint16_t size;
226 int err = 0;
227
228 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
229
230 size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
231 if ((buf = ibuf_open(size)) == NULL)
232 fatal(__func__);
233
234 err |= gen_ldp_hdr(buf, size);
235 size -= LDP_HDR_SIZE;
236 err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
237
238 switch (capability) {
239 case TLV_TYPE_TWCARD_CAP:
240 err |= gen_cap_twcard_tlv(buf, enable);
241 break;
242 case TLV_TYPE_UNOTIF_CAP:
243 err |= gen_cap_unotif_tlv(buf, enable);
244 break;
245 case TLV_TYPE_DYNAMIC_CAP:
246 /*
247 * RFC 5561 - Section 9:
248 * "An LDP speaker MUST NOT include the Dynamic Capability
249 * Announcement Parameter in Capability messages sent to
250 * its peers".
251 */
252 /* FALLTHROUGH */
253 default:
254 fatalx("send_capability: unsupported capability");
255 }
256
257 if (err) {
258 ibuf_free(buf);
259 return;
260 }
261
262 evbuf_enqueue(&nbr->tcp->wbuf, buf);
263 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
264 nbr->stats.capability_sent++;
265 }
266
267 int
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
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
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
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
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 }