1 /* $NetBSD: fsm.c,v 1.3 2010/12/13 01:25:19 christos 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("Received it on 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"); 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) 95 hi->keepalive = ht->ch.holdtime; 96 if (!get_ldp_peer(&pduid->ldp_id)) { 97 /* First of all set peer_addr to announced LDP_ID */ 98 memcpy(&peer_addr, &pduid->ldp_id, 99 sizeof(struct in_addr)); 100 /* 101 * Now let's see if there is any transport TLV in 102 * there 103 */ 104 if (pduid->length - PDU_PAYLOAD_LENGTH - 105 sizeof(struct hello_tlv) > 3) { 106 trtlv = (struct transport_address_tlv *) &ht[1]; 107 if (trtlv->type == TLV_IPV4_TRANSPORT) 108 memcpy(&peer_addr, &trtlv->address, 109 sizeof(struct in_addr)); 110 } else 111 trtlv = NULL; 112 /* 113 * RFC says: If A1 > A2, LSR1 plays the active role; 114 * otherwise it is passive. 115 */ 116 if (ntohl(peer_addr.s_addr) < ntohl(ladd->s_addr)) { 117 #define TRADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL 118 peer = ldp_peer_new(&pduid->ldp_id, padd, 119 TRADDR, ht->ch.holdtime, 0); 120 if (!peer) 121 return; 122 if (peer && peer->state == LDP_PEER_CONNECTED) 123 send_initialize(peer); 124 } 125 } 126 } 127 128 struct address_list_tlv * 129 build_address_list_tlv(void) 130 { 131 struct address_list_tlv *t; 132 struct ifaddrs *ifa, *ifb; 133 struct sockaddr_in *sa; 134 struct in_addr *ia; 135 uint16_t adrcount = 0; 136 137 if (getifaddrs(&ifa) == -1) 138 return NULL; 139 140 /* Find out the number of addresses */ 141 /* Ignore loopback */ 142 for (ifb = ifa; ifb; ifb = ifb->ifa_next) 143 if ((ifb->ifa_addr->sa_family == AF_INET) && 144 (ifb->ifa_flags & IFF_UP)) { 145 sa = (struct sockaddr_in *) ifb->ifa_addr; 146 if (sa->sin_addr.s_addr << 24 >> 24 != 127) 147 adrcount++; 148 } 149 t = malloc(sizeof(*t) + (adrcount - 1) * sizeof(struct in_addr)); 150 151 if (!t) { 152 fatalp("build_address_list_tlv: malloc problem\n"); 153 return NULL; 154 } 155 156 t->type = htons(LDP_ADDRESS); 157 t->length = htons(sizeof(struct address_list_tlv) - TLV_TYPE_LENGTH 158 + (adrcount - 1) * sizeof(struct in_addr)); 159 t->messageid = htonl(get_message_id()); 160 161 t->a_type = htons(TLV_ADDRESS_LIST); 162 t->a_length = htons(sizeof(t->a_af) + 163 adrcount * sizeof(struct in_addr)); 164 t->a_af = htons(LDP_AF_INET); 165 166 ia = &t->a_address; 167 for (adrcount = 0, ifb = ifa; ifb; ifb = ifb->ifa_next) { 168 if ((ifb->ifa_addr->sa_family != AF_INET) || 169 (!(ifb->ifa_flags & IFF_UP)) || 170 (ifb->ifa_flags & IFF_LOOPBACK)) 171 continue; 172 sa = (struct sockaddr_in *) ifb->ifa_addr; 173 memcpy(&ia[adrcount], &sa->sin_addr, sizeof(struct in_addr)); 174 adrcount++; 175 } 176 freeifaddrs(ifa); 177 178 add_my_if_addrs(ia, adrcount); 179 return t; 180 } 181 182 /* 183 * Calculate LDP ID 184 * Get also mpls pseudo-interface address 185 */ 186 int 187 set_my_ldp_id() 188 { 189 struct ifaddrs *ifa, *ifb; 190 struct in_addr a; 191 struct sockaddr_in *sa; 192 193 a.s_addr = 0; 194 my_ldp_id[0] = 0; 195 mplssockaddr.sa_len = 0; 196 197 if (getifaddrs(&ifa) == -1) 198 return LDP_E_GENERIC; 199 200 for (ifb = ifa; ifb; ifb = ifb->ifa_next) 201 if(ifb->ifa_flags & IFF_UP) { 202 if (strncmp("mpls", ifb->ifa_name, 4) == 0 && 203 ifb->ifa_addr->sa_family == AF_LINK) 204 memcpy(&mplssockaddr, ifb->ifa_addr, 205 ifb->ifa_addr->sa_len); 206 207 if (ifb->ifa_addr->sa_family != AF_INET) 208 continue; 209 210 sa = (struct sockaddr_in *) ifb->ifa_addr; 211 if (ntohl(sa->sin_addr.s_addr) >> 24 == 127) 212 continue; /* No 127/8 */ 213 if (ntohl(sa->sin_addr.s_addr) > ntohl(a.s_addr)) 214 a.s_addr = sa->sin_addr.s_addr; 215 } 216 freeifaddrs(ifa); 217 debugp("LDP ID: %s\n", inet_ntoa(a)); 218 strlcpy(my_ldp_id, inet_ntoa(a), INET_ADDRSTRLEN); 219 return LDP_E_OK; 220 } 221