]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/notification.c
af5bb267d7a8e30fbc2e246b7f974ed827a8cf95
1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
14 #include "ldp_debug.h"
16 static int gen_returned_tlvs(struct ibuf
*, uint16_t, uint16_t, char *);
17 static void log_msg_notification(int, struct nbr
*, struct notify_msg
*);
20 send_notification_full(struct tcp_conn
*tcp
, struct notify_msg
*nm
)
27 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ STATUS_SIZE
;
28 if (nm
->flags
& F_NOTIF_PW_STATUS
)
29 size
+= PW_STATUS_TLV_SIZE
;
30 if (nm
->flags
& F_NOTIF_FEC
)
31 size
+= len_fec_tlv(&nm
->fec
);
32 if (nm
->flags
& F_NOTIF_RETURNED_TLVS
)
33 size
+= TLV_HDR_SIZE
* 2 + nm
->rtlvs
.length
;
35 if ((buf
= ibuf_open(size
)) == NULL
)
38 err
|= gen_ldp_hdr(buf
, size
);
40 err
|= gen_msg_hdr(buf
, MSG_TYPE_NOTIFICATION
, size
);
41 err
|= gen_status_tlv(buf
, nm
->status_code
, nm
->msg_id
, nm
->msg_type
);
43 if (nm
->flags
& F_NOTIF_PW_STATUS
)
44 err
|= gen_pw_status_tlv(buf
, nm
->pw_status
);
45 if (nm
->flags
& F_NOTIF_FEC
)
46 err
|= gen_fec_tlv(buf
, &nm
->fec
);
47 if (nm
->flags
& F_NOTIF_RETURNED_TLVS
)
48 err
|= gen_returned_tlvs(buf
, nm
->rtlvs
.type
, nm
->rtlvs
.length
,
56 log_msg_notification(1, tcp
->nbr
, nm
);
57 nbr_fsm(tcp
->nbr
, NBR_EVT_PDU_SENT
);
58 tcp
->nbr
->stats
.notif_sent
++;
61 /* update SNMP session counters */
62 switch (nm
->status_code
) {
64 leconf
->stats
.session_rejects_hello
++;
67 leconf
->stats
.bad_ldp_id
++;
70 leconf
->stats
.bad_pdu_len
++;
73 leconf
->stats
.bad_msg_len
++;
76 leconf
->stats
.bad_tlv_len
++;
79 leconf
->stats
.malformed_tlv
++;
82 leconf
->stats
.keepalive_timer_exp
++;
85 leconf
->stats
.shutdown_send_notify
++;
91 evbuf_enqueue(&tcp
->wbuf
, buf
);
94 /* send a notification without optional tlvs */
96 send_notification(struct tcp_conn
*tcp
, uint32_t status_code
, uint32_t msg_id
,
101 memset(&nm
, 0, sizeof(nm
));
102 nm
.status_code
= status_code
;
104 nm
.msg_type
= msg_type
;
106 send_notification_full(tcp
, &nm
);
110 send_notification_rtlvs(struct nbr
*nbr
, uint32_t status_code
, uint32_t msg_id
,
111 uint16_t msg_type
, uint16_t tlv_type
, uint16_t tlv_len
, char *tlv_data
)
113 struct notify_msg nm
;
115 memset(&nm
, 0, sizeof(nm
));
116 nm
.status_code
= status_code
;
118 nm
.msg_type
= msg_type
;
119 /* do not append the given TLV if it's too big (shouldn't happen) */
120 if (tlv_len
< 1024) {
121 nm
.rtlvs
.type
= tlv_type
;
122 nm
.rtlvs
.length
= tlv_len
;
123 nm
.rtlvs
.data
= tlv_data
;
124 nm
.flags
|= F_NOTIF_RETURNED_TLVS
;
127 send_notification_full(nbr
->tcp
, &nm
);
131 recv_notification(struct nbr
*nbr
, char *buf
, uint16_t len
)
134 struct status_tlv st
;
135 struct notify_msg nm
;
138 memcpy(&msg
, buf
, sizeof(msg
));
142 if (len
< STATUS_SIZE
) {
143 session_shutdown(nbr
, S_BAD_MSG_LEN
, msg
.id
, msg
.type
);
144 leconf
->stats
.bad_msg_len
++;
147 memcpy(&st
, buf
, sizeof(st
));
149 if (ntohs(st
.length
) > STATUS_SIZE
- TLV_HDR_SIZE
||
150 ntohs(st
.length
) > len
- TLV_HDR_SIZE
) {
151 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
152 leconf
->stats
.bad_tlv_len
++;
158 memset(&nm
, 0, sizeof(nm
));
159 nm
.status_code
= ntohl(st
.status_code
);
161 /* Optional Parameters */
167 if (len
< sizeof(tlv
)) {
168 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
169 leconf
->stats
.bad_tlv_len
++;
173 memcpy(&tlv
, buf
, TLV_HDR_SIZE
);
174 tlv_type
= ntohs(tlv
.type
);
175 tlv_len
= ntohs(tlv
.length
);
176 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
177 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
178 leconf
->stats
.bad_tlv_len
++;
185 case TLV_TYPE_EXTSTATUS
:
186 case TLV_TYPE_RETURNEDPDU
:
187 case TLV_TYPE_RETURNEDMSG
:
188 /* TODO is there any use for this? */
190 case TLV_TYPE_PW_STATUS
:
192 session_shutdown(nbr
, S_BAD_TLV_LEN
,
197 nm
.pw_status
= ntohl(*(uint32_t *)buf
);
198 nm
.flags
|= F_NOTIF_PW_STATUS
;
201 if ((tlen
= tlv_decode_fec_elm(nbr
, &msg
, buf
,
202 tlv_len
, &nm
.fec
)) == -1)
204 /* allow only one fec element */
205 if (tlen
!= tlv_len
) {
206 session_shutdown(nbr
, S_BAD_TLV_VAL
,
208 leconf
->stats
.bad_tlv_len
++;
211 nm
.flags
|= F_NOTIF_FEC
;
214 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
)) {
215 nbr
->stats
.unknown_tlv
++;
216 send_notification_rtlvs(nbr
, S_UNKNOWN_TLV
,
217 msg
.id
, msg
.type
, tlv_type
, tlv_len
, buf
);
219 /* ignore unknown tlv */
227 switch (nm
.status_code
) {
229 if (!(nm
.flags
& (F_NOTIF_PW_STATUS
|F_NOTIF_FEC
))) {
230 send_notification(nbr
->tcp
, S_MISS_MSG
,
235 switch (nm
.fec
.type
) {
239 send_notification(nbr
->tcp
, S_BAD_TLV_VAL
,
245 if (!(nm
.flags
& F_NOTIF_FEC
)) {
246 send_notification(nbr
->tcp
, S_MISS_MSG
,
250 if (nm
.fec
.type
!= MAP_TYPE_TYPED_WCARD
) {
251 send_notification(nbr
->tcp
, S_BAD_TLV_VAL
,
260 log_msg_notification(0, nbr
, &nm
);
262 if (st
.status_code
& htonl(STATUS_FATAL
)) {
263 if (nbr
->state
== NBR_STA_OPENSENT
)
264 nbr_start_idtimer(nbr
);
267 * RFC 5036 - Section 3.5.1.1:
268 * "When an LSR receives a Shutdown message during session
269 * initialization, it SHOULD transmit a Shutdown message and
270 * then close the transport connection".
272 if (nbr
->state
!= NBR_STA_OPER
&&
273 nm
.status_code
== S_SHUTDOWN
) {
274 leconf
->stats
.session_attempts
++;
275 send_notification(nbr
->tcp
, S_SHUTDOWN
,
279 leconf
->stats
.shutdown_rcv_notify
++;
280 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
284 /* lde needs to know about a few notification messages
285 * and update SNMP session counters
287 switch (nm
.status_code
) {
290 ldpe_imsg_compose_lde(IMSG_NOTIFICATION
, nbr
->peerid
, 0,
294 leconf
->stats
.session_rejects_hello
++;
296 case S_PARM_ADV_MODE
:
297 leconf
->stats
.session_rejects_ad
++;
300 leconf
->stats
.session_rejects_max_pdu
++;
303 leconf
->stats
.session_rejects_lr
++;
306 leconf
->stats
.bad_ldp_id
++;
309 leconf
->stats
.bad_pdu_len
++;
312 leconf
->stats
.bad_msg_len
++;
315 leconf
->stats
.bad_tlv_len
++;
318 leconf
->stats
.malformed_tlv
++;
321 leconf
->stats
.shutdown_rcv_notify
++;
331 gen_status_tlv(struct ibuf
*buf
, uint32_t status_code
, uint32_t msg_id
,
334 struct status_tlv st
;
336 memset(&st
, 0, sizeof(st
));
337 st
.type
= htons(TLV_TYPE_STATUS
);
338 st
.length
= htons(STATUS_TLV_LEN
);
339 st
.status_code
= htonl(status_code
);
341 * For convenience, msg_id and msg_type are already in network
345 st
.msg_type
= msg_type
;
347 return (ibuf_add(buf
, &st
, STATUS_SIZE
));
351 gen_returned_tlvs(struct ibuf
*buf
, uint16_t type
, uint16_t length
,
358 rtlvs
.type
= htons(TLV_TYPE_RETURNED_TLVS
);
359 rtlvs
.length
= htons(length
+ TLV_HDR_SIZE
);
360 tlv
.type
= htons(type
);
361 tlv
.length
= htons(length
);
363 err
= ibuf_add(buf
, &rtlvs
, sizeof(rtlvs
));
364 err
|= ibuf_add(buf
, &tlv
, sizeof(tlv
));
365 err
|= ibuf_add(buf
, tlv_data
, length
);
371 log_msg_notification(int out
, struct nbr
*nbr
, struct notify_msg
*nm
)
373 if (nm
->status_code
& STATUS_FATAL
) {
374 debug_msg(out
, "notification: lsr-id %pI4, status %s (fatal error)", &nbr
->id
,
375 status_code_name(nm
->status_code
));
379 debug_msg(out
, "notification: lsr-id %pI4, status %s",
380 &nbr
->id
, status_code_name(nm
->status_code
));
381 if (nm
->flags
& F_NOTIF_FEC
)
382 debug_msg(out
, "notification: fec %s", log_map(&nm
->fec
));
383 if (nm
->flags
& F_NOTIF_PW_STATUS
)
384 debug_msg(out
, "notification: pw-status %s",
385 (nm
->pw_status
== PW_FORWARDING
) ? "forwarding" : "not forwarding");