1 /* $NetBSD: fsm.c,v 1.5 2011/06/16 14:48:30 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 <sys/types.h> 33 #include <sys/socket.h> 34 #include <arpa/inet.h> 35 #include <netinet/in.h> 36 #include <net/if.h> 37 38 #include <ifaddrs.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <strings.h> 42 43 #include "ldp.h" 44 #include "ldp_peer.h" 45 #include "socketops.h" 46 #include "ldp_errors.h" 47 #include "fsm.h" 48 49 char my_ldp_id[20]; 50 struct sockaddr mplssockaddr; 51 52 /* Processing a hello */ 53 void 54 run_ldp_hello(struct ldp_pdu * pduid, struct hello_tlv * ht, 55 struct in_addr * padd, struct in_addr * ladd, int mysock) 56 { 57 struct ldp_peer *peer = NULL; 58 struct in_addr peer_addr; 59 struct transport_address_tlv *trtlv; 60 struct hello_info *hi; 61 62 if ((!pduid) || (!ht)) 63 return; 64 65 debugp("Hello received for address: %s\n", inet_ntoa(*ladd)); 66 debugp("Hello: Type: 0x%.4X Length: %.2d ID: %.8X\n", ht->type, 67 ht->length, ht->messageid); 68 69 /* Add it to hello list or just update timer */ 70 SLIST_FOREACH(hi, &hello_info_head, infos) 71 if (hi->ldp_id.s_addr == pduid->ldp_id.s_addr) 72 break; 73 if (hi == NULL) { 74 hi = malloc(sizeof(*hi)); 75 if (!hi) { 76 fatalp("Cannot alloc a hello info structure"); 77 return; 78 } 79 hi->ldp_id.s_addr = pduid->ldp_id.s_addr; 80 SLIST_INSERT_HEAD(&hello_info_head, hi, infos); 81 } else 82 /* Just update timer */ 83 hi->keepalive = LDP_HELLO_KEEP; 84 85 if (ht->length <= 4) /* Common hello parameters */ 86 return; 87 ht->ch.type = ntohs(ht->ch.type); 88 ht->ch.length = ntohs(ht->ch.length); 89 ht->ch.holdtime = ntohs(ht->ch.holdtime); 90 ht->ch.res = ntohs(ht->ch.res); 91 debugp("Common hello Type: 0x%.4X Length: %.2d R:%d T:%d" 92 "Hold time: %d\n", ht->ch.type, ht->ch.length, 93 ht->ch.tr / 2, ht->ch.tr % 2, ht->ch.holdtime); 94 if (ht->ch.holdtime != 0) 95 hi->keepalive = ht->ch.holdtime; 96 else { 97 if (ht->ch.res >> 15 == 0) 98 hi->keepalive = LDP_HELLO_KEEP; 99 else 100 hi->keepalive = LDP_THELLO_KEEP; 101 } 102 if (!get_ldp_peer(&pduid->ldp_id)) { 103 /* First of all set peer_addr to announced LDP_ID */ 104 memcpy(&peer_addr, &pduid->ldp_id, 105 sizeof(struct in_addr)); 106 /* 107 * Now let's see if there is any transport TLV in 108 * there 109 */ 110 if (pduid->length - PDU_PAYLOAD_LENGTH - 111 sizeof(struct hello_tlv) > 3) { 112 trtlv = (struct transport_address_tlv *) &ht[1]; 113 if (trtlv->type == TLV_IPV4_TRANSPORT) 114 memcpy(&peer_addr, &trtlv->address, 115 sizeof(struct in_addr)); 116 } else 117 trtlv = NULL; 118 /* 119 * RFC says: If A1 > A2, LSR1 plays the active role; 120 * otherwise it is passive. 121 */ 122 if (ntohl(peer_addr.s_addr) < ntohl(ladd->s_addr)) { 123 #define TRADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL 124 peer = ldp_peer_new(&pduid->ldp_id, padd, 125 TRADDR, ht->ch.holdtime, 0); 126 if (!peer) 127 return; 128 if (peer && peer->state == LDP_PEER_CONNECTED) 129 send_initialize(peer); 130 } 131 } 132 } 133 134 struct address_list_tlv * 135 build_address_list_tlv(void) 136 { 137 struct address_list_tlv *t; 138 struct ifaddrs *ifa, *ifb; 139 struct sockaddr_in *sa; 140 struct in_addr *ia; 141 uint16_t adrcount = 0; 142 143 if (getifaddrs(&ifa) == -1) 144 return NULL; 145 146 /* Find out the number of addresses */ 147 /* Ignore loopback */ 148 for (ifb = ifa; ifb; ifb = ifb->ifa_next) 149 if ((ifb->ifa_addr->sa_family == AF_INET) && 150 (ifb->ifa_flags & IFF_UP)) { 151 sa = (struct sockaddr_in *) ifb->ifa_addr; 152 if (ntohl(sa->sin_addr.s_addr) >> 24 != IN_LOOPBACKNET) 153 adrcount++; 154 } 155 t = malloc(sizeof(*t) + (adrcount - 1) * sizeof(struct in_addr)); 156 157 if (!t) { 158 fatalp("build_address_list_tlv: malloc problem\n"); 159 freeifaddrs(ifa); 160 return NULL; 161 } 162 163 t->type = htons(LDP_ADDRESS); 164 t->length = htons(sizeof(struct address_list_tlv) - TLV_TYPE_LENGTH 165 + (adrcount - 1) * sizeof(struct in_addr)); 166 t->messageid = htonl(get_message_id()); 167 168 t->a_type = htons(TLV_ADDRESS_LIST); 169 t->a_length = htons(sizeof(t->a_af) + 170 adrcount * sizeof(struct in_addr)); 171 t->a_af = htons(LDP_AF_INET); 172 173 ia = &t->a_address; 174 for (adrcount = 0, ifb = ifa; ifb; ifb = ifb->ifa_next) { 175 if ((ifb->ifa_addr->sa_family != AF_INET) || 176 (!(ifb->ifa_flags & IFF_UP)) || 177 (ifb->ifa_flags & IFF_LOOPBACK)) 178 continue; 179 sa = (struct sockaddr_in *) ifb->ifa_addr; 180 memcpy(&ia[adrcount], &sa->sin_addr, sizeof(struct in_addr)); 181 adrcount++; 182 } 183 freeifaddrs(ifa); 184 185 add_my_if_addrs(ia, adrcount); 186 return t; 187 } 188 189 /* 190 * Calculate LDP ID 191 * Get also mpls pseudo-interface address 192 */ 193 int 194 set_my_ldp_id() 195 { 196 struct ifaddrs *ifa, *ifb; 197 struct in_addr a; 198 struct sockaddr_in *sa; 199 200 a.s_addr = 0; 201 my_ldp_id[0] = '\0'; 202 mplssockaddr.sa_len = 0; 203 204 if (getifaddrs(&ifa) == -1) 205 return LDP_E_GENERIC; 206 207 for (ifb = ifa; ifb; ifb = ifb->ifa_next) 208 if(ifb->ifa_flags & IFF_UP) { 209 if (strncmp("mpls", ifb->ifa_name, 4) == 0 && 210 ifb->ifa_addr->sa_family == AF_LINK) 211 memcpy(&mplssockaddr, ifb->ifa_addr, 212 ifb->ifa_addr->sa_len); 213 214 if (ifb->ifa_addr->sa_family != AF_INET) 215 continue; 216 217 sa = (struct sockaddr_in *) ifb->ifa_addr; 218 if (ntohl(sa->sin_addr.s_addr) >> 24 == IN_LOOPBACKNET) 219 continue; /* No 127/8 */ 220 if (ntohl(sa->sin_addr.s_addr) > ntohl(a.s_addr)) 221 a.s_addr = sa->sin_addr.s_addr; 222 } 223 freeifaddrs(ifa); 224 debugp("LDP ID: %s\n", inet_ntoa(a)); 225 strlcpy(my_ldp_id, inet_ntoa(a), INET_ADDRSTRLEN); 226 return LDP_E_OK; 227 } 228