| File: | src/usr.sbin/mrouted/vif.c |
| Warning: | line 1056, column 18 Access to field 'al_addr' results in a dereference of a null pointer (loaded from variable 'n') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $NetBSD: vif.c,v 1.6 1995/12/10 10:07:19 mycroft Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * The mrouted program is covered by the license in the accompanying file | |||
| 5 | * named "LICENSE". Use of the mrouted program represents acceptance of | |||
| 6 | * the terms and conditions listed in that file. | |||
| 7 | * | |||
| 8 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of | |||
| 9 | * Leland Stanford Junior University. | |||
| 10 | */ | |||
| 11 | ||||
| 12 | ||||
| 13 | #include "defs.h" | |||
| 14 | #include <fcntl.h> | |||
| 15 | ||||
| 16 | /* | |||
| 17 | * Exported variables. | |||
| 18 | */ | |||
| 19 | struct uvif uvifs[MAXVIFS32]; /* array of virtual interfaces */ | |||
| 20 | vifi_t numvifs; /* number of vifs in use */ | |||
| 21 | int vifs_down; /* 1=>some interfaces are down */ | |||
| 22 | int phys_vif; /* An enabled vif */ | |||
| 23 | int udp_socket; /* Since the honkin' kernel doesn't support */ | |||
| 24 | /* ioctls on raw IP sockets, we need a UDP */ | |||
| 25 | /* socket as well as our IGMP (raw) socket. */ | |||
| 26 | /* How dumb. */ | |||
| 27 | int vifs_with_neighbors; /* == 1 if I am a leaf */ | |||
| 28 | ||||
| 29 | typedef struct { | |||
| 30 | vifi_t vifi; | |||
| 31 | struct listaddr *g; | |||
| 32 | int q_time; | |||
| 33 | } cbk_t; | |||
| 34 | ||||
| 35 | /* | |||
| 36 | * Forward declarations. | |||
| 37 | */ | |||
| 38 | static void start_vif(vifi_t vifi); | |||
| 39 | static void start_vif2(vifi_t vifi); | |||
| 40 | static void stop_vif(vifi_t vifi); | |||
| 41 | static void age_old_hosts(void); | |||
| 42 | static void send_probe_on_vif(struct uvif *v); | |||
| 43 | static int info_version(char *p, int); | |||
| 44 | static void DelVif(void *arg); | |||
| 45 | static int SetTimer(int vifi, struct listaddr *g); | |||
| 46 | static int DeleteTimer(int id); | |||
| 47 | static void SendQuery(void *arg); | |||
| 48 | static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, | |||
| 49 | int q_time); | |||
| 50 | ||||
| 51 | ||||
| 52 | /* | |||
| 53 | * Initialize the virtual interfaces, but do not install | |||
| 54 | * them in the kernel. Start routing on all vifs that are | |||
| 55 | * not down or disabled. | |||
| 56 | */ | |||
| 57 | void | |||
| 58 | init_vifs(void) | |||
| 59 | { | |||
| 60 | vifi_t vifi; | |||
| 61 | struct uvif *v; | |||
| 62 | int enabled_vifs, enabled_phyints; | |||
| 63 | extern char *configfilename; | |||
| 64 | ||||
| 65 | numvifs = 0; | |||
| 66 | vifs_with_neighbors = 0; | |||
| 67 | vifs_down = FALSE0; | |||
| 68 | ||||
| 69 | /* | |||
| 70 | * Configure the vifs based on the interface configuration of the | |||
| 71 | * the kernel and the contents of the configuration file. | |||
| 72 | * (Open a UDP socket for ioctl use in the config procedures.) | |||
| 73 | */ | |||
| 74 | if ((udp_socket = socket(AF_INET2, SOCK_DGRAM2, 0)) == -1) | |||
| 75 | logit(LOG_ERR3, errno(*__errno()), "UDP socket"); | |||
| 76 | logit(LOG_INFO6,0,"Getting vifs from kernel interfaces"); | |||
| 77 | config_vifs_from_kernel(); | |||
| 78 | logit(LOG_INFO6,0,"Getting vifs from %s",configfilename); | |||
| 79 | config_vifs_from_file(); | |||
| 80 | ||||
| 81 | /* | |||
| 82 | * Quit if there are fewer than two enabled vifs. | |||
| 83 | */ | |||
| 84 | enabled_vifs = 0; | |||
| 85 | enabled_phyints = 0; | |||
| 86 | phys_vif = -1; | |||
| 87 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { | |||
| 88 | if (!(v->uv_flags & VIFF_DISABLED0x0200)) { | |||
| 89 | ++enabled_vifs; | |||
| 90 | if (!(v->uv_flags & VIFF_TUNNEL0x1)) { | |||
| 91 | if (phys_vif == -1) | |||
| 92 | phys_vif = vifi; | |||
| 93 | ++enabled_phyints; | |||
| 94 | } | |||
| 95 | } | |||
| 96 | } | |||
| 97 | if (enabled_vifs < 2) | |||
| 98 | logit(LOG_ERR3, 0, "can't forward: %s", | |||
| 99 | enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif"); | |||
| 100 | ||||
| 101 | if (enabled_phyints == 0) | |||
| 102 | logit(LOG_WARNING4, 0, | |||
| 103 | "no enabled interfaces, forwarding via tunnels only"); | |||
| 104 | ||||
| 105 | logit(LOG_INFO6, 0, "Installing vifs in mrouted..."); | |||
| 106 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { | |||
| 107 | if (!(v->uv_flags & VIFF_DISABLED0x0200)) { | |||
| 108 | if (!(v->uv_flags & VIFF_DOWN0x0100)) { | |||
| 109 | if (v->uv_flags & VIFF_TUNNEL0x1) | |||
| 110 | logit(LOG_INFO6, 0, "vif #%d, tunnel %s -> %s", vifi, | |||
| 111 | inet_fmt(v->uv_lcl_addr, s1), | |||
| 112 | inet_fmt(v->uv_rmt_addr, s2)); | |||
| 113 | else | |||
| 114 | logit(LOG_INFO6, 0, "vif #%d, phyint %s", vifi, | |||
| 115 | inet_fmt(v->uv_lcl_addr, s1)); | |||
| 116 | start_vif2(vifi); | |||
| 117 | } else logit(LOG_INFO6, 0, | |||
| 118 | "%s is not yet up; vif #%u not in service", | |||
| 119 | v->uv_name, vifi); | |||
| 120 | } | |||
| 121 | } | |||
| 122 | } | |||
| 123 | ||||
| 124 | /* | |||
| 125 | * Start routing on all virtual interfaces that are not down or | |||
| 126 | * administratively disabled. | |||
| 127 | */ | |||
| 128 | void | |||
| 129 | init_installvifs(void) | |||
| 130 | { | |||
| 131 | vifi_t vifi; | |||
| 132 | struct uvif *v; | |||
| 133 | ||||
| 134 | logit(LOG_INFO6, 0, "Installing vifs in kernel..."); | |||
| 135 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { | |||
| 136 | if (!(v->uv_flags & VIFF_DISABLED0x0200)) { | |||
| 137 | if (!(v->uv_flags & VIFF_DOWN0x0100)) { | |||
| 138 | if (v->uv_flags & VIFF_TUNNEL0x1) | |||
| 139 | logit(LOG_INFO6, 0, "vif #%d, tunnel %s -> %s", vifi, | |||
| 140 | inet_fmt(v->uv_lcl_addr, s1), | |||
| 141 | inet_fmt(v->uv_rmt_addr, s2)); | |||
| 142 | else | |||
| 143 | logit(LOG_INFO6, 0, "vif #%d, phyint %s", vifi, | |||
| 144 | inet_fmt(v->uv_lcl_addr, s1)); | |||
| 145 | k_add_vif(vifi, &uvifs[vifi]); | |||
| 146 | } else logit(LOG_INFO6, 0, | |||
| 147 | "%s is not yet up; vif #%u not in service", | |||
| 148 | v->uv_name, vifi); | |||
| 149 | } | |||
| 150 | } | |||
| 151 | } | |||
| 152 | ||||
| 153 | /* | |||
| 154 | * See if any interfaces have changed from up state to down, or vice versa, | |||
| 155 | * including any non-multicast-capable interfaces that are in use as local | |||
| 156 | * tunnel end-points. Ignore interfaces that have been administratively | |||
| 157 | * disabled. | |||
| 158 | */ | |||
| 159 | void | |||
| 160 | check_vif_state(void) | |||
| 161 | { | |||
| 162 | vifi_t vifi; | |||
| 163 | struct uvif *v; | |||
| 164 | struct ifreq ifr; | |||
| 165 | ||||
| 166 | vifs_down = FALSE0; | |||
| 167 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { | |||
| 168 | ||||
| 169 | if (v->uv_flags & VIFF_DISABLED0x0200) continue; | |||
| 170 | ||||
| 171 | strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ16); | |||
| 172 | if (ioctl(udp_socket, SIOCGIFFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((17))), (char *)&ifr) == -1) | |||
| 173 | logit(LOG_ERR3, errno(*__errno()), | |||
| 174 | "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); | |||
| 175 | ||||
| 176 | if (v->uv_flags & VIFF_DOWN0x0100) { | |||
| 177 | if (ifr.ifr_flagsifr_ifru.ifru_flags & IFF_UP0x1) { | |||
| 178 | v->uv_flags &= ~VIFF_DOWN0x0100; | |||
| 179 | start_vif(vifi); | |||
| 180 | logit(LOG_INFO6, 0, | |||
| 181 | "%s has come up; vif #%u now in service", | |||
| 182 | v->uv_name, vifi); | |||
| 183 | } | |||
| 184 | else vifs_down = TRUE1; | |||
| 185 | } | |||
| 186 | else { | |||
| 187 | if (!(ifr.ifr_flagsifr_ifru.ifru_flags & IFF_UP0x1)) { | |||
| 188 | stop_vif(vifi); | |||
| 189 | v->uv_flags |= VIFF_DOWN0x0100; | |||
| 190 | logit(LOG_INFO6, 0, | |||
| 191 | "%s has gone down; vif #%u taken out of service", | |||
| 192 | v->uv_name, vifi); | |||
| 193 | vifs_down = TRUE1; | |||
| 194 | } | |||
| 195 | } | |||
| 196 | } | |||
| 197 | } | |||
| 198 | ||||
| 199 | /* | |||
| 200 | * Send a probe message on vif v | |||
| 201 | */ | |||
| 202 | static void | |||
| 203 | send_probe_on_vif(struct uvif *v) | |||
| 204 | { | |||
| 205 | char *p; | |||
| 206 | int datalen = 0; | |||
| 207 | struct listaddr *nbr; | |||
| 208 | int i; | |||
| 209 | ||||
| 210 | p = send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8; | |||
| 211 | ||||
| 212 | for (i = 0; i < 4; i++) | |||
| 213 | *p++ = ((char *)&(dvmrp_genid))[i]; | |||
| 214 | datalen += 4; | |||
| 215 | ||||
| 216 | /* | |||
| 217 | * add the neighbor list on the interface to the message | |||
| 218 | */ | |||
| 219 | nbr = v->uv_neighbors; | |||
| 220 | ||||
| 221 | while (nbr) { | |||
| 222 | for (i = 0; i < 4; i++) | |||
| 223 | *p++ = ((char *)&nbr->al_addr)[i]; | |||
| 224 | datalen +=4; | |||
| 225 | nbr = nbr->al_next; | |||
| 226 | } | |||
| 227 | ||||
| 228 | send_igmp(v->uv_lcl_addr, | |||
| 229 | (v->uv_flags & VIFF_TUNNEL0x1) ? v->uv_rmt_addr | |||
| 230 | : dvmrp_group, | |||
| 231 | IGMP_DVMRP0x13, DVMRP_PROBE1, | |||
| 232 | htonl(MROUTED_LEVEL |(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) ? (__uint32_t)(((__uint32_t)(((8 << 8) | 3 | (( 0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v-> uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff) << 24 | ((__uint32_t)(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff00) << 8 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff0000) >> 8 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff000000) >> 24) : __swap32md (((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)))) | |||
| 233 | ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS))(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) ? (__uint32_t)(((__uint32_t)(((8 << 8) | 3 | (( 0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v-> uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff) << 24 | ((__uint32_t)(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff00) << 8 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff0000) >> 8 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0))) & 0xff000000) >> 24) : __swap32md (((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24)) | ((v->uv_flags & 0x1000) ? 0 : (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)))), | |||
| 234 | datalen); | |||
| 235 | } | |||
| 236 | ||||
| 237 | /* | |||
| 238 | * Add a vifi to the kernel and start routing on it. | |||
| 239 | */ | |||
| 240 | static void | |||
| 241 | start_vif(vifi_t vifi) | |||
| 242 | { | |||
| 243 | /* | |||
| 244 | * Install the interface in the kernel's vif structure. | |||
| 245 | */ | |||
| 246 | k_add_vif(vifi, &uvifs[vifi]); | |||
| 247 | ||||
| 248 | start_vif2(vifi); | |||
| 249 | } | |||
| 250 | ||||
| 251 | /* | |||
| 252 | * Add a vifi to all the user-level data structures but don't add | |||
| 253 | * it to the kernel yet. | |||
| 254 | */ | |||
| 255 | static void | |||
| 256 | start_vif2(vifi_t vifi) | |||
| 257 | { | |||
| 258 | struct uvif *v; | |||
| 259 | u_int32_t src; | |||
| 260 | struct phaddr *p; | |||
| 261 | ||||
| 262 | v = &uvifs[vifi]; | |||
| 263 | src = v->uv_lcl_addr; | |||
| 264 | ||||
| 265 | /* | |||
| 266 | * Update the existing route entries to take into account the new vif. | |||
| 267 | */ | |||
| 268 | add_vif_to_routes(vifi); | |||
| 269 | ||||
| 270 | if (!(v->uv_flags & VIFF_TUNNEL0x1)) { | |||
| 271 | /* | |||
| 272 | * Join the DVMRP multicast group on the interface. | |||
| 273 | * (This is not strictly necessary, since the kernel promiscuously | |||
| 274 | * receives IGMP packets addressed to ANY IP multicast group while | |||
| 275 | * multicast routing is enabled. However, joining the group allows | |||
| 276 | * this host to receive non-IGMP packets as well, such as 'pings'.) | |||
| 277 | */ | |||
| 278 | k_join(dvmrp_group, src); | |||
| 279 | ||||
| 280 | /* | |||
| 281 | * Join the ALL-ROUTERS multicast group on the interface. | |||
| 282 | * This allows mtrace requests to loop back if they are run | |||
| 283 | * on the multicast router. | |||
| 284 | */ | |||
| 285 | k_join(allrtrs_group, src); | |||
| 286 | ||||
| 287 | /* | |||
| 288 | * Install an entry in the routing table for the subnet to which | |||
| 289 | * the interface is connected. | |||
| 290 | */ | |||
| 291 | start_route_updates(); | |||
| 292 | update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi); | |||
| 293 | for (p = v->uv_addrs; p; p = p->pa_next) { | |||
| 294 | start_route_updates(); | |||
| 295 | update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi); | |||
| 296 | } | |||
| 297 | ||||
| 298 | /* | |||
| 299 | * Until neighbors are discovered, assume responsibility for sending | |||
| 300 | * periodic group membership queries to the subnet. Send the first | |||
| 301 | * query. | |||
| 302 | */ | |||
| 303 | v->uv_flags |= VIFF_QUERIER0x0400; | |||
| 304 | send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY0x11, | |||
| 305 | (v->uv_flags & VIFF_IGMPV10x2000) ? 0 : | |||
| 306 | IGMP_MAX_HOST_REPORT_DELAY10 * IGMP_TIMER_SCALE10, 0, 0); | |||
| 307 | age_old_hosts(); | |||
| 308 | } | |||
| 309 | ||||
| 310 | v->uv_leaf_timer = LEAF_CONFIRMATION_TIME200; | |||
| 311 | ||||
| 312 | /* | |||
| 313 | * Send a probe via the new vif to look for neighbors. | |||
| 314 | */ | |||
| 315 | send_probe_on_vif(v); | |||
| 316 | } | |||
| 317 | ||||
| 318 | /* | |||
| 319 | * Stop routing on the specified virtual interface. | |||
| 320 | */ | |||
| 321 | static void | |||
| 322 | stop_vif(vifi_t vifi) | |||
| 323 | { | |||
| 324 | struct uvif *v; | |||
| 325 | struct listaddr *a; | |||
| 326 | struct phaddr *p; | |||
| 327 | ||||
| 328 | v = &uvifs[vifi]; | |||
| 329 | ||||
| 330 | if (!(v->uv_flags & VIFF_TUNNEL0x1)) { | |||
| 331 | /* | |||
| 332 | * Depart from the DVMRP multicast group on the interface. | |||
| 333 | */ | |||
| 334 | k_leave(dvmrp_group, v->uv_lcl_addr); | |||
| 335 | ||||
| 336 | /* | |||
| 337 | * Depart from the ALL-ROUTERS multicast group on the interface. | |||
| 338 | */ | |||
| 339 | k_leave(allrtrs_group, v->uv_lcl_addr); | |||
| 340 | ||||
| 341 | /* | |||
| 342 | * Update the entry in the routing table for the subnet to which | |||
| 343 | * the interface is connected, to take into account the interface | |||
| 344 | * failure. | |||
| 345 | */ | |||
| 346 | start_route_updates(); | |||
| 347 | update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE32, 0, vifi); | |||
| 348 | for (p = v->uv_addrs; p; p = p->pa_next) { | |||
| 349 | start_route_updates(); | |||
| 350 | update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE32, 0, vifi); | |||
| 351 | } | |||
| 352 | ||||
| 353 | /* | |||
| 354 | * Discard all group addresses. (No need to tell kernel; | |||
| 355 | * the k_del_vif() call, below, will clean up kernel state.) | |||
| 356 | */ | |||
| 357 | while (v->uv_groups != NULL((void *)0)) { | |||
| 358 | a = v->uv_groups; | |||
| 359 | v->uv_groups = a->al_next; | |||
| 360 | free((char *)a); | |||
| 361 | } | |||
| 362 | ||||
| 363 | v->uv_flags &= ~VIFF_QUERIER0x0400; | |||
| 364 | } | |||
| 365 | ||||
| 366 | /* | |||
| 367 | * Update the existing route entries to take into account the vif failure. | |||
| 368 | */ | |||
| 369 | delete_vif_from_routes(vifi); | |||
| 370 | ||||
| 371 | /* | |||
| 372 | * Delete the interface from the kernel's vif structure. | |||
| 373 | */ | |||
| 374 | k_del_vif(vifi); | |||
| 375 | ||||
| 376 | /* | |||
| 377 | * Discard all neighbor addresses. | |||
| 378 | */ | |||
| 379 | if (v->uv_neighbors) | |||
| 380 | vifs_with_neighbors--; | |||
| 381 | ||||
| 382 | while (v->uv_neighbors != NULL((void *)0)) { | |||
| 383 | a = v->uv_neighbors; | |||
| 384 | v->uv_neighbors = a->al_next; | |||
| 385 | free((char *)a); | |||
| 386 | } | |||
| 387 | } | |||
| 388 | ||||
| 389 | ||||
| 390 | /* | |||
| 391 | * stop routing on all vifs | |||
| 392 | */ | |||
| 393 | void | |||
| 394 | stop_all_vifs(void) | |||
| 395 | { | |||
| 396 | vifi_t vifi; | |||
| 397 | struct uvif *v; | |||
| 398 | struct listaddr *a; | |||
| 399 | struct vif_acl *acl; | |||
| 400 | ||||
| 401 | for (vifi = 0; vifi < numvifs; vifi++) { | |||
| 402 | v = &uvifs[vifi]; | |||
| 403 | while (v->uv_groups != NULL((void *)0)) { | |||
| 404 | a = v->uv_groups; | |||
| 405 | v->uv_groups = a->al_next; | |||
| 406 | free((char *)a); | |||
| 407 | } | |||
| 408 | while (v->uv_neighbors != NULL((void *)0)) { | |||
| 409 | a = v->uv_neighbors; | |||
| 410 | v->uv_neighbors = a->al_next; | |||
| 411 | free((char *)a); | |||
| 412 | } | |||
| 413 | while (v->uv_acl != NULL((void *)0)) { | |||
| 414 | acl = v->uv_acl; | |||
| 415 | v->uv_acl = acl->acl_next; | |||
| 416 | free((char *)acl); | |||
| 417 | } | |||
| 418 | } | |||
| 419 | } | |||
| 420 | ||||
| 421 | ||||
| 422 | /* | |||
| 423 | * Find the virtual interface from which an incoming packet arrived, | |||
| 424 | * based on the packet's source and destination IP addresses. | |||
| 425 | */ | |||
| 426 | vifi_t | |||
| 427 | find_vif(u_int32_t src, u_int32_t dst) | |||
| 428 | { | |||
| 429 | vifi_t vifi; | |||
| 430 | struct uvif *v; | |||
| 431 | struct phaddr *p; | |||
| 432 | ||||
| 433 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { | |||
| 434 | if (!(v->uv_flags & (VIFF_DOWN0x0100|VIFF_DISABLED0x0200))) { | |||
| 435 | if (v->uv_flags & VIFF_TUNNEL0x1) { | |||
| 436 | if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr) | |||
| 437 | return(vifi); | |||
| 438 | } | |||
| 439 | else { | |||
| 440 | if ((src & v->uv_subnetmask) == v->uv_subnet && | |||
| 441 | ((v->uv_subnetmask == 0xffffffff) || | |||
| 442 | (src != v->uv_subnetbcast))) | |||
| 443 | return(vifi); | |||
| 444 | for (p=v->uv_addrs; p; p=p->pa_next) { | |||
| 445 | if ((src & p->pa_subnetmask) == p->pa_subnet && | |||
| 446 | ((p->pa_subnetmask == 0xffffffff) || | |||
| 447 | (src != p->pa_subnetbcast))) | |||
| 448 | return(vifi); | |||
| 449 | } | |||
| 450 | } | |||
| 451 | } | |||
| 452 | } | |||
| 453 | return (NO_VIF((vifi_t)32)); | |||
| 454 | } | |||
| 455 | ||||
| 456 | static void | |||
| 457 | age_old_hosts(void) | |||
| 458 | { | |||
| 459 | vifi_t vifi; | |||
| 460 | struct uvif *v; | |||
| 461 | struct listaddr *g; | |||
| 462 | ||||
| 463 | /* | |||
| 464 | * Decrement the old-hosts-present timer for each | |||
| 465 | * active group on each vif. | |||
| 466 | */ | |||
| 467 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) | |||
| 468 | for (g = v->uv_groups; g != NULL((void *)0); g = g->al_next) | |||
| 469 | if (g->al_old) | |||
| 470 | g->al_old--; | |||
| 471 | } | |||
| 472 | ||||
| 473 | ||||
| 474 | /* | |||
| 475 | * Send group membership queries to all subnets for which I am querier. | |||
| 476 | */ | |||
| 477 | void | |||
| 478 | query_groups(void) | |||
| 479 | { | |||
| 480 | vifi_t vifi; | |||
| 481 | struct uvif *v; | |||
| 482 | ||||
| 483 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { | |||
| 484 | if (v->uv_flags & VIFF_QUERIER0x0400) { | |||
| 485 | send_igmp(v->uv_lcl_addr, allhosts_group, | |||
| 486 | IGMP_HOST_MEMBERSHIP_QUERY0x11, | |||
| 487 | (v->uv_flags & VIFF_IGMPV10x2000) ? 0 : | |||
| 488 | IGMP_MAX_HOST_REPORT_DELAY10 * IGMP_TIMER_SCALE10, 0, 0); | |||
| 489 | } | |||
| 490 | } | |||
| 491 | age_old_hosts(); | |||
| 492 | } | |||
| 493 | ||||
| 494 | /* | |||
| 495 | * Process an incoming host membership query | |||
| 496 | */ | |||
| 497 | void | |||
| 498 | accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group, | |||
| 499 | int tmo) | |||
| 500 | { | |||
| 501 | vifi_t vifi; | |||
| 502 | struct uvif *v; | |||
| 503 | ||||
| 504 | if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32) || | |||
| 505 | (uvifs[vifi].uv_flags & VIFF_TUNNEL0x1)) { | |||
| 506 | logit(LOG_INFO6, 0, | |||
| 507 | "ignoring group membership query from non-adjacent host %s", | |||
| 508 | inet_fmt(src, s1)); | |||
| 509 | return; | |||
| 510 | } | |||
| 511 | ||||
| 512 | v = &uvifs[vifi]; | |||
| 513 | ||||
| 514 | /* | |||
| 515 | * If we consider ourselves the querier for this vif, but hear a | |||
| 516 | * query from a router with a lower IP address, yield to them. | |||
| 517 | * | |||
| 518 | * This is done here as well as in the neighbor discovery in case | |||
| 519 | * there is a querier that doesn't speak DVMRP. | |||
| 520 | * | |||
| 521 | * XXX If this neighbor doesn't speak DVMRP, then we need to create | |||
| 522 | * some neighbor state for him so that we can time him out! | |||
| 523 | */ | |||
| 524 | if ((v->uv_flags & VIFF_QUERIER0x0400) && | |||
| 525 | (ntohl(src)(__uint32_t)(__builtin_constant_p(src) ? (__uint32_t)(((__uint32_t )(src) & 0xff) << 24 | ((__uint32_t)(src) & 0xff00 ) << 8 | ((__uint32_t)(src) & 0xff0000) >> 8 | ((__uint32_t)(src) & 0xff000000) >> 24) : __swap32md (src)) < ntohl(v->uv_lcl_addr)(__uint32_t)(__builtin_constant_p(v->uv_lcl_addr) ? (__uint32_t )(((__uint32_t)(v->uv_lcl_addr) & 0xff) << 24 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff00) << 8 | (( __uint32_t)(v->uv_lcl_addr) & 0xff0000) >> 8 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff000000) >> 24 ) : __swap32md(v->uv_lcl_addr)))) { | |||
| 526 | v->uv_flags &= ~VIFF_QUERIER0x0400; | |||
| 527 | ||||
| 528 | } | |||
| 529 | } | |||
| 530 | ||||
| 531 | /* | |||
| 532 | * Process an incoming group membership report. | |||
| 533 | */ | |||
| 534 | void | |||
| 535 | accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, | |||
| 536 | int r_type) | |||
| 537 | { | |||
| 538 | vifi_t vifi; | |||
| 539 | struct uvif *v; | |||
| 540 | struct listaddr *g; | |||
| 541 | ||||
| 542 | if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32) || | |||
| 543 | (uvifs[vifi].uv_flags & VIFF_TUNNEL0x1)) { | |||
| 544 | logit(LOG_INFO6, 0, | |||
| 545 | "ignoring group membership report from non-adjacent host %s", | |||
| 546 | inet_fmt(src, s1)); | |||
| 547 | return; | |||
| 548 | } | |||
| 549 | ||||
| 550 | v = &uvifs[vifi]; | |||
| 551 | ||||
| 552 | /* | |||
| 553 | * Look for the group in our group list; if found, reset its timer. | |||
| 554 | */ | |||
| 555 | for (g = v->uv_groups; g != NULL((void *)0); g = g->al_next) { | |||
| 556 | if (group == g->al_addr) { | |||
| 557 | if (r_type == IGMP_v1_HOST_MEMBERSHIP_REPORT0x12) | |||
| 558 | g->al_old = OLD_AGE_THRESHOLD2; | |||
| 559 | ||||
| 560 | /** delete old timers, set a timer for expiration **/ | |||
| 561 | g->al_timer = GROUP_EXPIRE_TIME270; | |||
| 562 | if (g->al_query) | |||
| 563 | g->al_query = DeleteTimer(g->al_query); | |||
| 564 | if (g->al_timerid) | |||
| 565 | g->al_timerid = DeleteTimer(g->al_timerid); | |||
| 566 | g->al_timerid = SetTimer(vifi, g); | |||
| 567 | break; | |||
| 568 | } | |||
| 569 | } | |||
| 570 | ||||
| 571 | /* | |||
| 572 | * If not found, add it to the list and update kernel cache. | |||
| 573 | */ | |||
| 574 | if (g == NULL((void *)0)) { | |||
| 575 | g = malloc(sizeof(struct listaddr)); | |||
| 576 | if (g == NULL((void *)0)) | |||
| 577 | logit(LOG_ERR3, 0, "ran out of memory"); /* fatal */ | |||
| 578 | ||||
| 579 | g->al_addr = group; | |||
| 580 | if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT0x16) | |||
| 581 | g->al_old = 0; | |||
| 582 | else | |||
| 583 | g->al_old = OLD_AGE_THRESHOLD2; | |||
| 584 | ||||
| 585 | /** set a timer for expiration **/ | |||
| 586 | g->al_query = 0; | |||
| 587 | g->al_timer = GROUP_EXPIRE_TIME270; | |||
| 588 | time(&g->al_ctime); | |||
| 589 | g->al_timerid = SetTimer(vifi, g); | |||
| 590 | g->al_next = v->uv_groups; | |||
| 591 | v->uv_groups = g; | |||
| 592 | ||||
| 593 | update_lclgrp(vifi, group); | |||
| 594 | } | |||
| 595 | ||||
| 596 | /* | |||
| 597 | * Check if a graft is necessary for this group | |||
| 598 | */ | |||
| 599 | chkgrp_graft(vifi, group); | |||
| 600 | } | |||
| 601 | ||||
| 602 | ||||
| 603 | void | |||
| 604 | accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group) | |||
| 605 | { | |||
| 606 | vifi_t vifi; | |||
| 607 | struct uvif *v; | |||
| 608 | struct listaddr *g; | |||
| 609 | ||||
| 610 | if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32) || | |||
| 611 | (uvifs[vifi].uv_flags & VIFF_TUNNEL0x1)) { | |||
| 612 | logit(LOG_INFO6, 0, | |||
| 613 | "ignoring group leave report from non-adjacent host %s", | |||
| 614 | inet_fmt(src, s1)); | |||
| 615 | return; | |||
| 616 | } | |||
| 617 | ||||
| 618 | v = &uvifs[vifi]; | |||
| 619 | ||||
| 620 | if (!(v->uv_flags & VIFF_QUERIER0x0400) || (v->uv_flags & VIFF_IGMPV10x2000)) | |||
| 621 | return; | |||
| 622 | ||||
| 623 | /* | |||
| 624 | * Look for the group in our group list in order to set up a short-timeout | |||
| 625 | * query. | |||
| 626 | */ | |||
| 627 | for (g = v->uv_groups; g != NULL((void *)0); g = g->al_next) { | |||
| 628 | if (group == g->al_addr) { | |||
| 629 | logit(LOG_DEBUG7, 0, | |||
| 630 | "[vif.c, _accept_leave_message] %d %d \n", | |||
| 631 | g->al_old, g->al_query); | |||
| 632 | ||||
| 633 | /* Ignore the leave message if there are old hosts present */ | |||
| 634 | if (g->al_old) | |||
| 635 | return; | |||
| 636 | ||||
| 637 | /* still waiting for a reply to a query, ignore the leave */ | |||
| 638 | if (g->al_query) | |||
| 639 | return; | |||
| 640 | ||||
| 641 | /** delete old timer set a timer for expiration **/ | |||
| 642 | if (g->al_timerid) | |||
| 643 | g->al_timerid = DeleteTimer(g->al_timerid); | |||
| 644 | ||||
| 645 | /** send a group specific querry **/ | |||
| 646 | g->al_timer = LEAVE_EXPIRE_TIME3; | |||
| 647 | send_igmp(v->uv_lcl_addr, g->al_addr, | |||
| 648 | IGMP_HOST_MEMBERSHIP_QUERY0x11, | |||
| 649 | LEAVE_EXPIRE_TIME3 / 3 * IGMP_TIMER_SCALE10, | |||
| 650 | g->al_addr, 0); | |||
| 651 | g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3, | |||
| 652 | LEAVE_EXPIRE_TIME3 / 3 * IGMP_TIMER_SCALE10); | |||
| 653 | g->al_timerid = SetTimer(vifi, g); | |||
| 654 | break; | |||
| 655 | } | |||
| 656 | } | |||
| 657 | } | |||
| 658 | ||||
| 659 | ||||
| 660 | /* | |||
| 661 | * Send a periodic probe on all vifs. | |||
| 662 | * Useful to determine one-way interfaces. | |||
| 663 | * Detect neighbor loss faster. | |||
| 664 | */ | |||
| 665 | void | |||
| 666 | probe_for_neighbors(void) | |||
| 667 | { | |||
| 668 | vifi_t vifi; | |||
| 669 | struct uvif *v; | |||
| 670 | ||||
| 671 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { | |||
| 672 | if (!(v->uv_flags & (VIFF_DOWN0x0100|VIFF_DISABLED0x0200))) { | |||
| 673 | send_probe_on_vif(v); | |||
| 674 | } | |||
| 675 | } | |||
| 676 | } | |||
| 677 | ||||
| 678 | ||||
| 679 | /* | |||
| 680 | * Send a list of all of our neighbors to the requestor, `src'. | |||
| 681 | */ | |||
| 682 | void | |||
| 683 | accept_neighbor_request(u_int32_t src, u_int32_t dst) | |||
| 684 | { | |||
| 685 | vifi_t vifi; | |||
| 686 | struct uvif *v; | |||
| 687 | u_char *p, *ncount; | |||
| 688 | struct listaddr *la; | |||
| 689 | int datalen; | |||
| 690 | u_int32_t temp_addr, us, them = src; | |||
| 691 | ||||
| 692 | /* Determine which of our addresses to use as the source of our response | |||
| 693 | * to this query. | |||
| 694 | */ | |||
| 695 | if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t )(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)( dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000 ) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24 ) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xe0000000)))) { /* query sent to a multicast group */ | |||
| 696 | int udp; /* find best interface to reply on */ | |||
| 697 | struct sockaddr_in addr; | |||
| 698 | int addrlen = sizeof(addr); | |||
| 699 | ||||
| 700 | memset(&addr, 0, sizeof addr); | |||
| 701 | addr.sin_family = AF_INET2; | |||
| 702 | addr.sin_len = sizeof addr; | |||
| 703 | addr.sin_addr.s_addr = dst; | |||
| 704 | addr.sin_port = htons(2000)(__uint16_t)(__builtin_constant_p(2000) ? (__uint16_t)(((__uint16_t )(2000) & 0xffU) << 8 | ((__uint16_t)(2000) & 0xff00U ) >> 8) : __swap16md(2000)); /* any port over 1024 will do... */ | |||
| 705 | if ((udp = socket(AF_INET2, SOCK_DGRAM2, 0)) == -1 | |||
| 706 | || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) == -1 | |||
| 707 | || getsockname(udp, (struct sockaddr *) &addr, &addrlen) == -1) { | |||
| 708 | logit(LOG_WARNING4, errno(*__errno()), "Determining local address"); | |||
| 709 | close(udp); | |||
| 710 | return; | |||
| 711 | } | |||
| 712 | close(udp); | |||
| 713 | us = addr.sin_addr.s_addr; | |||
| 714 | } else /* query sent to us alone */ | |||
| 715 | us = dst; | |||
| 716 | ||||
| 717 | #define PUT_ADDR(a)temp_addr = (__uint32_t)(__builtin_constant_p(a) ? (__uint32_t )(((__uint32_t)(a) & 0xff) << 24 | ((__uint32_t)(a) & 0xff00) << 8 | ((__uint32_t)(a) & 0xff0000) >> 8 | ((__uint32_t)(a) & 0xff000000) >> 24) : __swap32md (a)); *p++ = temp_addr >> 24; *p++ = (temp_addr >> 16) & 0xFF; *p++ = (temp_addr >> 8) & 0xFF; *p ++ = temp_addr & 0xFF; temp_addr = ntohl(a)(__uint32_t)(__builtin_constant_p(a) ? (__uint32_t)(((__uint32_t )(a) & 0xff) << 24 | ((__uint32_t)(a) & 0xff00) << 8 | ((__uint32_t)(a) & 0xff0000) >> 8 | ( (__uint32_t)(a) & 0xff000000) >> 24) : __swap32md(a )); \ | |||
| 718 | *p++ = temp_addr >> 24; \ | |||
| 719 | *p++ = (temp_addr >> 16) & 0xFF; \ | |||
| 720 | *p++ = (temp_addr >> 8) & 0xFF; \ | |||
| 721 | *p++ = temp_addr & 0xFF; | |||
| 722 | ||||
| 723 | p = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 724 | datalen = 0; | |||
| 725 | ||||
| 726 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { | |||
| 727 | if (v->uv_flags & VIFF_DISABLED0x0200) | |||
| 728 | continue; | |||
| 729 | ||||
| 730 | ncount = 0; | |||
| 731 | ||||
| 732 | for (la = v->uv_neighbors; la; la = la->al_next) { | |||
| 733 | ||||
| 734 | /* Make sure that there's room for this neighbor... */ | |||
| 735 | if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN( 576 - 60 - 8 )) { | |||
| 736 | send_igmp(us, them, IGMP_DVMRP0x13, DVMRP_NEIGHBORS4, | |||
| 737 | htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), datalen); | |||
| 738 | p = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 739 | datalen = 0; | |||
| 740 | ncount = 0; | |||
| 741 | } | |||
| 742 | ||||
| 743 | /* Put out the header for this neighbor list... */ | |||
| 744 | if (ncount == 0) { | |||
| 745 | PUT_ADDR(v->uv_lcl_addr)temp_addr = (__uint32_t)(__builtin_constant_p(v->uv_lcl_addr ) ? (__uint32_t)(((__uint32_t)(v->uv_lcl_addr) & 0xff) << 24 | ((__uint32_t)(v->uv_lcl_addr) & 0xff00) << 8 | ((__uint32_t)(v->uv_lcl_addr) & 0xff0000 ) >> 8 | ((__uint32_t)(v->uv_lcl_addr) & 0xff000000 ) >> 24) : __swap32md(v->uv_lcl_addr)); *p++ = temp_addr >> 24; *p++ = (temp_addr >> 16) & 0xFF; *p++ = (temp_addr >> 8) & 0xFF; *p++ = temp_addr & 0xFF ;; | |||
| 746 | *p++ = v->uv_metric; | |||
| 747 | *p++ = v->uv_threshold; | |||
| 748 | ncount = p; | |||
| 749 | *p++ = 0; | |||
| 750 | datalen += 4 + 3; | |||
| 751 | } | |||
| 752 | ||||
| 753 | PUT_ADDR(la->al_addr)temp_addr = (__uint32_t)(__builtin_constant_p(la->al_addr) ? (__uint32_t)(((__uint32_t)(la->al_addr) & 0xff) << 24 | ((__uint32_t)(la->al_addr) & 0xff00) << 8 | ((__uint32_t)(la->al_addr) & 0xff0000) >> 8 | ( (__uint32_t)(la->al_addr) & 0xff000000) >> 24) : __swap32md(la->al_addr)); *p++ = temp_addr >> 24; * p++ = (temp_addr >> 16) & 0xFF; *p++ = (temp_addr >> 8) & 0xFF; *p++ = temp_addr & 0xFF;; | |||
| 754 | datalen += 4; | |||
| 755 | (*ncount)++; | |||
| 756 | } | |||
| 757 | } | |||
| 758 | ||||
| 759 | if (datalen != 0) | |||
| 760 | send_igmp(us, them, IGMP_DVMRP0x13, DVMRP_NEIGHBORS4, htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), | |||
| 761 | datalen); | |||
| 762 | } | |||
| 763 | ||||
| 764 | /* | |||
| 765 | * Send a list of all of our neighbors to the requestor, `src'. | |||
| 766 | */ | |||
| 767 | void | |||
| 768 | accept_neighbor_request2(u_int32_t src, u_int32_t dst) | |||
| 769 | { | |||
| 770 | vifi_t vifi; | |||
| 771 | struct uvif *v; | |||
| 772 | u_char *p, *ncount; | |||
| 773 | struct listaddr *la; | |||
| 774 | int datalen; | |||
| 775 | u_int32_t us, them = src; | |||
| 776 | ||||
| 777 | /* Determine which of our addresses to use as the source of our response | |||
| 778 | * to this query. | |||
| 779 | */ | |||
| 780 | if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t )(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)( dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000 ) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24 ) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xe0000000)))) { /* query sent to a multicast group */ | |||
| 781 | int udp; /* find best interface to reply on */ | |||
| 782 | struct sockaddr_in addr; | |||
| 783 | int addrlen = sizeof(addr); | |||
| 784 | ||||
| 785 | memset(&addr, 0, sizeof addr); | |||
| 786 | addr.sin_family = AF_INET2; | |||
| 787 | addr.sin_len = sizeof addr; | |||
| 788 | addr.sin_addr.s_addr = dst; | |||
| 789 | addr.sin_port = htons(2000)(__uint16_t)(__builtin_constant_p(2000) ? (__uint16_t)(((__uint16_t )(2000) & 0xffU) << 8 | ((__uint16_t)(2000) & 0xff00U ) >> 8) : __swap16md(2000)); /* any port over 1024 will do... */ | |||
| 790 | if ((udp = socket(AF_INET2, SOCK_DGRAM2, 0)) == -1 | |||
| 791 | || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) == -1 | |||
| 792 | || getsockname(udp, (struct sockaddr *) &addr, &addrlen) == -1) { | |||
| 793 | logit(LOG_WARNING4, errno(*__errno()), "Determining local address"); | |||
| 794 | close(udp); | |||
| 795 | return; | |||
| 796 | } | |||
| 797 | close(udp); | |||
| 798 | us = addr.sin_addr.s_addr; | |||
| 799 | } else /* query sent to us alone */ | |||
| 800 | us = dst; | |||
| 801 | ||||
| 802 | p = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 803 | datalen = 0; | |||
| 804 | ||||
| 805 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { | |||
| 806 | u_short vflags = v->uv_flags; | |||
| 807 | u_char rflags = 0; | |||
| 808 | if (vflags & VIFF_TUNNEL0x1) | |||
| 809 | rflags |= DVMRP_NF_TUNNEL0x01; | |||
| 810 | if (vflags & VIFF_SRCRT0x2) | |||
| 811 | rflags |= DVMRP_NF_SRCRT0x02; | |||
| 812 | if (vflags & VIFF_DOWN0x0100) | |||
| 813 | rflags |= DVMRP_NF_DOWN0x10; | |||
| 814 | if (vflags & VIFF_DISABLED0x0200) | |||
| 815 | rflags |= DVMRP_NF_DISABLED0x20; | |||
| 816 | if (vflags & VIFF_QUERIER0x0400) | |||
| 817 | rflags |= DVMRP_NF_QUERIER0x40; | |||
| 818 | if (vflags & VIFF_LEAF0x1000) | |||
| 819 | rflags |= DVMRP_NF_LEAF0x80; | |||
| 820 | ncount = 0; | |||
| 821 | la = v->uv_neighbors; | |||
| 822 | if (la == NULL((void *)0)) { | |||
| 823 | /* | |||
| 824 | * include down & disabled interfaces and interfaces on | |||
| 825 | * leaf nets. | |||
| 826 | */ | |||
| 827 | if (rflags & DVMRP_NF_TUNNEL0x01) | |||
| 828 | rflags |= DVMRP_NF_DOWN0x10; | |||
| 829 | if (datalen > MAX_DVMRP_DATA_LEN( 576 - 60 - 8 ) - 12) { | |||
| 830 | send_igmp(us, them, IGMP_DVMRP0x13, DVMRP_NEIGHBORS26, | |||
| 831 | htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), datalen); | |||
| 832 | p = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 833 | datalen = 0; | |||
| 834 | } | |||
| 835 | *(u_int*)p = v->uv_lcl_addr; | |||
| 836 | p += 4; | |||
| 837 | *p++ = v->uv_metric; | |||
| 838 | *p++ = v->uv_threshold; | |||
| 839 | *p++ = rflags; | |||
| 840 | *p++ = 1; | |||
| 841 | *(u_int*)p = v->uv_rmt_addr; | |||
| 842 | p += 4; | |||
| 843 | datalen += 12; | |||
| 844 | } else { | |||
| 845 | for ( ; la; la = la->al_next) { | |||
| 846 | /* Make sure that there's room for this neighbor... */ | |||
| 847 | if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN( 576 - 60 - 8 )) { | |||
| 848 | send_igmp(us, them, IGMP_DVMRP0x13, DVMRP_NEIGHBORS26, | |||
| 849 | htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), datalen); | |||
| 850 | p = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 851 | datalen = 0; | |||
| 852 | ncount = 0; | |||
| 853 | } | |||
| 854 | /* Put out the header for this neighbor list... */ | |||
| 855 | if (ncount == 0) { | |||
| 856 | *(u_int*)p = v->uv_lcl_addr; | |||
| 857 | p += 4; | |||
| 858 | *p++ = v->uv_metric; | |||
| 859 | *p++ = v->uv_threshold; | |||
| 860 | *p++ = rflags; | |||
| 861 | ncount = p; | |||
| 862 | *p++ = 0; | |||
| 863 | datalen += 4 + 4; | |||
| 864 | } | |||
| 865 | *(u_int*)p = la->al_addr; | |||
| 866 | p += 4; | |||
| 867 | datalen += 4; | |||
| 868 | (*ncount)++; | |||
| 869 | } | |||
| 870 | } | |||
| 871 | } | |||
| 872 | if (datalen != 0) | |||
| 873 | send_igmp(us, them, IGMP_DVMRP0x13, DVMRP_NEIGHBORS26, htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), | |||
| 874 | datalen); | |||
| 875 | } | |||
| 876 | ||||
| 877 | void | |||
| 878 | accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen) | |||
| 879 | { | |||
| 880 | u_char *q; | |||
| 881 | int len; | |||
| 882 | int outlen = 0; | |||
| 883 | ||||
| 884 | q = (u_char *) (send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8); | |||
| 885 | ||||
| 886 | /* To be general, this must deal properly with breaking up over-sized | |||
| 887 | * packets. That implies passing a length to each function, and | |||
| 888 | * allowing each function to request to be called again. Right now, | |||
| 889 | * we're only implementing the one thing we are positive will fit into | |||
| 890 | * a single packet, so we wimp out. | |||
| 891 | */ | |||
| 892 | while (datalen > 0) { | |||
| 893 | len = 0; | |||
| 894 | switch (*p) { | |||
| 895 | case DVMRP_INFO_VERSION1: | |||
| 896 | len = info_version(q, (u_char *)send_buf + RECV_BUF_SIZE8192 - q); | |||
| 897 | break; | |||
| 898 | ||||
| 899 | case DVMRP_INFO_NEIGHBORS2: | |||
| 900 | default: | |||
| 901 | logit(LOG_INFO6, 0, "ignoring unknown info type %d", *p); | |||
| 902 | break; | |||
| 903 | } | |||
| 904 | *(q+1) = len++; | |||
| 905 | outlen += len * 4; | |||
| 906 | q += len * 4; | |||
| 907 | len = (*(p+1) + 1) * 4; | |||
| 908 | p += len; | |||
| 909 | datalen -= len; | |||
| 910 | } | |||
| 911 | ||||
| 912 | if (outlen != 0) | |||
| 913 | send_igmp(INADDR_ANY((u_int32_t)(0x00000000)), src, IGMP_DVMRP0x13, DVMRP_INFO_REPLY11, | |||
| 914 | htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t )(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t )(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | ( 1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24 ))) & 0xff000000) >> 24) : __swap32md(((8 << 8 ) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24)) )), outlen); | |||
| 915 | } | |||
| 916 | ||||
| 917 | /* | |||
| 918 | * Information response -- return version string | |||
| 919 | */ | |||
| 920 | static int | |||
| 921 | info_version(char *p, int len) | |||
| 922 | { | |||
| 923 | extern char versionstring[]; | |||
| 924 | ||||
| 925 | if (len < 5) | |||
| 926 | return (0); | |||
| 927 | *p++ = DVMRP_INFO_VERSION1; | |||
| 928 | p++; /* skip over length */ | |||
| 929 | *p++ = 0; /* zero out */ | |||
| 930 | *p++ = 0; /* reserved fields */ | |||
| 931 | strlcpy(p, versionstring, len - 4); | |||
| 932 | ||||
| 933 | len = strlen(p); | |||
| 934 | return ((len + 3) / 4); | |||
| 935 | } | |||
| 936 | ||||
| 937 | /* | |||
| 938 | * Process an incoming neighbor-list message. | |||
| 939 | */ | |||
| 940 | void | |||
| 941 | accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen, | |||
| 942 | u_int32_t level) | |||
| 943 | { | |||
| 944 | logit(LOG_INFO6, 0, "ignoring spurious DVMRP neighbor list from %s to %s", | |||
| 945 | inet_fmt(src, s1), inet_fmt(dst, s2)); | |||
| 946 | } | |||
| 947 | ||||
| 948 | ||||
| 949 | /* | |||
| 950 | * Process an incoming neighbor-list message. | |||
| 951 | */ | |||
| 952 | void | |||
| 953 | accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen, | |||
| 954 | u_int32_t level) | |||
| 955 | { | |||
| 956 | logit(LOG_INFO6, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", | |||
| 957 | inet_fmt(src, s1), inet_fmt(dst, s2)); | |||
| 958 | } | |||
| 959 | ||||
| 960 | /* | |||
| 961 | * Process an incoming info reply message. | |||
| 962 | */ | |||
| 963 | void | |||
| 964 | accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen) | |||
| 965 | { | |||
| 966 | logit(LOG_INFO6, 0, "ignoring spurious DVMRP info reply from %s to %s", | |||
| 967 | inet_fmt(src, s1), inet_fmt(dst, s2)); | |||
| 968 | } | |||
| 969 | ||||
| 970 | ||||
| 971 | /* | |||
| 972 | * Update the neighbor entry for neighbor 'addr' on vif 'vifi'. | |||
| 973 | * 'msgtype' is the type of DVMRP message received from the neighbor. | |||
| 974 | * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise. | |||
| 975 | */ | |||
| 976 | int | |||
| 977 | update_neighbor(vifi_t vifi, u_int32_t addr, int msgtype, char *p, | |||
| 978 | int datalen, u_int32_t level) | |||
| 979 | { | |||
| 980 | struct uvif *v; | |||
| 981 | struct listaddr *n; | |||
| 982 | u_int32_t genid = 0; | |||
| 983 | u_int32_t router; | |||
| 984 | u_int32_t send_tables = 0; | |||
| 985 | int do_reset = FALSE0; | |||
| 986 | int nflags; | |||
| 987 | ||||
| 988 | v = &uvifs[vifi]; | |||
| 989 | nflags = (level >> 16) & 0xff; | |||
| 990 | ||||
| 991 | /* | |||
| 992 | * Confirm that 'addr' is a valid neighbor address on vif 'vifi'. | |||
| 993 | * IT IS ASSUMED that this was preceded by a call to find_vif(), which | |||
| 994 | * checks that 'addr' is either a valid remote tunnel endpoint or a | |||
| 995 | * non-broadcast address belonging to a directly-connected subnet. | |||
| 996 | * Therefore, here we check only that 'addr' is not our own address | |||
| 997 | * (due to an impostor or erroneous loopback) or an address of the form | |||
| 998 | * {subnet,0} ("the unknown host"). These checks are not performed in | |||
| 999 | * find_vif() because those types of address are acceptable for some | |||
| 1000 | * types of IGMP message (such as group membership reports). | |||
| 1001 | */ | |||
| 1002 | if (!(v->uv_flags & VIFF_TUNNEL0x1) && | |||
| ||||
| 1003 | (addr == v->uv_lcl_addr || | |||
| 1004 | addr == v->uv_subnet )) { | |||
| 1005 | logit(LOG_WARNING4, 0, | |||
| 1006 | "received DVMRP message from 'the unknown host' or self: %s", | |||
| 1007 | inet_fmt(addr, s1)); | |||
| 1008 | return (FALSE0); | |||
| 1009 | } | |||
| 1010 | ||||
| 1011 | /* | |||
| 1012 | * Look for addr in list of neighbors. | |||
| 1013 | */ | |||
| 1014 | for (n = v->uv_neighbors; n != NULL((void *)0); n = n->al_next) { | |||
| 1015 | if (addr == n->al_addr) { | |||
| 1016 | break; | |||
| 1017 | } | |||
| 1018 | } | |||
| 1019 | ||||
| 1020 | /* | |||
| 1021 | * Found it. Reset its timer, and check for a version change | |||
| 1022 | */ | |||
| 1023 | if (n
| |||
| 1024 | n->al_timer = 0; | |||
| 1025 | ||||
| 1026 | /* | |||
| 1027 | * update the neighbors version and protocol number | |||
| 1028 | * if changed => router went down and came up, | |||
| 1029 | * so take action immediately. | |||
| 1030 | */ | |||
| 1031 | if ((n->al_pv != (level & 0xff)) || | |||
| 1032 | (n->al_mv != ((level >> 8) & 0xff))) { | |||
| 1033 | ||||
| 1034 | do_reset = TRUE1; | |||
| 1035 | logit(LOG_DEBUG7, 0, | |||
| 1036 | "version change neighbor %s [old:%d.%d, new:%d.%d]", | |||
| 1037 | inet_fmt(addr, s1), | |||
| 1038 | n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff); | |||
| 1039 | ||||
| 1040 | n->al_pv = level & 0xff; | |||
| 1041 | n->al_mv = (level >> 8) & 0xff; | |||
| 1042 | } | |||
| 1043 | } else { | |||
| 1044 | /* | |||
| 1045 | * If not found, add it to the list. If the neighbor has a lower | |||
| 1046 | * IP address than me, yield querier duties to it. | |||
| 1047 | */ | |||
| 1048 | logit(LOG_DEBUG7, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x", | |||
| 1049 | inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, | |||
| 1050 | (level >> 16) & 0xff); | |||
| 1051 | ||||
| 1052 | n = malloc(sizeof(struct listaddr)); | |||
| 1053 | if (n == NULL((void *)0)) | |||
| 1054 | logit(LOG_ERR3, 0, "ran out of memory"); /* fatal */ | |||
| 1055 | ||||
| 1056 | n->al_addr = addr; | |||
| ||||
| 1057 | n->al_pv = level & 0xff; | |||
| 1058 | n->al_mv = (level >> 8) & 0xff; | |||
| 1059 | n->al_genid = 0; | |||
| 1060 | ||||
| 1061 | time(&n->al_ctime); | |||
| 1062 | n->al_timer = 0; | |||
| 1063 | n->al_next = v->uv_neighbors; | |||
| 1064 | ||||
| 1065 | /* | |||
| 1066 | * If we thought that we had no neighbors on this vif, send a route | |||
| 1067 | * report to the vif. If this is just a new neighbor on the same | |||
| 1068 | * vif, send the route report just to the new neighbor. | |||
| 1069 | */ | |||
| 1070 | if (v->uv_neighbors == NULL((void *)0)) { | |||
| 1071 | send_tables = (v->uv_flags & VIFF_TUNNEL0x1) ? addr : dvmrp_group; | |||
| 1072 | vifs_with_neighbors++; | |||
| 1073 | } else { | |||
| 1074 | send_tables = addr; | |||
| 1075 | } | |||
| 1076 | ||||
| 1077 | v->uv_neighbors = n; | |||
| 1078 | ||||
| 1079 | if (!(v->uv_flags & VIFF_TUNNEL0x1) && | |||
| 1080 | ntohl(addr)(__uint32_t)(__builtin_constant_p(addr) ? (__uint32_t)(((__uint32_t )(addr) & 0xff) << 24 | ((__uint32_t)(addr) & 0xff00 ) << 8 | ((__uint32_t)(addr) & 0xff0000) >> 8 | ((__uint32_t)(addr) & 0xff000000) >> 24) : __swap32md (addr)) < ntohl(v->uv_lcl_addr)(__uint32_t)(__builtin_constant_p(v->uv_lcl_addr) ? (__uint32_t )(((__uint32_t)(v->uv_lcl_addr) & 0xff) << 24 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff00) << 8 | (( __uint32_t)(v->uv_lcl_addr) & 0xff0000) >> 8 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff000000) >> 24 ) : __swap32md(v->uv_lcl_addr))) | |||
| 1081 | v->uv_flags &= ~VIFF_QUERIER0x0400; | |||
| 1082 | } | |||
| 1083 | ||||
| 1084 | /* | |||
| 1085 | * Check if the router gen-ids are the same. | |||
| 1086 | * Need to reset the prune state of the router if not. | |||
| 1087 | * Also check for one-way interfaces by seeing if we are in our | |||
| 1088 | * neighbor's list of known routers. | |||
| 1089 | */ | |||
| 1090 | if (msgtype == DVMRP_PROBE1) { | |||
| 1091 | ||||
| 1092 | /* Check genid neighbor flag. Also check version number; 3.3 and | |||
| 1093 | * 3.4 didn't set this flag. */ | |||
| 1094 | if ((((level >> 16) & 0xff) & NF_GENID0x04) || | |||
| 1095 | (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) { | |||
| 1096 | ||||
| 1097 | int i; | |||
| 1098 | ||||
| 1099 | if (datalen < 4) { | |||
| 1100 | logit(LOG_WARNING4, 0, | |||
| 1101 | "received truncated probe message from %s (len %d)", | |||
| 1102 | inet_fmt(addr, s1), datalen); | |||
| 1103 | return (FALSE0); | |||
| 1104 | } | |||
| 1105 | ||||
| 1106 | for (i = 0; i < 4; i++) | |||
| 1107 | ((char *)&genid)[i] = *p++; | |||
| 1108 | datalen -= 4; | |||
| 1109 | ||||
| 1110 | if (n->al_genid == 0) | |||
| 1111 | n->al_genid = genid; | |||
| 1112 | else if (n->al_genid != genid) { | |||
| 1113 | logit(LOG_DEBUG7, 0, | |||
| 1114 | "new genid neigbor %s on vif %d [old:%x, new:%x]", | |||
| 1115 | inet_fmt(addr, s1), vifi, n->al_genid, genid); | |||
| 1116 | ||||
| 1117 | n->al_genid = genid; | |||
| 1118 | do_reset = TRUE1; | |||
| 1119 | } | |||
| 1120 | ||||
| 1121 | /* | |||
| 1122 | * loop through router list and check for one-way ifs. | |||
| 1123 | */ | |||
| 1124 | ||||
| 1125 | v->uv_flags |= VIFF_ONEWAY0x0800; | |||
| 1126 | ||||
| 1127 | while (datalen > 0) { | |||
| 1128 | if (datalen < 4) { | |||
| 1129 | logit(LOG_WARNING4, 0, | |||
| 1130 | "received truncated probe message from %s (len %d)", | |||
| 1131 | inet_fmt(addr, s1), datalen); | |||
| 1132 | return (FALSE0); | |||
| 1133 | } | |||
| 1134 | for (i = 0; i < 4; i++) | |||
| 1135 | ((char *)&router)[i] = *p++; | |||
| 1136 | datalen -= 4; | |||
| 1137 | if (router == v->uv_lcl_addr) { | |||
| 1138 | v->uv_flags &= ~VIFF_ONEWAY0x0800; | |||
| 1139 | break; | |||
| 1140 | } | |||
| 1141 | } | |||
| 1142 | } | |||
| 1143 | } | |||
| 1144 | if (n->al_flags != nflags) { | |||
| 1145 | n->al_flags = nflags; | |||
| 1146 | ||||
| 1147 | if (n->al_flags & NF_LEAF0x01) { | |||
| 1148 | /*XXX If we have non-leaf neighbors then we know we shouldn't | |||
| 1149 | * mark this vif as a leaf. For now we just count on other | |||
| 1150 | * probes and/or reports resetting the timer. */ | |||
| 1151 | if (!v->uv_leaf_timer) | |||
| 1152 | v->uv_leaf_timer = LEAF_CONFIRMATION_TIME200; | |||
| 1153 | } else { | |||
| 1154 | /* If we get a leaf to non-leaf transition, we *must* update | |||
| 1155 | * the routing table. */ | |||
| 1156 | if (v->uv_flags & VIFF_LEAF0x1000 && send_tables == 0) | |||
| 1157 | send_tables = addr; | |||
| 1158 | v->uv_flags &= ~VIFF_LEAF0x1000; | |||
| 1159 | v->uv_leaf_timer = 0; | |||
| 1160 | } | |||
| 1161 | } | |||
| 1162 | if (do_reset) { | |||
| 1163 | reset_neighbor_state(vifi, addr); | |||
| 1164 | if (!send_tables) | |||
| 1165 | send_tables = addr; | |||
| 1166 | } | |||
| 1167 | if (send_tables) | |||
| 1168 | report(ALL_ROUTES0, vifi, send_tables); | |||
| 1169 | ||||
| 1170 | return (TRUE1); | |||
| 1171 | } | |||
| 1172 | ||||
| 1173 | ||||
| 1174 | /* | |||
| 1175 | * On every timer interrupt, advance the timer in each neighbor and | |||
| 1176 | * group entry on every vif. | |||
| 1177 | */ | |||
| 1178 | void | |||
| 1179 | age_vifs(void) | |||
| 1180 | { | |||
| 1181 | vifi_t vifi; | |||
| 1182 | struct uvif *v; | |||
| 1183 | struct listaddr *a, *prev_a, *n; | |||
| 1184 | u_int32_t addr; | |||
| 1185 | ||||
| 1186 | for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { | |||
| 1187 | if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL5 == 0)) { | |||
| 1188 | v->uv_flags |= VIFF_LEAF0x1000; | |||
| 1189 | } | |||
| 1190 | ||||
| 1191 | for (prev_a = (struct listaddr *)&(v->uv_neighbors), | |||
| 1192 | a = v->uv_neighbors; | |||
| 1193 | a != NULL((void *)0); | |||
| 1194 | prev_a = a, a = a->al_next) { | |||
| 1195 | ||||
| 1196 | if ((a->al_timer += TIMER_INTERVAL5) < NEIGHBOR_EXPIRE_TIME140) | |||
| 1197 | continue; | |||
| 1198 | ||||
| 1199 | /* | |||
| 1200 | * Neighbor has expired; delete it from the neighbor list, | |||
| 1201 | * delete it from the 'dominants' and 'subordinates arrays of | |||
| 1202 | * any route entries and assume querier duties unless there is | |||
| 1203 | * another neighbor with a lower IP address than mine. | |||
| 1204 | */ | |||
| 1205 | addr = a->al_addr; | |||
| 1206 | prev_a->al_next = a->al_next; | |||
| 1207 | free((char *)a); | |||
| 1208 | a = prev_a; | |||
| 1209 | ||||
| 1210 | delete_neighbor_from_routes(addr, vifi); | |||
| 1211 | ||||
| 1212 | if (v->uv_neighbors == NULL((void *)0)) | |||
| 1213 | vifs_with_neighbors--; | |||
| 1214 | ||||
| 1215 | v->uv_leaf_timer = LEAF_CONFIRMATION_TIME200; | |||
| 1216 | ||||
| 1217 | if (!(v->uv_flags & VIFF_TUNNEL0x1)) { | |||
| 1218 | v->uv_flags |= VIFF_QUERIER0x0400; | |||
| 1219 | for (n = v->uv_neighbors; n != NULL((void *)0); n = n->al_next) { | |||
| 1220 | if (ntohl(n->al_addr)(__uint32_t)(__builtin_constant_p(n->al_addr) ? (__uint32_t )(((__uint32_t)(n->al_addr) & 0xff) << 24 | ((__uint32_t )(n->al_addr) & 0xff00) << 8 | ((__uint32_t)(n-> al_addr) & 0xff0000) >> 8 | ((__uint32_t)(n->al_addr ) & 0xff000000) >> 24) : __swap32md(n->al_addr)) < ntohl(v->uv_lcl_addr)(__uint32_t)(__builtin_constant_p(v->uv_lcl_addr) ? (__uint32_t )(((__uint32_t)(v->uv_lcl_addr) & 0xff) << 24 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff00) << 8 | (( __uint32_t)(v->uv_lcl_addr) & 0xff0000) >> 8 | ( (__uint32_t)(v->uv_lcl_addr) & 0xff000000) >> 24 ) : __swap32md(v->uv_lcl_addr))) { | |||
| 1221 | v->uv_flags &= ~VIFF_QUERIER0x0400; | |||
| 1222 | } | |||
| 1223 | if (!(n->al_flags & NF_LEAF0x01)) { | |||
| 1224 | v->uv_leaf_timer = 0; | |||
| 1225 | } | |||
| 1226 | } | |||
| 1227 | } | |||
| 1228 | } | |||
| 1229 | } | |||
| 1230 | } | |||
| 1231 | ||||
| 1232 | /* | |||
| 1233 | * Returns the neighbor info struct for a given neighbor | |||
| 1234 | */ | |||
| 1235 | struct listaddr * | |||
| 1236 | neighbor_info(vifi_t vifi, u_int32_t addr) | |||
| 1237 | { | |||
| 1238 | struct listaddr *u; | |||
| 1239 | ||||
| 1240 | for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next) | |||
| 1241 | if (u->al_addr == addr) | |||
| 1242 | return u; | |||
| 1243 | ||||
| 1244 | return NULL((void *)0); | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | /* | |||
| 1248 | * Print the contents of the uvifs array on file 'fp'. | |||
| 1249 | */ | |||
| 1250 | void | |||
| 1251 | dump_vifs(FILE *fp) | |||
| 1252 | { | |||
| 1253 | vifi_t vifi; | |||
| 1254 | struct uvif *v; | |||
| 1255 | struct listaddr *a; | |||
| 1256 | struct phaddr *p; | |||
| 1257 | struct sioc_vif_req v_req; | |||
| 1258 | ||||
| 1259 | fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors); | |||
| 1260 | ||||
| 1261 | if (vifs_with_neighbors == 1) | |||
| 1262 | fprintf(fp,"[This host is a leaf]\n\n"); | |||
| 1263 | ||||
| 1264 | fprintf(fp, | |||
| 1265 | "\nVirtual Interface Table\n%s", | |||
| 1266 | "Vif Name Local-Address "); | |||
| 1267 | fprintf(fp, | |||
| 1268 | "M Thr Rate Flags\n"); | |||
| 1269 | ||||
| 1270 | for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { | |||
| 1271 | ||||
| 1272 | fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ", | |||
| 1273 | vifi, | |||
| 1274 | v->uv_name, | |||
| 1275 | inet_fmt(v->uv_lcl_addr, s1), | |||
| 1276 | (v->uv_flags & VIFF_TUNNEL0x1) ? | |||
| 1277 | "tunnel": | |||
| 1278 | "subnet", | |||
| 1279 | (v->uv_flags & VIFF_TUNNEL0x1) ? | |||
| 1280 | inet_fmt(v->uv_rmt_addr, s2) : | |||
| 1281 | inet_fmts(v->uv_subnet, v->uv_subnetmask, s3), | |||
| 1282 | v->uv_metric, | |||
| 1283 | v->uv_threshold, | |||
| 1284 | v->uv_rate_limit); | |||
| 1285 | ||||
| 1286 | if (v->uv_flags & VIFF_ONEWAY0x0800) fprintf(fp, " one-way"); | |||
| 1287 | if (v->uv_flags & VIFF_DOWN0x0100) fprintf(fp, " down"); | |||
| 1288 | if (v->uv_flags & VIFF_DISABLED0x0200) fprintf(fp, " disabled"); | |||
| 1289 | if (v->uv_flags & VIFF_QUERIER0x0400) fprintf(fp, " querier"); | |||
| 1290 | if (v->uv_flags & VIFF_SRCRT0x2) fprintf(fp, " src-rt"); | |||
| 1291 | if (v->uv_flags & VIFF_LEAF0x1000) fprintf(fp, " leaf"); | |||
| 1292 | if (v->uv_flags & VIFF_IGMPV10x2000) fprintf(fp, " IGMPv1"); | |||
| 1293 | fprintf(fp, "\n"); | |||
| 1294 | ||||
| 1295 | if (v->uv_addrs != NULL((void *)0)) { | |||
| 1296 | fprintf(fp, " alternate subnets: %s\n", | |||
| 1297 | inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1)); | |||
| 1298 | for (p = v->uv_addrs->pa_next; p; p = p->pa_next) { | |||
| 1299 | fprintf(fp, " %s\n", | |||
| 1300 | inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); | |||
| 1301 | } | |||
| 1302 | } | |||
| 1303 | ||||
| 1304 | if (v->uv_neighbors != NULL((void *)0)) { | |||
| 1305 | fprintf(fp, " peers: %s (%d.%d) (0x%x)\n", | |||
| 1306 | inet_fmt(v->uv_neighbors->al_addr, s1), | |||
| 1307 | v->uv_neighbors->al_pv, v->uv_neighbors->al_mv, | |||
| 1308 | v->uv_neighbors->al_flags); | |||
| 1309 | for (a = v->uv_neighbors->al_next; a != NULL((void *)0); a = a->al_next) { | |||
| 1310 | fprintf(fp, " %s (%d.%d) (0x%x)\n", | |||
| 1311 | inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, | |||
| 1312 | a->al_flags); | |||
| 1313 | } | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | if (v->uv_groups != NULL((void *)0)) { | |||
| 1317 | fprintf(fp, " groups: %-15s\n", | |||
| 1318 | inet_fmt(v->uv_groups->al_addr, s1)); | |||
| 1319 | for (a = v->uv_groups->al_next; a != NULL((void *)0); a = a->al_next) { | |||
| 1320 | fprintf(fp, " %-15s\n", | |||
| 1321 | inet_fmt(a->al_addr, s1)); | |||
| 1322 | } | |||
| 1323 | } | |||
| 1324 | if (v->uv_acl != NULL((void *)0)) { | |||
| 1325 | struct vif_acl *acl; | |||
| 1326 | ||||
| 1327 | fprintf(fp, " boundaries: %-18s\n", | |||
| 1328 | inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1)); | |||
| 1329 | for (acl = v->uv_acl->acl_next; acl != NULL((void *)0); acl = acl->acl_next) { | |||
| 1330 | fprintf(fp, " : %-18s\n", | |||
| 1331 | inet_fmts(acl->acl_addr, acl->acl_mask, s1)); | |||
| 1332 | } | |||
| 1333 | } | |||
| 1334 | v_req.vifi = vifi; | |||
| 1335 | if (ioctl(udp_socket, SIOCGETVIFCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct sioc_vif_req) & 0x1fff) << 16) | ((('u')) << 8) | ((51))), (char *)&v_req) == -1) { | |||
| 1336 | logit(LOG_WARNING4, 0, | |||
| 1337 | "SIOCGETVIFCNT fails"); | |||
| 1338 | } | |||
| 1339 | else { | |||
| 1340 | fprintf(fp, " pkts in : %ld\n", | |||
| 1341 | v_req.icount); | |||
| 1342 | fprintf(fp, " pkts out: %ld\n", | |||
| 1343 | v_req.ocount); | |||
| 1344 | } | |||
| 1345 | fprintf(fp, "\n"); | |||
| 1346 | } | |||
| 1347 | fprintf(fp, "\n"); | |||
| 1348 | } | |||
| 1349 | ||||
| 1350 | /* | |||
| 1351 | * Time out record of a group membership on a vif | |||
| 1352 | */ | |||
| 1353 | static void | |||
| 1354 | DelVif(void *arg) | |||
| 1355 | { | |||
| 1356 | cbk_t *cbk = (cbk_t *)arg; | |||
| 1357 | vifi_t vifi = cbk->vifi; | |||
| 1358 | struct uvif *v = &uvifs[vifi]; | |||
| 1359 | struct listaddr *a, **anp, *g = cbk->g; | |||
| 1360 | ||||
| 1361 | /* | |||
| 1362 | * Group has expired | |||
| 1363 | * delete all kernel cache entries with this group | |||
| 1364 | */ | |||
| 1365 | if (g->al_query) | |||
| 1366 | DeleteTimer(g->al_query); | |||
| 1367 | ||||
| 1368 | delete_lclgrp(vifi, g->al_addr); | |||
| 1369 | ||||
| 1370 | anp = &(v->uv_groups); | |||
| 1371 | while ((a = *anp) != NULL((void *)0)) { | |||
| 1372 | if (a == g) { | |||
| 1373 | *anp = a->al_next; | |||
| 1374 | free((char *)a); | |||
| 1375 | } else { | |||
| 1376 | anp = &a->al_next; | |||
| 1377 | } | |||
| 1378 | } | |||
| 1379 | ||||
| 1380 | free(cbk); | |||
| 1381 | } | |||
| 1382 | ||||
| 1383 | /* | |||
| 1384 | * Set a timer to delete the record of a group membership on a vif. | |||
| 1385 | */ | |||
| 1386 | static int | |||
| 1387 | SetTimer(int vifi, struct listaddr *g) | |||
| 1388 | { | |||
| 1389 | cbk_t *cbk; | |||
| 1390 | ||||
| 1391 | cbk = malloc(sizeof(cbk_t)); | |||
| 1392 | cbk->g = g; | |||
| 1393 | cbk->vifi = vifi; | |||
| 1394 | return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk); | |||
| 1395 | } | |||
| 1396 | ||||
| 1397 | /* | |||
| 1398 | * Delete a timer that was set above. | |||
| 1399 | */ | |||
| 1400 | static int | |||
| 1401 | DeleteTimer(int id) | |||
| 1402 | { | |||
| 1403 | timer_clearTimer(id); | |||
| 1404 | return 0; | |||
| 1405 | } | |||
| 1406 | ||||
| 1407 | /* | |||
| 1408 | * Send a group-specific query. | |||
| 1409 | */ | |||
| 1410 | static void | |||
| 1411 | SendQuery(void *arg) | |||
| 1412 | { | |||
| 1413 | cbk_t *cbk = (cbk_t *)arg; | |||
| 1414 | struct uvif *v = &uvifs[cbk->vifi]; | |||
| 1415 | ||||
| 1416 | send_igmp(v->uv_lcl_addr, cbk->g->al_addr, | |||
| 1417 | IGMP_HOST_MEMBERSHIP_QUERY0x11, | |||
| 1418 | cbk->q_time, cbk->g->al_addr, 0); | |||
| 1419 | cbk->g->al_query = 0; | |||
| 1420 | free(cbk); | |||
| 1421 | } | |||
| 1422 | ||||
| 1423 | /* | |||
| 1424 | * Set a timer to send a group-specific query. | |||
| 1425 | */ | |||
| 1426 | static int | |||
| 1427 | SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time) | |||
| 1428 | { | |||
| 1429 | cbk_t *cbk; | |||
| 1430 | ||||
| 1431 | cbk = malloc(sizeof(cbk_t)); | |||
| 1432 | cbk->g = g; | |||
| 1433 | cbk->q_time = q_time; | |||
| 1434 | cbk->vifi = vifi; | |||
| 1435 | return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk); | |||
| 1436 | } |