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