1 /* $NetBSD: tlv_stack.c,v 1.13 2013/07/31 06:58:23 kefren Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren@NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <arpa/inet.h>
33
34 #include <netmpls/mpls.h>
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #include "ldp.h"
41 #include "ldp_errors.h"
42 #include "ldp_peer.h"
43 #include "tlv.h"
44 #include "socketops.h"
45 #include "pdu.h"
46 #include "label.h"
47 #include "mpls_interface.h"
48 #include "tlv_stack.h"
49
50 static uint8_t ldp_ceil8(int);
51
52 static uint8_t
ldp_ceil8(int x)53 ldp_ceil8(int x)
54 {
55 if (x % 8 == 0)
56 return x / 8;
57 return x / 8 + 1;
58 }
59
60 int
map_label(struct ldp_peer * p,struct fec_tlv * f,struct label_tlv * l)61 map_label(struct ldp_peer * p, struct fec_tlv * f, struct label_tlv * l)
62 {
63 int n;
64 struct prefix_tlv *pref;
65 union sockunion socktmp;
66 struct label *lbl_check;
67
68 if (ntohs(f->type) != TLV_FEC) {
69 debugp("Invalid FEC TLV !\n");
70 return LDP_E_BAD_FEC;
71 }
72 if (ntohs(l->type) != TLV_GENERIC_LABEL) {
73 debugp("Invalid LABEL TLV! (0x%.4X)\n", ntohs(l->type));
74 return LDP_E_BAD_LABEL;
75 }
76 /*
77 * Actually address field length is given only in length field in
78 * bits !
79 */
80
81 n = ntohs(f->length);
82 if (!n)
83 return LDP_E_BAD_FEC;
84
85 debugp("Label %u for:\n", ntohl(l->label));
86
87 pref = (struct prefix_tlv *) (f + 1);
88 memset (&socktmp, 0, sizeof(socktmp));
89
90 /*
91 * Section 3.4.1
92 * Note that this version of LDP supports the use of multiple FEC
93 * Elements per FEC for the Label Mapping message only. The use of
94 * multiple FEC Elements in other messages is not permitted in this
95 * version, and is a subject for future study.
96 */
97
98 for (; n > 0; pref = (struct prefix_tlv *) ((unsigned char *) pref +
99 ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH)) {
100 n -= ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH;
101 if (ntohs(pref->af) == LDP_AF_INET) {
102 socktmp.sa.sa_family = AF_INET;
103 socktmp.sa.sa_len = sizeof(socktmp.sin);
104 } else if (ntohs(pref->af) == LDP_AF_INET6) {
105 socktmp.sa.sa_family = AF_INET6;
106 socktmp.sa.sa_len = sizeof(socktmp.sin6);
107 } else {
108 warnp("BAD ADDRESS FAMILY (%d) ! (prefix type %d, "
109 "length %d)\n", ntohs(pref->af), pref->type,
110 pref->prelen);
111 return LDP_E_BAD_AF;
112 }
113 switch(pref->type) {
114 case FEC_PREFIX:
115 case FEC_HOST:
116 if (socktmp.sa.sa_family == AF_INET)
117 memcpy(&socktmp.sin.sin_addr, &pref->prefix,
118 ldp_ceil8(pref->prelen));
119 else
120 memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
121 ldp_ceil8(pref->prelen));
122 warnp("Prefix/Host add from %s: %s/%d\n",
123 inet_ntoa(p->ldp_id), satos(&socktmp.sa),
124 pref->prelen);
125
126 ldp_peer_add_mapping(p, &socktmp.sa, pref->prelen,
127 ntohl(l->label));
128
129 /* Try to change RIB only if label is installed */
130 lbl_check = label_get_by_prefix(&socktmp.sa,
131 pref->prelen);
132 if (lbl_check != NULL && lbl_check->p == p) {
133 lbl_check->label = ntohl(l->label);
134 mpls_add_label(lbl_check);
135 } else
136 warnp("[map_label] lbl check failed: %s\n",
137 lbl_check == NULL ? "(null)" :
138 lbl_check->p == NULL ? "(null peer)" :
139 inet_ntoa(lbl_check->p->ldp_id));
140 break;
141 case FEC_WILDCARD:
142 fatalp("LDP: Wildcard add from peer %s\n",
143 satos(p->address));
144 return LDP_E_BAD_FEC;
145 default:
146 fatalp("Unknown FEC type %d\n", pref->type);
147 return LDP_E_BAD_FEC;
148 }
149 }
150
151 return LDP_E_OK;
152 }
153
154 int
withdraw_label(struct ldp_peer * p,struct fec_tlv * f)155 withdraw_label(struct ldp_peer * p, struct fec_tlv * f)
156 {
157 int n;
158 struct prefix_tlv *pref;
159 union sockunion socktmp;
160 struct label *lab;
161
162 if (ntohs(f->type) != TLV_FEC) {
163 debugp("Invalid FEC TLV !\n");
164 return LDP_E_BAD_FEC;
165 }
166 n = ntohs(f->length);
167 if (!n)
168 return LDP_E_BAD_FEC;
169
170 pref = (struct prefix_tlv *) & f[1];
171
172 memset(&socktmp, 0, sizeof(socktmp));
173 if (ntohs(pref->af) == LDP_AF_INET) {
174 socktmp.sa.sa_family = AF_INET;
175 socktmp.sa.sa_len = sizeof(socktmp.sin);
176 } else if (ntohs(pref->af) != LDP_AF_INET6) {
177 socktmp.sa.sa_family = AF_INET6;
178 socktmp.sa.sa_len = sizeof(socktmp.sin6);
179 } else {
180 warnp("WITHDRAW: Bad AF (%d)! (prefix type %d, length %d)\n",
181 ntohs(pref->af), pref->type, pref->prelen);
182 return LDP_E_BAD_AF;
183 }
184 switch(pref->type) {
185 case FEC_PREFIX:
186 case FEC_HOST:
187 if (socktmp.sa.sa_family == AF_INET)
188 memcpy(&socktmp.sin.sin_addr, &pref->prefix,
189 ldp_ceil8(pref->prelen));
190 else
191 memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
192 ldp_ceil8(pref->prelen));
193 debugp("Prefix/Host withdraw: %s/%d\n", satos(&socktmp.sa),
194 pref->prelen);
195
196 /* Delete mapping */
197 ldp_peer_delete_mapping(p, &socktmp.sa, pref->prelen);
198
199 /* Get label, see if we're pointing to this peer
200 * if so, send withdraw, reattach IP route and announce
201 * POP Label
202 */
203 lab = label_get_by_prefix(&socktmp.sa, pref->prelen);
204 if (lab && lab->p == p) {
205 label_reattach_route(lab, REATT_INET_CHANGE);
206 announce_label_change(lab); /* binding has changed */
207 }
208 break;
209 case FEC_WILDCARD:
210 fatalp("LDP neighbour %s: Wildcard withdraw !!!\n",
211 satos(p->address));
212 ldp_peer_delete_all_mappings(p);
213 label_reattach_all_peer_labels(p, REATT_INET_CHANGE);
214 break;
215 default:
216 fatalp("Unknown FEC type %d\n", pref->type);
217 return LDP_E_BAD_FEC;
218 }
219
220 return LDP_E_OK;
221 }
222
223
224 /*
225 * In case of label withdraw, reuse the same buffer to send label release
226 * Simply replace type and message id
227 */
228 void
prepare_release(struct tlv * v)229 prepare_release(struct tlv * v)
230 {
231 struct label_map_tlv *t;
232
233 t = (struct label_map_tlv *) v;
234
235 t->type = htons(LDP_LABEL_RELEASE);
236 t->messageid = htonl(get_message_id());
237 }
238
239 /* Sends a label mapping */
240 void
send_label_tlv(const struct ldp_peer * peer,const struct sockaddr * addr,uint8_t prefixlen,uint32_t label,const struct label_request_tlv * lrt)241 send_label_tlv(const struct ldp_peer * peer, const struct sockaddr * addr,
242 uint8_t prefixlen, uint32_t label, const struct label_request_tlv *lrt)
243 {
244 struct label_map_tlv *lmt;
245 struct fec_tlv *fec;
246 struct prefix_tlv *p;
247 struct label_tlv *l;
248
249 debugp("SENDING LABEL TLV %s TO %s\n", satos(addr),
250 inet_ntoa(peer->ldp_id));
251
252 /*
253 * Ok, so we have label map tlv that contains fec tlvs and label tlv
254 * but fec tlv contains prefix or host tlvs and prefix or host tlvs
255 * contains the network. After that we may have optional parameters
256 * Got it ?
257 */
258
259 lmt = calloc(1,
260 sizeof(struct label_map_tlv) +
261 sizeof(struct fec_tlv) +
262 sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
263 ldp_ceil8(prefixlen) +
264 sizeof(struct label_tlv) +
265 /* Label request optional parameter */
266 (lrt != NULL ? sizeof(struct label_request_tlv) : 0) );
267
268 if (!lmt) {
269 fatalp("send_label_tlv: calloc problem\n");
270 return;
271 }
272
273 lmt->type = htons(LDP_LABEL_MAPPING);
274 lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
275 + sizeof(struct fec_tlv)
276 + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
277 ldp_ceil8(prefixlen)
278 + sizeof(struct label_tlv) +
279 + (lrt != NULL ? sizeof(struct label_request_tlv) : 0));
280 lmt->messageid = htonl(get_message_id());
281
282 /* FEC TLV */
283 fec = (struct fec_tlv *) & lmt[1];
284 fec->type = htons(TLV_FEC);
285 fec->length = htons(sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
286 ldp_ceil8(prefixlen));
287
288 /* Now let's do the even a dirtier job: PREFIX TLV */
289 p = (struct prefix_tlv *) & fec[1];
290 /*
291 * RFC5036 obsoletes FEC_HOST
292 *
293 * if (prefixlen == 32) p->type = FEC_HOST; else
294 */
295 p->type = FEC_PREFIX;
296 p->af = htons(LDP_AF_INET);
297 p->prelen = prefixlen;
298 memcpy(&p->prefix, & ((const struct sockaddr_in*)addr)->sin_addr,
299 ldp_ceil8(prefixlen));
300
301 /* LABEL TLV */
302 l = (struct label_tlv *) ((unsigned char *) p +
303 sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
304 ldp_ceil8(prefixlen));
305 l->type = htons(TLV_GENERIC_LABEL);
306 l->length = htons(sizeof(l->label));
307 l->label = htonl(label);
308
309 /* Label request optional parameter */
310 if (lrt)
311 memcpy(((char*)l) + TLV_TYPE_LENGTH + ntohs(l->length),
312 lrt, htons(lrt->length) + TLV_TYPE_LENGTH);
313
314 /* Wow, seems we're ready */
315 send_tlv(peer, (struct tlv *) lmt);
316 free(lmt);
317 }
318
319 void
send_label_tlv_to_all(const struct sockaddr * addr,uint8_t prefixlen,uint32_t label)320 send_label_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen,
321 uint32_t label)
322 {
323 struct ldp_peer *p;
324 SLIST_FOREACH(p, &ldp_peer_head, peers)
325 if (p->state == LDP_PEER_ESTABLISHED)
326 send_label_tlv(p, addr, prefixlen, label, NULL);
327 }
328
329 /*
330 * Send all local labels to a peer
331 */
332 void
send_all_bindings(const struct ldp_peer * peer)333 send_all_bindings(const struct ldp_peer * peer)
334 {
335 struct label *l = NULL;
336
337 while((l = label_get_right(l)) != NULL)
338 send_label_tlv(peer, &l->so_dest.sa,
339 from_union_to_cidr(&l->so_pref), l->binding, NULL);
340
341 }
342
343 /* Sends a label WITHDRAW */
344 void
send_withdraw_tlv(const struct ldp_peer * peer,const struct sockaddr * addr,uint8_t prefixlen)345 send_withdraw_tlv(const struct ldp_peer * peer, const struct sockaddr * addr,
346 uint8_t prefixlen)
347 {
348 struct label_map_tlv *lmt;
349 struct fec_tlv *fec;
350 struct prefix_tlv *p;
351
352 /*
353 * Ok, so we have label map tlv that contains fec tlvs but fec tlv
354 * contains prefix or host tlvs and prefix or host tlvs contains the
355 * network. Yes, we don't have to announce label here
356 */
357
358 lmt = malloc(sizeof(struct label_map_tlv)
359 + sizeof(struct fec_tlv)
360 + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
361 ldp_ceil8(prefixlen));
362
363 if (!lmt) {
364 fatalp("send_withdraw_tlv: malloc problem\n");
365 return;
366 }
367
368 lmt->type = htons(LDP_LABEL_WITHDRAW);
369 lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
370 + sizeof(struct fec_tlv)
371 + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
372 ldp_ceil8(prefixlen));
373 lmt->messageid = htonl(get_message_id());
374
375 /* FEC TLV */
376 fec = (struct fec_tlv *) & lmt[1];
377 fec->type = htons(TLV_FEC);
378 fec->length = htons(sizeof(struct fec_tlv) - TLV_TYPE_LENGTH
379 + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
380 ldp_ceil8(prefixlen));
381
382 /* Now the even dirtier job: PREFIX TLV */
383 p = (struct prefix_tlv *) & fec[1];
384 /*
385 * RFC5036 obsoletes FEC_HOST
386 *
387 * if (prefixlen == 32) p->type = FEC_HOST; else
388 */
389 p->type = FEC_PREFIX;
390 p->af = htons(LDP_AF_INET);
391 p->prelen = prefixlen;
392 memcpy(&p->prefix, addr, ldp_ceil8(prefixlen));
393
394 /* Wow, seems we're ready */
395 send_tlv(peer, (struct tlv *) lmt);
396 free(lmt);
397 }
398
399 void
send_withdraw_tlv_to_all(const struct sockaddr * addr,uint8_t prefixlen)400 send_withdraw_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen)
401 {
402 struct ldp_peer *p;
403 SLIST_FOREACH(p, &ldp_peer_head, peers)
404 if (p->state == LDP_PEER_ESTABLISHED)
405 send_withdraw_tlv(p, addr, prefixlen);
406 }
407
408 int
request_respond(const struct ldp_peer * p,const struct label_map_tlv * lmt,const struct fec_tlv * fec)409 request_respond(const struct ldp_peer *p, const struct label_map_tlv *lmt,
410 const struct fec_tlv *fec)
411 {
412 const struct prefix_tlv *pref;
413 union sockunion socktmp;
414 struct label *lab;
415 struct label_request_tlv lrm;
416
417 if (ntohs(fec->type) != TLV_FEC || fec->length == 0) {
418 debugp("Invalid FEC TLV !\n");
419 return LDP_E_BAD_FEC;
420 }
421 pref = (const struct prefix_tlv *) (fec + 1);
422
423 memset(&socktmp, 0, sizeof(socktmp));
424 if (ntohs(pref->af) == LDP_AF_INET) {
425 socktmp.sa.sa_family = AF_INET;
426 socktmp.sa.sa_len = sizeof(socktmp.sin);
427 } else if (ntohs(pref->af) == LDP_AF_INET6) {
428 socktmp.sa.sa_family = AF_INET6;
429 socktmp.sa.sa_len = sizeof(socktmp.sin6);
430 } else {
431 debugp("request_respond: Bad address family\n");
432 return LDP_E_BAD_AF;
433 }
434
435 switch (pref->type) {
436 case FEC_PREFIX:
437 case FEC_HOST:
438
439 if (socktmp.sa.sa_family == AF_INET)
440 memcpy(&socktmp.sin.sin_addr, &pref->prefix,
441 ldp_ceil8(pref->prelen));
442 else /* AF_INET6 */
443 memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
444 ldp_ceil8(pref->prelen));
445 debugp("Prefix/Host request: %s/%d\n", satos(&socktmp.sa),
446 pref->prelen);
447
448 lab = label_get_by_prefix(&socktmp.sa, pref->prelen);
449 if (!lab)
450 return LDP_E_NO_SUCH_ROUTE;
451 lrm.type = htons(TLV_LABEL_REQUEST);
452 /* XXX - use sizeof */
453 lrm.length = htons(socktmp.sa.sa_family == AF_INET ? 4 : 16);
454 lrm.messageid = lmt->messageid;
455 send_label_tlv(p, &socktmp.sa, pref->prelen, lab->binding,
456 &lrm);
457 break;
458
459 case FEC_WILDCARD:
460 /*
461 * Section 3.4.1
462 * To be used only in the Label Withdraw and Label Release
463 */
464 /* Fallthrough */
465 default:
466
467 fatalp("Invalid FEC type\n");
468 return LDP_E_BAD_FEC;
469 }
470 return LDP_E_OK;
471 }
472