]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/address.c
Merge remote-tracking branch 'origin/cmaster' into cmaster-next
[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 *, uint16_t, int,
30 struct if_addr_head *, unsigned int);
31 static void address_list_add(struct if_addr_head *, struct if_addr *);
32 static void address_list_clr(struct if_addr_head *);
33
34 static void
35 send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
36 unsigned int addr_count, int withdraw)
37 {
38 struct ibuf *buf;
39 uint16_t msg_type;
40 uint8_t addr_size;
41 struct if_addr *if_addr;
42 uint16_t size;
43 unsigned int tlv_addr_count = 0;
44 int err = 0;
45
46 /* nothing to send */
47 if (LIST_EMPTY(addr_list))
48 return;
49
50 if (!withdraw)
51 msg_type = MSG_TYPE_ADDR;
52 else
53 msg_type = MSG_TYPE_ADDRWITHDRAW;
54
55 switch (af) {
56 case AF_INET:
57 addr_size = sizeof(struct in_addr);
58 break;
59 case AF_INET6:
60 addr_size = sizeof(struct in6_addr);
61 break;
62 default:
63 fatalx("send_address: unknown af");
64 }
65
66 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
67 /*
68 * Send as many addresses as possible - respect the session's
69 * negotiated maximum pdu length.
70 */
71 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE;
72 if (size + addr_count * addr_size <= nbr->max_pdu_len)
73 tlv_addr_count = addr_count;
74 else
75 tlv_addr_count = (nbr->max_pdu_len - size) / addr_size;
76 size += tlv_addr_count * addr_size;
77 addr_count -= tlv_addr_count;
78
79 if ((buf = ibuf_open(size)) == NULL)
80 fatal(__func__);
81
82 err |= gen_ldp_hdr(buf, size);
83 size -= LDP_HDR_SIZE;
84 err |= gen_msg_hdr(buf, msg_type, size);
85 size -= LDP_MSG_SIZE;
86 err |= gen_address_list_tlv(buf, size, af, addr_list,
87 tlv_addr_count);
88 if (err) {
89 address_list_clr(addr_list);
90 ibuf_free(buf);
91 return;
92 }
93
94 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
95 debug_msg_send("%s: lsr-id %s address %s",
96 msg_name(msg_type), inet_ntoa(nbr->id),
97 log_addr(af, &if_addr->addr));
98
99 LIST_REMOVE(if_addr, entry);
100 free(if_addr);
101 if (--tlv_addr_count == 0)
102 break;
103 }
104
105 evbuf_enqueue(&nbr->tcp->wbuf, buf);
106 }
107
108 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
109 }
110
111 void
112 send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
113 {
114 struct if_addr_head addr_list;
115
116 LIST_INIT(&addr_list);
117 address_list_add(&addr_list, if_addr);
118 send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
119 }
120
121 void
122 send_address_all(struct nbr *nbr, int af)
123 {
124 struct if_addr_head addr_list;
125 struct if_addr *if_addr;
126 unsigned int addr_count = 0;
127
128 LIST_INIT(&addr_list);
129 LIST_FOREACH(if_addr, &global.addr_list, entry) {
130 if (if_addr->af != af)
131 continue;
132
133 address_list_add(&addr_list, if_addr);
134 addr_count++;
135 }
136
137 send_address(nbr, af, &addr_list, addr_count, 0);
138 }
139
140 int
141 recv_address(struct nbr *nbr, char *buf, uint16_t len)
142 {
143 struct ldp_msg msg;
144 uint16_t msg_type;
145 struct address_list_tlv alt;
146 enum imsg_type type;
147 struct lde_addr lde_addr;
148
149 memcpy(&msg, buf, sizeof(msg));
150 buf += LDP_MSG_SIZE;
151 len -= LDP_MSG_SIZE;
152
153 /* Address List TLV */
154 if (len < ADDR_LIST_SIZE) {
155 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
156 return (-1);
157 }
158
159 memcpy(&alt, buf, sizeof(alt));
160 if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
161 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
162 return (-1);
163 }
164 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
165 session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type);
166 return (-1);
167 }
168 switch (ntohs(alt.family)) {
169 case AF_IPV4:
170 if (!nbr->v4_enabled)
171 /* just ignore the message */
172 return (0);
173 break;
174 case AF_IPV6:
175 if (!nbr->v6_enabled)
176 /* just ignore the message */
177 return (0);
178 break;
179 default:
180 send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type);
181 return (-1);
182 }
183 buf += sizeof(alt);
184 len -= sizeof(alt);
185
186 msg_type = ntohs(msg.type);
187 if (msg_type == MSG_TYPE_ADDR)
188 type = IMSG_ADDRESS_ADD;
189 else
190 type = IMSG_ADDRESS_DEL;
191
192 while (len > 0) {
193 switch (ntohs(alt.family)) {
194 case AF_IPV4:
195 if (len < sizeof(struct in_addr)) {
196 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
197 msg.type);
198 return (-1);
199 }
200
201 memset(&lde_addr, 0, sizeof(lde_addr));
202 lde_addr.af = AF_INET;
203 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
204
205 buf += sizeof(struct in_addr);
206 len -= sizeof(struct in_addr);
207 break;
208 case AF_IPV6:
209 if (len < sizeof(struct in6_addr)) {
210 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
211 msg.type);
212 return (-1);
213 }
214
215 memset(&lde_addr, 0, sizeof(lde_addr));
216 lde_addr.af = AF_INET6;
217 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
218
219 buf += sizeof(struct in6_addr);
220 len -= sizeof(struct in6_addr);
221 break;
222 default:
223 fatalx("recv_address: unknown af");
224 }
225
226 debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type),
227 inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
228
229 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
230 sizeof(lde_addr));
231 }
232
233 return (0);
234 }
235
236 static int
237 gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
238 struct if_addr_head *addr_list, unsigned int tlv_addr_count)
239 {
240 struct address_list_tlv alt;
241 uint16_t addr_size;
242 struct if_addr *if_addr;
243 int err = 0;
244
245 memset(&alt, 0, sizeof(alt));
246 alt.type = TLV_TYPE_ADDRLIST;
247 alt.length = htons(size - TLV_HDR_SIZE);
248
249 switch (af) {
250 case AF_INET:
251 alt.family = htons(AF_IPV4);
252 addr_size = sizeof(struct in_addr);
253 break;
254 case AF_INET6:
255 alt.family = htons(AF_IPV6);
256 addr_size = sizeof(struct in6_addr);
257 break;
258 default:
259 fatalx("gen_address_list_tlv: unknown af");
260 }
261
262 err |= ibuf_add(buf, &alt, sizeof(alt));
263 LIST_FOREACH(if_addr, addr_list, entry) {
264 err |= ibuf_add(buf, &if_addr->addr, addr_size);
265 if (--tlv_addr_count == 0)
266 break;
267 }
268
269 return (err);
270 }
271
272 static void
273 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
274 {
275 struct if_addr *new;
276
277 new = malloc(sizeof(*new));
278 if (new == NULL)
279 fatal(__func__);
280 *new = *if_addr;
281
282 LIST_INSERT_HEAD(addr_list, new, entry);
283 }
284
285 static void
286 address_list_clr(struct if_addr_head *addr_list)
287 {
288 struct if_addr *if_addr;
289
290 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
291 LIST_REMOVE(if_addr, entry);
292 free(if_addr);
293 }
294 }