]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/address.c
Merge pull request #12780 from opensourcerouting/spdx-license-id
[mirror_frr.git] / ldpd / address.c
1 // SPDX-License-Identifier: ISC
2 /* $OpenBSD$ */
3
4 /*
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 */
7
8 #include <zebra.h>
9
10 #include "ldpd.h"
11 #include "ldpe.h"
12 #include "lde.h"
13 #include "log.h"
14 #include "ldp_debug.h"
15
16 static void send_address(struct nbr *, int, struct if_addr_head *,
17 unsigned int, int);
18 static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
19 unsigned int);
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,
24 union ldpd_addr *);
25 static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
26
27 static void
28 send_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
59 while (LIST_FIRST(addr_list) != NULL) {
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
75 err |= gen_ldp_hdr(buf, size);
76 size -= LDP_HDR_SIZE;
77 err |= gen_msg_hdr(buf, msg_type, size);
78 size -= LDP_MSG_SIZE;
79 err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
80 (void)size;
81 if (err) {
82 address_list_clr(addr_list);
83 ibuf_free(buf);
84 return;
85 }
86
87 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
88 log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
89
90 LIST_REMOVE(if_addr, entry);
91 assert(if_addr != LIST_FIRST(addr_list));
92 free(if_addr);
93 if (--tlv_addr_count == 0)
94 break;
95 }
96
97 evbuf_enqueue(&nbr->tcp->wbuf, buf);
98
99 /* no errors - update per neighbor message counters */
100 switch (msg_type) {
101 case MSG_TYPE_ADDR:
102 nbr->stats.addr_sent++;
103 break;
104 case MSG_TYPE_ADDRWITHDRAW:
105 nbr->stats.addrwdraw_sent++;
106 break;
107 default:
108 break;
109 }
110 }
111
112 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
113 }
114
115 void
116 send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
117 {
118 struct if_addr_head addr_list;
119
120 LIST_INIT(&addr_list);
121 address_list_add(&addr_list, if_addr);
122 send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
123 }
124
125 void
126 send_address_all(struct nbr *nbr, int af)
127 {
128 struct if_addr_head addr_list;
129 struct if_addr *if_addr;
130 unsigned int addr_count = 0;
131
132 LIST_INIT(&addr_list);
133 LIST_FOREACH(if_addr, &global.addr_list, entry) {
134 if (if_addr->af != af)
135 continue;
136
137 address_list_add(&addr_list, if_addr);
138 addr_count++;
139 }
140
141 send_address(nbr, af, &addr_list, addr_count, 0);
142 }
143
144 void
145 send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
146 {
147 struct ibuf *buf;
148 uint16_t size;
149 int err;
150
151 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
152 TLV_HDR_SIZE;
153 if (mac)
154 size += ETH_ALEN;
155
156 if ((buf = ibuf_open(size)) == NULL)
157 fatal(__func__);
158
159 err = gen_ldp_hdr(buf, size);
160 size -= LDP_HDR_SIZE;
161 err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
162 err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
163 err |= gen_fec_tlv(buf, fec);
164 err |= gen_mac_list_tlv(buf, mac);
165 if (err) {
166 ibuf_free(buf);
167 return;
168 }
169
170 log_msg_mac_withdrawal(1, nbr, mac);
171
172 evbuf_enqueue(&nbr->tcp->wbuf, buf);
173
174 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
175 }
176
177 int
178 recv_address(struct nbr *nbr, char *buf, uint16_t len)
179 {
180 struct ldp_msg msg;
181 uint16_t msg_type;
182 enum imsg_type type;
183 struct address_list_tlv alt;
184 uint16_t alt_len;
185 uint16_t alt_family;
186 struct lde_addr lde_addr;
187
188 memcpy(&msg, buf, sizeof(msg));
189 msg_type = ntohs(msg.type);
190 switch (msg_type) {
191 case MSG_TYPE_ADDR:
192 type = IMSG_ADDRESS_ADD;
193 break;
194 case MSG_TYPE_ADDRWITHDRAW:
195 type = IMSG_ADDRESS_DEL;
196 break;
197 default:
198 fatalx("recv_address: unexpected msg type");
199 }
200 buf += LDP_MSG_SIZE;
201 len -= LDP_MSG_SIZE;
202
203 /* Address List TLV */
204 if (len < ADDR_LIST_SIZE) {
205 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
206 return (-1);
207 }
208 memcpy(&alt, buf, sizeof(alt));
209 alt_len = ntohs(alt.length);
210 alt_family = ntohs(alt.family);
211 if (alt_len > len - TLV_HDR_SIZE) {
212 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
213 return (-1);
214 }
215 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
216 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
217 return (-1);
218 }
219 switch (alt_family) {
220 case AF_IPV4:
221 if (!nbr->v4_enabled)
222 /* just ignore the message */
223 return (0);
224 break;
225 case AF_IPV6:
226 if (!nbr->v6_enabled)
227 /* just ignore the message */
228 return (0);
229 break;
230 default:
231 send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
232 return (-1);
233 }
234 alt_len -= sizeof(alt.family);
235 buf += sizeof(alt);
236 len -= sizeof(alt);
237
238 /* Process all received addresses */
239 while (alt_len > 0) {
240 switch (alt_family) {
241 case AF_IPV4:
242 if (alt_len < sizeof(struct in_addr)) {
243 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
244 msg.type);
245 return (-1);
246 }
247
248 memset(&lde_addr, 0, sizeof(lde_addr));
249 lde_addr.af = AF_INET;
250 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
251
252 buf += sizeof(struct in_addr);
253 len -= sizeof(struct in_addr);
254 alt_len -= sizeof(struct in_addr);
255 break;
256 case AF_IPV6:
257 if (alt_len < sizeof(struct in6_addr)) {
258 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
259 msg.type);
260 return (-1);
261 }
262
263 memset(&lde_addr, 0, sizeof(lde_addr));
264 lde_addr.af = AF_INET6;
265 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
266
267 buf += sizeof(struct in6_addr);
268 len -= sizeof(struct in6_addr);
269 alt_len -= sizeof(struct in6_addr);
270 break;
271 default:
272 fatalx("recv_address: unknown af");
273 }
274
275 log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
276
277 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
278 sizeof(lde_addr));
279 }
280
281 /* Optional Parameters */
282 while (len > 0) {
283 struct tlv tlv;
284 uint16_t tlv_type;
285 uint16_t tlv_len;
286
287 if (len < sizeof(tlv)) {
288 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
289 return (-1);
290 }
291
292 memcpy(&tlv, buf, TLV_HDR_SIZE);
293 tlv_type = ntohs(tlv.type);
294 tlv_len = ntohs(tlv.length);
295 if (tlv_len + TLV_HDR_SIZE > len) {
296 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
297 return (-1);
298 }
299 buf += TLV_HDR_SIZE;
300 len -= TLV_HDR_SIZE;
301
302 switch (tlv_type) {
303 default:
304 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
305 send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
306 msg.id, msg.type, tlv_type, tlv_len, buf);
307 /* ignore unknown tlv */
308 break;
309 }
310 buf += tlv_len;
311 len -= tlv_len;
312 }
313
314 return (0);
315 }
316
317 static int
318 gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
319 unsigned int tlv_addr_count)
320 {
321 struct address_list_tlv alt;
322 uint16_t addr_size;
323 struct if_addr *if_addr;
324 int err = 0;
325
326 memset(&alt, 0, sizeof(alt));
327 alt.type = htons(TLV_TYPE_ADDRLIST);
328
329 switch (af) {
330 case AF_INET:
331 alt.family = htons(AF_IPV4);
332 addr_size = sizeof(struct in_addr);
333 break;
334 case AF_INET6:
335 alt.family = htons(AF_IPV6);
336 addr_size = sizeof(struct in6_addr);
337 break;
338 default:
339 fatalx("gen_address_list_tlv: unknown af");
340 }
341 alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
342
343 err |= ibuf_add(buf, &alt, sizeof(alt));
344 if (addr_list == NULL)
345 return (err);
346
347 LIST_FOREACH(if_addr, addr_list, entry) {
348 err |= ibuf_add(buf, &if_addr->addr, addr_size);
349 if (--tlv_addr_count == 0)
350 break;
351 }
352
353 return (err);
354 }
355
356 static int
357 gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
358 {
359 struct tlv tlv;
360 int err;
361
362 memset(&tlv, 0, sizeof(tlv));
363 tlv.type = htons(TLV_TYPE_MAC_LIST);
364 if (mac)
365 tlv.length = htons(ETH_ALEN);
366 err = ibuf_add(buf, &tlv, sizeof(tlv));
367 if (mac)
368 err |= ibuf_add(buf, mac, ETH_ALEN);
369
370 return (err);
371 }
372
373 static void
374 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
375 {
376 struct if_addr *new;
377
378 new = malloc(sizeof(*new));
379 if (new == NULL)
380 fatal(__func__);
381 *new = *if_addr;
382
383 LIST_INSERT_HEAD(addr_list, new, entry);
384 }
385
386 static void
387 address_list_clr(struct if_addr_head *addr_list)
388 {
389 struct if_addr *if_addr;
390
391 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
392 LIST_REMOVE(if_addr, entry);
393 assert(if_addr != LIST_FIRST(addr_list));
394 free(if_addr);
395 }
396 }
397
398 static void
399 log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
400 union ldpd_addr *addr)
401 {
402 debug_msg(out, "%s: lsr-id %pI4, address %s", msg_name(msg_type),
403 &nbr->id, log_addr(af, addr));
404 }
405
406 static void
407 log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
408 {
409 char buf[ETHER_ADDR_STRLEN];
410
411 debug_msg(out, "mac withdrawal: lsr-id %pI4, mac %s", &nbr->id,
412 (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
413 "wildcard");
414 }