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