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