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