]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/address.c
1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
14 #include "ldp_debug.h"
16 static void send_address(struct nbr
*, int, struct if_addr_head
*,
18 static int gen_address_list_tlv(struct ibuf
*, int, struct if_addr_head
*,
20 static int gen_mac_list_tlv(struct ibuf
*, uint8_t *);
21 static void address_list_add(struct if_addr_head
*, struct if_addr
*);
22 static void address_list_clr(struct if_addr_head
*);
23 static void log_msg_address(int, uint16_t, struct nbr
*, int,
25 static void log_msg_mac_withdrawal(int, struct nbr
*, uint8_t *);
28 send_address(struct nbr
*nbr
, int af
, struct if_addr_head
*addr_list
,
29 unsigned int addr_count
, int withdraw
)
34 struct if_addr
*if_addr
;
36 unsigned int tlv_addr_count
= 0;
40 if (LIST_EMPTY(addr_list
))
44 msg_type
= MSG_TYPE_ADDR
;
46 msg_type
= MSG_TYPE_ADDRWITHDRAW
;
50 addr_size
= sizeof(struct in_addr
);
53 addr_size
= sizeof(struct in6_addr
);
56 fatalx("send_address: unknown af");
59 while (LIST_FIRST(addr_list
) != NULL
) {
61 * Send as many addresses as possible - respect the session's
62 * negotiated maximum pdu length.
64 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ ADDR_LIST_SIZE
;
65 if (size
+ addr_count
* addr_size
<= nbr
->max_pdu_len
)
66 tlv_addr_count
= addr_count
;
68 tlv_addr_count
= (nbr
->max_pdu_len
- size
) / addr_size
;
69 size
+= tlv_addr_count
* addr_size
;
70 addr_count
-= tlv_addr_count
;
72 if ((buf
= ibuf_open(size
)) == NULL
)
75 SET_FLAG(err
, gen_ldp_hdr(buf
, size
));
77 SET_FLAG(err
, gen_msg_hdr(buf
, msg_type
, size
));
79 SET_FLAG(err
, gen_address_list_tlv(buf
, af
, addr_list
, tlv_addr_count
));
83 address_list_clr(addr_list
);
88 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
89 log_msg_address(1, msg_type
, nbr
, af
, &if_addr
->addr
);
91 LIST_REMOVE(if_addr
, entry
);
92 assert(if_addr
!= LIST_FIRST(addr_list
));
94 if (--tlv_addr_count
== 0)
98 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
100 /* no errors - update per neighbor message counters */
103 nbr
->stats
.addr_sent
++;
105 case MSG_TYPE_ADDRWITHDRAW
:
106 nbr
->stats
.addrwdraw_sent
++;
113 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
117 send_address_single(struct nbr
*nbr
, struct if_addr
*if_addr
, int withdraw
)
119 struct if_addr_head addr_list
;
121 LIST_INIT(&addr_list
);
122 address_list_add(&addr_list
, if_addr
);
123 send_address(nbr
, if_addr
->af
, &addr_list
, 1, withdraw
);
127 send_address_all(struct nbr
*nbr
, int af
)
129 struct if_addr_head addr_list
;
130 struct if_addr
*if_addr
;
131 unsigned int addr_count
= 0;
133 LIST_INIT(&addr_list
);
134 LIST_FOREACH(if_addr
, &global
.addr_list
, entry
) {
135 if (if_addr
->af
!= af
)
138 address_list_add(&addr_list
, if_addr
);
142 send_address(nbr
, af
, &addr_list
, addr_count
, 0);
146 send_mac_withdrawal(struct nbr
*nbr
, struct map
*fec
, uint8_t *mac
)
152 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ ADDR_LIST_SIZE
+ len_fec_tlv(fec
) +
157 if ((buf
= ibuf_open(size
)) == NULL
)
160 err
= gen_ldp_hdr(buf
, size
);
161 size
-= LDP_HDR_SIZE
;
163 SET_FLAG(err
, gen_msg_hdr(buf
, MSG_TYPE_ADDRWITHDRAW
, size
));
164 SET_FLAG(err
, gen_address_list_tlv(buf
, AF_INET
, NULL
, 0));
165 SET_FLAG(err
, gen_fec_tlv(buf
, fec
));
166 SET_FLAG(err
, gen_mac_list_tlv(buf
, mac
));
173 log_msg_mac_withdrawal(1, nbr
, mac
);
175 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
177 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
181 recv_address(struct nbr
*nbr
, char *buf
, uint16_t len
)
186 struct address_list_tlv alt
;
189 struct lde_addr lde_addr
;
191 memcpy(&msg
, buf
, sizeof(msg
));
192 msg_type
= ntohs(msg
.type
);
195 type
= IMSG_ADDRESS_ADD
;
197 case MSG_TYPE_ADDRWITHDRAW
:
198 type
= IMSG_ADDRESS_DEL
;
201 fatalx("recv_address: unexpected msg type");
206 /* Address List TLV */
207 if (len
< ADDR_LIST_SIZE
) {
208 session_shutdown(nbr
, S_BAD_MSG_LEN
, msg
.id
, msg
.type
);
211 memcpy(&alt
, buf
, sizeof(alt
));
212 alt_len
= ntohs(alt
.length
);
213 alt_family
= ntohs(alt
.family
);
214 if (alt_len
> len
- TLV_HDR_SIZE
) {
215 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
218 if (ntohs(alt
.type
) != TLV_TYPE_ADDRLIST
) {
219 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
.id
, msg
.type
);
222 switch (alt_family
) {
224 if (!nbr
->v4_enabled
)
225 /* just ignore the message */
229 if (!nbr
->v6_enabled
)
230 /* just ignore the message */
234 send_notification(nbr
->tcp
, S_UNSUP_ADDR
, msg
.id
, msg
.type
);
237 alt_len
-= sizeof(alt
.family
);
241 /* Process all received addresses */
242 while (alt_len
> 0) {
243 switch (alt_family
) {
245 if (alt_len
< sizeof(struct in_addr
)) {
246 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
251 memset(&lde_addr
, 0, sizeof(lde_addr
));
252 lde_addr
.af
= AF_INET
;
253 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in_addr
));
255 buf
+= sizeof(struct in_addr
);
256 len
-= sizeof(struct in_addr
);
257 alt_len
-= sizeof(struct in_addr
);
260 if (alt_len
< sizeof(struct in6_addr
)) {
261 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
266 memset(&lde_addr
, 0, sizeof(lde_addr
));
267 lde_addr
.af
= AF_INET6
;
268 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in6_addr
));
270 buf
+= sizeof(struct in6_addr
);
271 len
-= sizeof(struct in6_addr
);
272 alt_len
-= sizeof(struct in6_addr
);
275 fatalx("recv_address: unknown af");
278 log_msg_address(0, msg_type
, nbr
, lde_addr
.af
, &lde_addr
.addr
);
280 ldpe_imsg_compose_lde(type
, nbr
->peerid
, 0, &lde_addr
,
284 /* Optional Parameters */
290 if (len
< sizeof(tlv
)) {
291 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
295 memcpy(&tlv
, buf
, TLV_HDR_SIZE
);
296 tlv_type
= ntohs(tlv
.type
);
297 tlv_len
= ntohs(tlv
.length
);
298 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
299 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
307 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
))
308 send_notification_rtlvs(nbr
, S_UNKNOWN_TLV
,
309 msg
.id
, msg
.type
, tlv_type
, tlv_len
, buf
);
310 /* ignore unknown tlv */
321 gen_address_list_tlv(struct ibuf
*buf
, int af
, struct if_addr_head
*addr_list
,
322 unsigned int tlv_addr_count
)
324 struct address_list_tlv alt
;
326 struct if_addr
*if_addr
;
329 memset(&alt
, 0, sizeof(alt
));
330 alt
.type
= htons(TLV_TYPE_ADDRLIST
);
334 alt
.family
= htons(AF_IPV4
);
335 addr_size
= sizeof(struct in_addr
);
338 alt
.family
= htons(AF_IPV6
);
339 addr_size
= sizeof(struct in6_addr
);
342 fatalx("gen_address_list_tlv: unknown af");
344 alt
.length
= htons(sizeof(alt
.family
) + addr_size
* tlv_addr_count
);
346 SET_FLAG(err
, ibuf_add(buf
, &alt
, sizeof(alt
)));
348 if (addr_list
== NULL
)
351 LIST_FOREACH(if_addr
, addr_list
, entry
) {
352 SET_FLAG(err
, ibuf_add(buf
, &if_addr
->addr
, addr_size
));
354 if (--tlv_addr_count
== 0)
362 gen_mac_list_tlv(struct ibuf
*buf
, uint8_t *mac
)
367 memset(&tlv
, 0, sizeof(tlv
));
368 tlv
.type
= htons(TLV_TYPE_MAC_LIST
);
370 tlv
.length
= htons(ETH_ALEN
);
371 err
= ibuf_add(buf
, &tlv
, sizeof(tlv
));
373 SET_FLAG(err
, ibuf_add(buf
, mac
, ETH_ALEN
));
379 address_list_add(struct if_addr_head
*addr_list
, struct if_addr
*if_addr
)
383 new = malloc(sizeof(*new));
388 LIST_INSERT_HEAD(addr_list
, new, entry
);
392 address_list_clr(struct if_addr_head
*addr_list
)
394 struct if_addr
*if_addr
;
396 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
397 LIST_REMOVE(if_addr
, entry
);
398 assert(if_addr
!= LIST_FIRST(addr_list
));
404 log_msg_address(int out
, uint16_t msg_type
, struct nbr
*nbr
, int af
,
405 union ldpd_addr
*addr
)
407 debug_msg(out
, "%s: lsr-id %pI4, address %s", msg_name(msg_type
),
408 &nbr
->id
, log_addr(af
, addr
));
412 log_msg_mac_withdrawal(int out
, struct nbr
*nbr
, uint8_t *mac
)
414 char buf
[ETHER_ADDR_STRLEN
];
416 debug_msg(out
, "mac withdrawal: lsr-id %pI4, mac %s", &nbr
->id
,
417 (mac
) ? prefix_mac2str((struct ethaddr
*)mac
, buf
, sizeof(buf
)) :