]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/notification.c
4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
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.
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.
25 #include "ldp_debug.h"
27 static int gen_returned_tlvs(struct ibuf
*, uint16_t, uint16_t, char *);
28 static void log_msg_notification(int, struct nbr
*, struct notify_msg
*);
31 send_notification_full(struct tcp_conn
*tcp
, struct notify_msg
*nm
)
38 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ STATUS_SIZE
;
39 if (nm
->flags
& F_NOTIF_PW_STATUS
)
40 size
+= PW_STATUS_TLV_SIZE
;
41 if (nm
->flags
& F_NOTIF_FEC
)
42 size
+= len_fec_tlv(&nm
->fec
);
43 if (nm
->flags
& F_NOTIF_RETURNED_TLVS
)
44 size
+= TLV_HDR_SIZE
* 2 + nm
->rtlvs
.length
;
46 if ((buf
= ibuf_open(size
)) == NULL
)
49 err
|= gen_ldp_hdr(buf
, size
);
51 err
|= gen_msg_hdr(buf
, MSG_TYPE_NOTIFICATION
, size
);
52 err
|= gen_status_tlv(buf
, nm
->status_code
, nm
->msg_id
, nm
->msg_type
);
54 if (nm
->flags
& F_NOTIF_PW_STATUS
)
55 err
|= gen_pw_status_tlv(buf
, nm
->pw_status
);
56 if (nm
->flags
& F_NOTIF_FEC
)
57 err
|= gen_fec_tlv(buf
, &nm
->fec
);
58 if (nm
->flags
& F_NOTIF_RETURNED_TLVS
)
59 err
|= gen_returned_tlvs(buf
, nm
->rtlvs
.type
, nm
->rtlvs
.length
,
67 log_msg_notification(1, tcp
->nbr
, nm
);
68 nbr_fsm(tcp
->nbr
, NBR_EVT_PDU_SENT
);
69 tcp
->nbr
->stats
.notif_sent
++;
72 evbuf_enqueue(&tcp
->wbuf
, buf
);
75 /* send a notification without optional tlvs */
77 send_notification(struct tcp_conn
*tcp
, uint32_t status_code
, uint32_t msg_id
,
82 memset(&nm
, 0, sizeof(nm
));
83 nm
.status_code
= status_code
;
85 nm
.msg_type
= msg_type
;
87 send_notification_full(tcp
, &nm
);
91 send_notification_rtlvs(struct nbr
*nbr
, uint32_t status_code
, uint32_t msg_id
,
92 uint16_t msg_type
, uint16_t tlv_type
, uint16_t tlv_len
, char *tlv_data
)
96 memset(&nm
, 0, sizeof(nm
));
97 nm
.status_code
= status_code
;
99 nm
.msg_type
= msg_type
;
100 /* do not append the given TLV if it's too big (shouldn't happen) */
101 if (tlv_len
< 1024) {
102 nm
.rtlvs
.type
= tlv_type
;
103 nm
.rtlvs
.length
= tlv_len
;
104 nm
.rtlvs
.data
= tlv_data
;
105 nm
.flags
|= F_NOTIF_RETURNED_TLVS
;
108 send_notification_full(nbr
->tcp
, &nm
);
112 recv_notification(struct nbr
*nbr
, char *buf
, uint16_t len
)
115 struct status_tlv st
;
116 struct notify_msg nm
;
119 memcpy(&msg
, buf
, sizeof(msg
));
123 if (len
< STATUS_SIZE
) {
124 session_shutdown(nbr
, S_BAD_MSG_LEN
, msg
.id
, msg
.type
);
127 memcpy(&st
, buf
, sizeof(st
));
129 if (ntohs(st
.length
) > STATUS_SIZE
- TLV_HDR_SIZE
||
130 ntohs(st
.length
) > len
- TLV_HDR_SIZE
) {
131 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
137 memset(&nm
, 0, sizeof(nm
));
138 nm
.status_code
= ntohl(st
.status_code
);
140 /* Optional Parameters */
146 if (len
< sizeof(tlv
)) {
147 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
151 memcpy(&tlv
, buf
, TLV_HDR_SIZE
);
152 tlv_type
= ntohs(tlv
.type
);
153 tlv_len
= ntohs(tlv
.length
);
154 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
155 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
162 case TLV_TYPE_EXTSTATUS
:
163 case TLV_TYPE_RETURNEDPDU
:
164 case TLV_TYPE_RETURNEDMSG
:
165 /* TODO is there any use for this? */
167 case TLV_TYPE_PW_STATUS
:
169 session_shutdown(nbr
, S_BAD_TLV_LEN
,
174 nm
.pw_status
= ntohl(*(uint32_t *)buf
);
175 nm
.flags
|= F_NOTIF_PW_STATUS
;
178 if ((tlen
= tlv_decode_fec_elm(nbr
, &msg
, buf
,
179 tlv_len
, &nm
.fec
)) == -1)
181 /* allow only one fec element */
182 if (tlen
!= tlv_len
) {
183 session_shutdown(nbr
, S_BAD_TLV_VAL
,
187 nm
.flags
|= F_NOTIF_FEC
;
190 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
))
191 send_notification_rtlvs(nbr
, S_UNKNOWN_TLV
,
192 msg
.id
, msg
.type
, tlv_type
, tlv_len
, buf
);
193 /* ignore unknown tlv */
201 switch (nm
.status_code
) {
203 if (!(nm
.flags
& (F_NOTIF_PW_STATUS
|F_NOTIF_FEC
))) {
204 send_notification(nbr
->tcp
, S_MISS_MSG
,
209 switch (nm
.fec
.type
) {
213 send_notification(nbr
->tcp
, S_BAD_TLV_VAL
,
219 if (!(nm
.flags
& F_NOTIF_FEC
)) {
220 send_notification(nbr
->tcp
, S_MISS_MSG
,
224 if (nm
.fec
.type
!= MAP_TYPE_TYPED_WCARD
) {
225 send_notification(nbr
->tcp
, S_BAD_TLV_VAL
,
234 log_msg_notification(0, nbr
, &nm
);
236 if (st
.status_code
& htonl(STATUS_FATAL
)) {
237 if (nbr
->state
== NBR_STA_OPENSENT
)
238 nbr_start_idtimer(nbr
);
241 * RFC 5036 - Section 3.5.1.1:
242 * "When an LSR receives a Shutdown message during session
243 * initialization, it SHOULD transmit a Shutdown message and
244 * then close the transport connection".
246 if (nbr
->state
!= NBR_STA_OPER
&& nm
.status_code
== S_SHUTDOWN
)
247 send_notification(nbr
->tcp
, S_SHUTDOWN
,
250 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
254 /* lde needs to know about a few notification messages */
255 switch (nm
.status_code
) {
258 ldpe_imsg_compose_lde(IMSG_NOTIFICATION
, nbr
->peerid
, 0,
269 gen_status_tlv(struct ibuf
*buf
, uint32_t status_code
, uint32_t msg_id
,
272 struct status_tlv st
;
274 memset(&st
, 0, sizeof(st
));
275 st
.type
= htons(TLV_TYPE_STATUS
);
276 st
.length
= htons(STATUS_TLV_LEN
);
277 st
.status_code
= htonl(status_code
);
279 * For convenience, msg_id and msg_type are already in network
283 st
.msg_type
= msg_type
;
285 return (ibuf_add(buf
, &st
, STATUS_SIZE
));
289 gen_returned_tlvs(struct ibuf
*buf
, uint16_t type
, uint16_t length
,
296 rtlvs
.type
= htons(TLV_TYPE_RETURNED_TLVS
);
297 rtlvs
.length
= htons(length
+ TLV_HDR_SIZE
);
298 tlv
.type
= htons(type
);
299 tlv
.length
= htons(length
);
301 err
= ibuf_add(buf
, &rtlvs
, sizeof(rtlvs
));
302 err
|= ibuf_add(buf
, &tlv
, sizeof(tlv
));
303 err
|= ibuf_add(buf
, tlv_data
, length
);
309 log_msg_notification(int out
, struct nbr
*nbr
, struct notify_msg
*nm
)
311 if (nm
->status_code
& STATUS_FATAL
) {
312 debug_msg(out
, "notification: lsr-id %s, status %s "
313 "(fatal error)", inet_ntoa(nbr
->id
),
314 status_code_name(nm
->status_code
));
318 debug_msg(out
, "notification: lsr-id %s, status %s",
319 inet_ntoa(nbr
->id
), status_code_name(nm
->status_code
));
320 if (nm
->flags
& F_NOTIF_FEC
)
321 debug_msg(out
, "notification: fec %s", log_map(&nm
->fec
));
322 if (nm
->flags
& F_NOTIF_PW_STATUS
)
323 debug_msg(out
, "notification: pw-status %s",
324 (nm
->pw_status
) ? "not forwarding" : "forwarding");