]>
Commit | Line | Data |
---|---|---|
8429abe0 RW |
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 | ||
eac6e3f0 | 19 | #include <zebra.h> |
8429abe0 RW |
20 | |
21 | #include "ldpd.h" | |
22 | #include "ldpe.h" | |
23 | #include "lde.h" | |
24 | #include "log.h" | |
eac6e3f0 | 25 | #include "ldp_debug.h" |
8429abe0 RW |
26 | |
27 | static void send_address(struct nbr *, int, struct if_addr_head *, | |
28 | unsigned int, int); | |
26519d8c RW |
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 *); | |
8429abe0 RW |
32 | static void address_list_add(struct if_addr_head *, struct if_addr *); |
33 | static void address_list_clr(struct if_addr_head *); | |
faf75793 RW |
34 | static void log_msg_address(int, uint16_t, struct nbr *, int, |
35 | union ldpd_addr *); | |
26519d8c | 36 | static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *); |
8429abe0 RW |
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; | |
26519d8c | 90 | err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count); |
e3df3ba6 | 91 | (void)size; |
8429abe0 RW |
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) { | |
faf75793 | 99 | log_msg_address(1, msg_type, nbr, af, &if_addr->addr); |
8429abe0 RW |
100 | |
101 | LIST_REMOVE(if_addr, entry); | |
11bf8e13 | 102 | assert(if_addr != LIST_FIRST(addr_list)); |
8429abe0 RW |
103 | free(if_addr); |
104 | if (--tlv_addr_count == 0) | |
105 | break; | |
106 | } | |
107 | ||
108 | evbuf_enqueue(&nbr->tcp->wbuf, buf); | |
0f7b5df9 RW |
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 | } | |
8429abe0 RW |
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 | ||
26519d8c RW |
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) | |
9bff8057 | 165 | size += ETH_ALEN; |
26519d8c RW |
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); | |
26519d8c RW |
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 | ||
8429abe0 RW |
188 | int |
189 | recv_address(struct nbr *nbr, char *buf, uint16_t len) | |
190 | { | |
191 | struct ldp_msg msg; | |
192 | uint16_t msg_type; | |
8429abe0 | 193 | enum imsg_type type; |
fd1cf443 RW |
194 | struct address_list_tlv alt; |
195 | uint16_t alt_len; | |
196 | uint16_t alt_family; | |
8429abe0 RW |
197 | struct lde_addr lde_addr; |
198 | ||
199 | memcpy(&msg, buf, sizeof(msg)); | |
fd1cf443 RW |
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 | } | |
8429abe0 RW |
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 | } | |
8429abe0 | 219 | memcpy(&alt, buf, sizeof(alt)); |
fd1cf443 RW |
220 | alt_len = ntohs(alt.length); |
221 | alt_family = ntohs(alt.family); | |
222 | if (alt_len > len - TLV_HDR_SIZE) { | |
8429abe0 RW |
223 | session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); |
224 | return (-1); | |
225 | } | |
226 | if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { | |
a33df200 | 227 | send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); |
8429abe0 RW |
228 | return (-1); |
229 | } | |
fd1cf443 | 230 | switch (alt_family) { |
8429abe0 RW |
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: | |
adbdf465 | 242 | send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type); |
8429abe0 RW |
243 | return (-1); |
244 | } | |
fd1cf443 | 245 | alt_len -= sizeof(alt.family); |
8429abe0 RW |
246 | buf += sizeof(alt); |
247 | len -= sizeof(alt); | |
248 | ||
fd1cf443 RW |
249 | /* Process all received addresses */ |
250 | while (alt_len > 0) { | |
251 | switch (alt_family) { | |
8429abe0 | 252 | case AF_IPV4: |
fd1cf443 | 253 | if (alt_len < sizeof(struct in_addr)) { |
8429abe0 RW |
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); | |
fd1cf443 | 265 | alt_len -= sizeof(struct in_addr); |
8429abe0 RW |
266 | break; |
267 | case AF_IPV6: | |
fd1cf443 | 268 | if (alt_len < sizeof(struct in6_addr)) { |
8429abe0 RW |
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); | |
fd1cf443 | 280 | alt_len -= sizeof(struct in6_addr); |
8429abe0 RW |
281 | break; |
282 | default: | |
283 | fatalx("recv_address: unknown af"); | |
284 | } | |
285 | ||
faf75793 | 286 | log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr); |
8429abe0 RW |
287 | |
288 | ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, | |
289 | sizeof(lde_addr)); | |
290 | } | |
291 | ||
fd1cf443 RW |
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 | ||
8429abe0 RW |
325 | return (0); |
326 | } | |
327 | ||
328 | static int | |
26519d8c RW |
329 | gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list, |
330 | unsigned int tlv_addr_count) | |
8429abe0 RW |
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)); | |
a33df200 | 338 | alt.type = htons(TLV_TYPE_ADDRLIST); |
8429abe0 RW |
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 | } | |
26519d8c | 352 | alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count); |
8429abe0 RW |
353 | |
354 | err |= ibuf_add(buf, &alt, sizeof(alt)); | |
26519d8c RW |
355 | if (addr_list == NULL) |
356 | return (err); | |
357 | ||
8429abe0 RW |
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 | ||
26519d8c RW |
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) | |
9bff8057 | 376 | tlv.length = htons(ETH_ALEN); |
26519d8c RW |
377 | err = ibuf_add(buf, &tlv, sizeof(tlv)); |
378 | if (mac) | |
9bff8057 | 379 | err |= ibuf_add(buf, mac, ETH_ALEN); |
26519d8c RW |
380 | |
381 | return (err); | |
382 | } | |
383 | ||
8429abe0 RW |
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); | |
11bf8e13 | 404 | assert(if_addr != LIST_FIRST(addr_list)); |
8429abe0 RW |
405 | free(if_addr); |
406 | } | |
407 | } | |
faf75793 RW |
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 | } | |
26519d8c RW |
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 | } |