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