]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/address.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / ldpd / address.c
CommitLineData
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 "lde.h"
13#include "log.h"
eac6e3f0 14#include "ldp_debug.h"
8429abe0
RW
15
16static void send_address(struct nbr *, int, struct if_addr_head *,
17 unsigned int, int);
26519d8c
RW
18static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
19 unsigned int);
20static int gen_mac_list_tlv(struct ibuf *, uint8_t *);
8429abe0
RW
21static void address_list_add(struct if_addr_head *, struct if_addr *);
22static void address_list_clr(struct if_addr_head *);
faf75793
RW
23static void log_msg_address(int, uint16_t, struct nbr *, int,
24 union ldpd_addr *);
26519d8c 25static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
8429abe0
RW
26
27static void
28send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
29 unsigned int addr_count, int withdraw)
30{
31 struct ibuf *buf;
32 uint16_t msg_type;
33 uint8_t addr_size;
34 struct if_addr *if_addr;
35 uint16_t size;
36 unsigned int tlv_addr_count = 0;
37 int err = 0;
38
39 /* nothing to send */
40 if (LIST_EMPTY(addr_list))
41 return;
42
43 if (!withdraw)
44 msg_type = MSG_TYPE_ADDR;
45 else
46 msg_type = MSG_TYPE_ADDRWITHDRAW;
47
48 switch (af) {
49 case AF_INET:
50 addr_size = sizeof(struct in_addr);
51 break;
52 case AF_INET6:
53 addr_size = sizeof(struct in6_addr);
54 break;
55 default:
56 fatalx("send_address: unknown af");
57 }
58
f67de3ee 59 while (LIST_FIRST(addr_list) != NULL) {
8429abe0
RW
60 /*
61 * Send as many addresses as possible - respect the session's
62 * negotiated maximum pdu length.
63 */
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;
67 else
68 tlv_addr_count = (nbr->max_pdu_len - size) / addr_size;
69 size += tlv_addr_count * addr_size;
70 addr_count -= tlv_addr_count;
71
72 if ((buf = ibuf_open(size)) == NULL)
73 fatal(__func__);
74
ee60199a 75 SET_FLAG(err, gen_ldp_hdr(buf, size));
8429abe0 76 size -= LDP_HDR_SIZE;
ee60199a 77 SET_FLAG(err, gen_msg_hdr(buf, msg_type, size));
8429abe0 78 size -= LDP_MSG_SIZE;
ee60199a 79 SET_FLAG(err, gen_address_list_tlv(buf, af, addr_list, tlv_addr_count));
e3df3ba6 80 (void)size;
ee60199a 81
8429abe0
RW
82 if (err) {
83 address_list_clr(addr_list);
84 ibuf_free(buf);
85 return;
86 }
87
88 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
faf75793 89 log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
8429abe0
RW
90
91 LIST_REMOVE(if_addr, entry);
11bf8e13 92 assert(if_addr != LIST_FIRST(addr_list));
8429abe0
RW
93 free(if_addr);
94 if (--tlv_addr_count == 0)
95 break;
96 }
97
98 evbuf_enqueue(&nbr->tcp->wbuf, buf);
0f7b5df9
RW
99
100 /* no errors - update per neighbor message counters */
101 switch (msg_type) {
102 case MSG_TYPE_ADDR:
103 nbr->stats.addr_sent++;
104 break;
105 case MSG_TYPE_ADDRWITHDRAW:
106 nbr->stats.addrwdraw_sent++;
107 break;
108 default:
109 break;
110 }
8429abe0
RW
111 }
112
113 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
114}
115
116void
117send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
118{
119 struct if_addr_head addr_list;
120
121 LIST_INIT(&addr_list);
122 address_list_add(&addr_list, if_addr);
123 send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
124}
125
126void
127send_address_all(struct nbr *nbr, int af)
128{
129 struct if_addr_head addr_list;
130 struct if_addr *if_addr;
131 unsigned int addr_count = 0;
132
133 LIST_INIT(&addr_list);
134 LIST_FOREACH(if_addr, &global.addr_list, entry) {
135 if (if_addr->af != af)
136 continue;
137
138 address_list_add(&addr_list, if_addr);
139 addr_count++;
140 }
141
142 send_address(nbr, af, &addr_list, addr_count, 0);
143}
144
26519d8c
RW
145void
146send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
147{
148 struct ibuf *buf;
149 uint16_t size;
150 int err;
151
152 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
153 TLV_HDR_SIZE;
154 if (mac)
9bff8057 155 size += ETH_ALEN;
26519d8c
RW
156
157 if ((buf = ibuf_open(size)) == NULL)
158 fatal(__func__);
159
160 err = gen_ldp_hdr(buf, size);
161 size -= LDP_HDR_SIZE;
ee60199a 162
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));
167
26519d8c
RW
168 if (err) {
169 ibuf_free(buf);
170 return;
171 }
172
173 log_msg_mac_withdrawal(1, nbr, mac);
174
175 evbuf_enqueue(&nbr->tcp->wbuf, buf);
176
177 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
178}
179
8429abe0
RW
180int
181recv_address(struct nbr *nbr, char *buf, uint16_t len)
182{
183 struct ldp_msg msg;
184 uint16_t msg_type;
8429abe0 185 enum imsg_type type;
fd1cf443
RW
186 struct address_list_tlv alt;
187 uint16_t alt_len;
188 uint16_t alt_family;
8429abe0
RW
189 struct lde_addr lde_addr;
190
191 memcpy(&msg, buf, sizeof(msg));
fd1cf443
RW
192 msg_type = ntohs(msg.type);
193 switch (msg_type) {
194 case MSG_TYPE_ADDR:
195 type = IMSG_ADDRESS_ADD;
196 break;
197 case MSG_TYPE_ADDRWITHDRAW:
198 type = IMSG_ADDRESS_DEL;
199 break;
200 default:
201 fatalx("recv_address: unexpected msg type");
202 }
8429abe0
RW
203 buf += LDP_MSG_SIZE;
204 len -= LDP_MSG_SIZE;
205
206 /* Address List TLV */
207 if (len < ADDR_LIST_SIZE) {
208 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
209 return (-1);
210 }
8429abe0 211 memcpy(&alt, buf, sizeof(alt));
fd1cf443
RW
212 alt_len = ntohs(alt.length);
213 alt_family = ntohs(alt.family);
214 if (alt_len > len - TLV_HDR_SIZE) {
8429abe0
RW
215 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
216 return (-1);
217 }
218 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
a33df200 219 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
8429abe0
RW
220 return (-1);
221 }
fd1cf443 222 switch (alt_family) {
8429abe0
RW
223 case AF_IPV4:
224 if (!nbr->v4_enabled)
225 /* just ignore the message */
226 return (0);
227 break;
228 case AF_IPV6:
229 if (!nbr->v6_enabled)
230 /* just ignore the message */
231 return (0);
232 break;
233 default:
adbdf465 234 send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
8429abe0
RW
235 return (-1);
236 }
fd1cf443 237 alt_len -= sizeof(alt.family);
8429abe0
RW
238 buf += sizeof(alt);
239 len -= sizeof(alt);
240
fd1cf443
RW
241 /* Process all received addresses */
242 while (alt_len > 0) {
243 switch (alt_family) {
8429abe0 244 case AF_IPV4:
fd1cf443 245 if (alt_len < sizeof(struct in_addr)) {
8429abe0
RW
246 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
247 msg.type);
248 return (-1);
249 }
250
251 memset(&lde_addr, 0, sizeof(lde_addr));
252 lde_addr.af = AF_INET;
253 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
254
255 buf += sizeof(struct in_addr);
256 len -= sizeof(struct in_addr);
fd1cf443 257 alt_len -= sizeof(struct in_addr);
8429abe0
RW
258 break;
259 case AF_IPV6:
fd1cf443 260 if (alt_len < sizeof(struct in6_addr)) {
8429abe0
RW
261 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
262 msg.type);
263 return (-1);
264 }
265
266 memset(&lde_addr, 0, sizeof(lde_addr));
267 lde_addr.af = AF_INET6;
268 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
269
270 buf += sizeof(struct in6_addr);
271 len -= sizeof(struct in6_addr);
fd1cf443 272 alt_len -= sizeof(struct in6_addr);
8429abe0
RW
273 break;
274 default:
275 fatalx("recv_address: unknown af");
276 }
277
faf75793 278 log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
8429abe0
RW
279
280 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
281 sizeof(lde_addr));
282 }
283
fd1cf443
RW
284 /* Optional Parameters */
285 while (len > 0) {
286 struct tlv tlv;
287 uint16_t tlv_type;
288 uint16_t tlv_len;
289
290 if (len < sizeof(tlv)) {
291 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
292 return (-1);
293 }
294
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);
300 return (-1);
301 }
302 buf += TLV_HDR_SIZE;
303 len -= TLV_HDR_SIZE;
304
305 switch (tlv_type) {
306 default:
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 */
311 break;
312 }
313 buf += tlv_len;
314 len -= tlv_len;
315 }
316
8429abe0
RW
317 return (0);
318}
319
320static int
26519d8c
RW
321gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
322 unsigned int tlv_addr_count)
8429abe0
RW
323{
324 struct address_list_tlv alt;
325 uint16_t addr_size;
326 struct if_addr *if_addr;
327 int err = 0;
328
329 memset(&alt, 0, sizeof(alt));
a33df200 330 alt.type = htons(TLV_TYPE_ADDRLIST);
8429abe0
RW
331
332 switch (af) {
333 case AF_INET:
334 alt.family = htons(AF_IPV4);
335 addr_size = sizeof(struct in_addr);
336 break;
337 case AF_INET6:
338 alt.family = htons(AF_IPV6);
339 addr_size = sizeof(struct in6_addr);
340 break;
341 default:
342 fatalx("gen_address_list_tlv: unknown af");
343 }
26519d8c 344 alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
8429abe0 345
ee60199a 346 SET_FLAG(err, ibuf_add(buf, &alt, sizeof(alt)));
347
26519d8c
RW
348 if (addr_list == NULL)
349 return (err);
350
8429abe0 351 LIST_FOREACH(if_addr, addr_list, entry) {
ee60199a 352 SET_FLAG(err, ibuf_add(buf, &if_addr->addr, addr_size));
353
8429abe0
RW
354 if (--tlv_addr_count == 0)
355 break;
356 }
357
358 return (err);
359}
360
26519d8c
RW
361static int
362gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
363{
364 struct tlv tlv;
365 int err;
366
367 memset(&tlv, 0, sizeof(tlv));
368 tlv.type = htons(TLV_TYPE_MAC_LIST);
369 if (mac)
9bff8057 370 tlv.length = htons(ETH_ALEN);
26519d8c
RW
371 err = ibuf_add(buf, &tlv, sizeof(tlv));
372 if (mac)
ee60199a 373 SET_FLAG(err, ibuf_add(buf, mac, ETH_ALEN));
26519d8c
RW
374
375 return (err);
376}
377
8429abe0
RW
378static void
379address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
380{
381 struct if_addr *new;
382
383 new = malloc(sizeof(*new));
384 if (new == NULL)
385 fatal(__func__);
386 *new = *if_addr;
387
388 LIST_INSERT_HEAD(addr_list, new, entry);
389}
390
391static void
392address_list_clr(struct if_addr_head *addr_list)
393{
394 struct if_addr *if_addr;
395
396 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
397 LIST_REMOVE(if_addr, entry);
11bf8e13 398 assert(if_addr != LIST_FIRST(addr_list));
8429abe0
RW
399 free(if_addr);
400 }
401}
faf75793
RW
402
403static void
404log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
405 union ldpd_addr *addr)
406{
903a7226
MS
407 debug_msg(out, "%s: lsr-id %pI4, address %s", msg_name(msg_type),
408 &nbr->id, log_addr(af, addr));
faf75793 409}
26519d8c
RW
410
411static void
412log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
413{
414 char buf[ETHER_ADDR_STRLEN];
415
903a7226 416 debug_msg(out, "mac withdrawal: lsr-id %pI4, mac %s", &nbr->id,
26519d8c
RW
417 (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
418 "wildcard");
419}