1 1.25 christos /* $NetBSD: output.c,v 1.25 2009/10/26 02:53:15 christos Exp $ */ 2 1.8 cgd 3 1.1 cgd /* 4 1.5 mycroft * Copyright (c) 1983, 1988, 1993 5 1.5 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.1 cgd * 3. All advertising materials mentioning features or use of this software 16 1.16 christos * must display the following acknowledgment: 17 1.1 cgd * This product includes software developed by the University of 18 1.1 cgd * California, Berkeley and its contributors. 19 1.1 cgd * 4. Neither the name of the University nor the names of its contributors 20 1.1 cgd * may be used to endorse or promote products derived from this software 21 1.1 cgd * without specific prior written permission. 22 1.1 cgd * 23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 cgd * SUCH DAMAGE. 34 1.1 cgd */ 35 1.1 cgd 36 1.20 christos #include "defs.h" 37 1.20 christos 38 1.20 christos #ifdef __NetBSD__ 39 1.25 christos __RCSID("$NetBSD: output.c,v 1.25 2009/10/26 02:53:15 christos Exp $"); 40 1.20 christos #elif defined(__FreeBSD__) 41 1.20 christos __RCSID("$FreeBSD$"); 42 1.20 christos #else 43 1.22 christos __RCSID("Revision: 2.27 "); 44 1.22 christos #ident "Revision: 2.27 " 45 1.8 cgd #endif 46 1.1 cgd 47 1.10 thorpej 48 1.17 christos u_int update_seqno; 49 1.10 thorpej 50 1.10 thorpej 51 1.10 thorpej /* walk the tree of routes with this for output 52 1.10 thorpej */ 53 1.10 thorpej struct { 54 1.10 thorpej struct sockaddr_in to; 55 1.10 thorpej naddr to_mask; 56 1.10 thorpej naddr to_net; 57 1.10 thorpej naddr to_std_mask; 58 1.10 thorpej naddr to_std_net; 59 1.10 thorpej struct interface *ifp; /* usually output interface */ 60 1.12 christos struct auth *a; 61 1.10 thorpej char metric; /* adjust metrics by interface */ 62 1.10 thorpej int npackets; 63 1.11 christos int gen_limit; 64 1.10 thorpej u_int state; 65 1.10 thorpej #define WS_ST_FLASH 0x001 /* send only changed routes */ 66 1.12 christos #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ 67 1.12 christos #define WS_ST_AG 0x004 /* ok to aggregate subnets */ 68 1.12 christos #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ 69 1.15 thorpej #define WS_ST_QUERY 0x010 /* responding to a query */ 70 1.15 thorpej #define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ 71 1.15 thorpej #define WS_ST_DEFAULT 0x040 /* faking a default */ 72 1.10 thorpej } ws; 73 1.10 thorpej 74 1.10 thorpej /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ 75 1.12 christos struct ws_buf v12buf; 76 1.10 thorpej union pkt_buf ripv12_buf; 77 1.10 thorpej 78 1.10 thorpej /* Another for only RIPv2 listeners */ 79 1.12 christos struct ws_buf v2buf; 80 1.10 thorpej union pkt_buf rip_v2_buf; 81 1.10 thorpej 82 1.10 thorpej 83 1.10 thorpej 84 1.12 christos void 85 1.12 christos bufinit(void) 86 1.12 christos { 87 1.12 christos ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; 88 1.12 christos v12buf.buf = &ripv12_buf.rip; 89 1.12 christos v12buf.base = &v12buf.buf->rip_nets[0]; 90 1.12 christos 91 1.12 christos rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; 92 1.12 christos rip_v2_buf.rip.rip_vers = RIPv2; 93 1.12 christos v2buf.buf = &rip_v2_buf.rip; 94 1.12 christos v2buf.base = &v2buf.buf->rip_nets[0]; 95 1.12 christos } 96 1.12 christos 97 1.12 christos 98 1.10 thorpej /* Send the contents of the global buffer via the non-multicast socket 99 1.10 thorpej */ 100 1.10 thorpej int /* <0 on failure */ 101 1.10 thorpej output(enum output_type type, 102 1.10 thorpej struct sockaddr_in *dst, /* send to here */ 103 1.10 thorpej struct interface *ifp, 104 1.10 thorpej struct rip *buf, 105 1.10 thorpej int size) /* this many bytes */ 106 1.10 thorpej { 107 1.21 lukem struct sockaddr_in osin; 108 1.10 thorpej int flags; 109 1.17 christos const char *msg; 110 1.10 thorpej int res; 111 1.10 thorpej naddr tgt_mcast; 112 1.10 thorpej int soc; 113 1.10 thorpej int serrno; 114 1.10 thorpej 115 1.21 lukem osin = *dst; 116 1.21 lukem if (osin.sin_port == 0) 117 1.21 lukem osin.sin_port = htons(RIP_PORT); 118 1.10 thorpej #ifdef _HAVE_SIN_LEN 119 1.21 lukem if (osin.sin_len == 0) 120 1.21 lukem osin.sin_len = sizeof(osin); 121 1.10 thorpej #endif 122 1.10 thorpej 123 1.10 thorpej soc = rip_sock; 124 1.10 thorpej flags = 0; 125 1.10 thorpej 126 1.10 thorpej switch (type) { 127 1.10 thorpej case OUT_QUERY: 128 1.10 thorpej msg = "Answer Query"; 129 1.10 thorpej if (soc < 0) 130 1.10 thorpej soc = ifp->int_rip_sock; 131 1.10 thorpej break; 132 1.10 thorpej case OUT_UNICAST: 133 1.10 thorpej msg = "Send"; 134 1.10 thorpej if (soc < 0) 135 1.10 thorpej soc = ifp->int_rip_sock; 136 1.10 thorpej flags = MSG_DONTROUTE; 137 1.10 thorpej break; 138 1.10 thorpej case OUT_BROADCAST: 139 1.10 thorpej if (ifp->int_if_flags & IFF_POINTOPOINT) { 140 1.10 thorpej msg = "Send"; 141 1.10 thorpej } else { 142 1.10 thorpej msg = "Send bcast"; 143 1.10 thorpej } 144 1.10 thorpej flags = MSG_DONTROUTE; 145 1.10 thorpej break; 146 1.10 thorpej case OUT_MULTICAST: 147 1.25 christos if ((ifp->int_if_flags & IFF_POINTOPOINT) 148 1.25 christos && !(ifp->int_if_flags & IFF_MULTICAST)) { 149 1.10 thorpej msg = "Send pt-to-pt"; 150 1.10 thorpej } else if (ifp->int_state & IS_DUP) { 151 1.10 thorpej trace_act("abort multicast output via %s" 152 1.12 christos " with duplicate address", 153 1.10 thorpej ifp->int_name); 154 1.10 thorpej return 0; 155 1.10 thorpej } else { 156 1.10 thorpej msg = "Send mcast"; 157 1.10 thorpej if (rip_sock_mcast != ifp) { 158 1.19 itojun #ifdef MCAST_IFINDEX 159 1.19 itojun /* specify ifindex */ 160 1.19 itojun tgt_mcast = htonl(ifp->int_index); 161 1.19 itojun #else 162 1.10 thorpej #ifdef MCAST_PPP_BUG 163 1.16 christos /* Do not specify the primary interface 164 1.10 thorpej * explicitly if we have the multicast 165 1.10 thorpej * point-to-point kernel bug, since the 166 1.10 thorpej * kernel will do the wrong thing if the 167 1.10 thorpej * local address of a point-to-point link 168 1.10 thorpej * is the same as the address of an ordinary 169 1.10 thorpej * interface. 170 1.10 thorpej */ 171 1.10 thorpej if (ifp->int_addr == myaddr) { 172 1.10 thorpej tgt_mcast = 0; 173 1.10 thorpej } else 174 1.10 thorpej #endif 175 1.10 thorpej tgt_mcast = ifp->int_addr; 176 1.19 itojun #endif 177 1.10 thorpej if (0 > setsockopt(rip_sock, 178 1.10 thorpej IPPROTO_IP, IP_MULTICAST_IF, 179 1.10 thorpej &tgt_mcast, 180 1.10 thorpej sizeof(tgt_mcast))) { 181 1.10 thorpej serrno = errno; 182 1.10 thorpej LOGERR("setsockopt(rip_sock," 183 1.10 thorpej "IP_MULTICAST_IF)"); 184 1.10 thorpej errno = serrno; 185 1.10 thorpej ifp = 0; 186 1.10 thorpej return -1; 187 1.10 thorpej } 188 1.10 thorpej rip_sock_mcast = ifp; 189 1.10 thorpej } 190 1.21 lukem osin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 191 1.10 thorpej } 192 1.12 christos break; 193 1.11 christos 194 1.11 christos case NO_OUT_MULTICAST: 195 1.11 christos case NO_OUT_RIPV2: 196 1.12 christos default: 197 1.12 christos #ifdef DEBUG 198 1.12 christos abort(); 199 1.12 christos #endif 200 1.12 christos return -1; 201 1.10 thorpej } 202 1.10 thorpej 203 1.21 lukem trace_rip(msg, "to", &osin, ifp, buf, size); 204 1.10 thorpej 205 1.10 thorpej res = sendto(soc, buf, size, flags, 206 1.21 lukem (struct sockaddr *)&osin, sizeof(osin)); 207 1.10 thorpej if (res < 0 208 1.10 thorpej && (ifp == 0 || !(ifp->int_state & IS_BROKE))) { 209 1.10 thorpej serrno = errno; 210 1.10 thorpej msglog("%s sendto(%s%s%s.%d): %s", msg, 211 1.10 thorpej ifp != 0 ? ifp->int_name : "", 212 1.10 thorpej ifp != 0 ? ", " : "", 213 1.21 lukem inet_ntoa(osin.sin_addr), 214 1.21 lukem ntohs(osin.sin_port), 215 1.10 thorpej strerror(errno)); 216 1.10 thorpej errno = serrno; 217 1.10 thorpej } 218 1.10 thorpej 219 1.10 thorpej return res; 220 1.10 thorpej } 221 1.10 thorpej 222 1.10 thorpej 223 1.12 christos /* Find the first key for a packet to send. 224 1.16 christos * Try for a key that is eligible and has not expired, but settle for 225 1.12 christos * the last key if they have all expired. 226 1.12 christos * If no key is ready yet, give up. 227 1.10 thorpej */ 228 1.12 christos struct auth * 229 1.12 christos find_auth(struct interface *ifp) 230 1.12 christos { 231 1.12 christos struct auth *ap, *res; 232 1.12 christos int i; 233 1.12 christos 234 1.12 christos 235 1.12 christos if (ifp == 0) 236 1.12 christos return 0; 237 1.12 christos 238 1.12 christos res = 0; 239 1.12 christos ap = ifp->int_auth; 240 1.12 christos for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { 241 1.12 christos /* stop looking after the last key */ 242 1.12 christos if (ap->type == RIP_AUTH_NONE) 243 1.12 christos break; 244 1.12 christos 245 1.12 christos /* ignore keys that are not ready yet */ 246 1.12 christos if ((u_long)ap->start > (u_long)clk.tv_sec) 247 1.12 christos continue; 248 1.12 christos 249 1.12 christos if ((u_long)ap->end < (u_long)clk.tv_sec) { 250 1.12 christos /* note best expired password as a fall-back */ 251 1.12 christos if (res == 0 || (u_long)ap->end > (u_long)res->end) 252 1.12 christos res = ap; 253 1.12 christos continue; 254 1.12 christos } 255 1.12 christos 256 1.12 christos /* note key with the best future */ 257 1.12 christos if (res == 0 || (u_long)res->end < (u_long)ap->end) 258 1.12 christos res = ap; 259 1.12 christos } 260 1.12 christos return res; 261 1.12 christos } 262 1.12 christos 263 1.12 christos 264 1.12 christos void 265 1.12 christos clr_ws_buf(struct ws_buf *wb, 266 1.12 christos struct auth *ap) 267 1.10 thorpej { 268 1.12 christos struct netauth *na; 269 1.12 christos 270 1.12 christos wb->lim = wb->base + NETS_LEN; 271 1.12 christos wb->n = wb->base; 272 1.13 lukem memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); 273 1.12 christos 274 1.16 christos /* (start to) install authentication if appropriate 275 1.12 christos */ 276 1.12 christos if (ap == 0) 277 1.12 christos return; 278 1.16 christos 279 1.12 christos na = (struct netauth*)wb->n; 280 1.12 christos if (ap->type == RIP_AUTH_PW) { 281 1.12 christos na->a_family = RIP_AF_AUTH; 282 1.12 christos na->a_type = RIP_AUTH_PW; 283 1.16 christos memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); 284 1.12 christos wb->n++; 285 1.12 christos 286 1.12 christos } else if (ap->type == RIP_AUTH_MD5) { 287 1.12 christos na->a_family = RIP_AF_AUTH; 288 1.12 christos na->a_type = RIP_AUTH_MD5; 289 1.12 christos na->au.a_md5.md5_keyid = ap->keyid; 290 1.22 christos na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; 291 1.16 christos na->au.a_md5.md5_seqno = htonl(clk.tv_sec); 292 1.12 christos wb->n++; 293 1.12 christos wb->lim--; /* make room for trailer */ 294 1.10 thorpej } 295 1.10 thorpej } 296 1.10 thorpej 297 1.10 thorpej 298 1.12 christos void 299 1.12 christos end_md5_auth(struct ws_buf *wb, 300 1.12 christos struct auth *ap) 301 1.12 christos { 302 1.12 christos struct netauth *na, *na2; 303 1.12 christos MD5_CTX md5_ctx; 304 1.16 christos int len; 305 1.12 christos 306 1.12 christos 307 1.12 christos na = (struct netauth*)wb->base; 308 1.12 christos na2 = (struct netauth*)wb->n; 309 1.16 christos len = (char *)na2-(char *)wb->buf; 310 1.12 christos na2->a_family = RIP_AF_AUTH; 311 1.16 christos na2->a_type = htons(1); 312 1.16 christos na->au.a_md5.md5_pkt_len = htons(len); 313 1.12 christos MD5Init(&md5_ctx); 314 1.22 christos MD5Update(&md5_ctx, (u_char *)wb->buf, len + RIP_AUTH_MD5_HASH_XTRA); 315 1.22 christos MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN); 316 1.12 christos MD5Final(na2->au.au_pw, &md5_ctx); 317 1.12 christos wb->n++; 318 1.12 christos } 319 1.12 christos 320 1.12 christos 321 1.10 thorpej /* Send the buffer 322 1.10 thorpej */ 323 1.10 thorpej static void 324 1.10 thorpej supply_write(struct ws_buf *wb) 325 1.10 thorpej { 326 1.10 thorpej /* Output multicast only if legal. 327 1.16 christos * If we would multicast and it would be illegal, then discard the 328 1.10 thorpej * packet. 329 1.10 thorpej */ 330 1.10 thorpej switch (wb->type) { 331 1.10 thorpej case NO_OUT_MULTICAST: 332 1.12 christos trace_pkt("skip multicast to %s because impossible", 333 1.10 thorpej naddr_ntoa(ws.to.sin_addr.s_addr)); 334 1.10 thorpej break; 335 1.10 thorpej case NO_OUT_RIPV2: 336 1.10 thorpej break; 337 1.10 thorpej default: 338 1.12 christos if (ws.a != 0 && ws.a->type == RIP_AUTH_MD5) 339 1.12 christos end_md5_auth(wb,ws.a); 340 1.10 thorpej if (output(wb->type, &ws.to, ws.ifp, wb->buf, 341 1.10 thorpej ((char *)wb->n - (char*)wb->buf)) < 0 342 1.10 thorpej && ws.ifp != 0) 343 1.10 thorpej if_sick(ws.ifp); 344 1.10 thorpej ws.npackets++; 345 1.10 thorpej break; 346 1.10 thorpej } 347 1.10 thorpej 348 1.12 christos clr_ws_buf(wb,ws.a); 349 1.10 thorpej } 350 1.10 thorpej 351 1.10 thorpej 352 1.10 thorpej /* put an entry into the packet 353 1.1 cgd */ 354 1.10 thorpej static void 355 1.10 thorpej supply_out(struct ag_info *ag) 356 1.10 thorpej { 357 1.10 thorpej int i; 358 1.12 christos naddr mask, v1_mask, dst_h, ddst_h = 0; 359 1.10 thorpej struct ws_buf *wb; 360 1.10 thorpej 361 1.10 thorpej 362 1.10 thorpej /* Skip this route if doing a flash update and it and the routes 363 1.10 thorpej * it aggregates have not changed recently. 364 1.10 thorpej */ 365 1.10 thorpej if (ag->ag_seqno < update_seqno 366 1.10 thorpej && (ws.state & WS_ST_FLASH)) 367 1.10 thorpej return; 368 1.10 thorpej 369 1.10 thorpej dst_h = ag->ag_dst_h; 370 1.10 thorpej mask = ag->ag_mask; 371 1.10 thorpej v1_mask = ripv1_mask_host(htonl(dst_h), 372 1.10 thorpej (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0); 373 1.10 thorpej i = 0; 374 1.10 thorpej 375 1.10 thorpej /* If we are sending RIPv2 packets that cannot (or must not) be 376 1.10 thorpej * heard by RIPv1 listeners, do not worry about sub- or supernets. 377 1.10 thorpej * Subnets (from other networks) can only be sent via multicast. 378 1.10 thorpej * A pair of subnet routes might have been promoted so that they 379 1.10 thorpej * are legal to send by RIPv1. 380 1.12 christos * If RIPv1 is off, use the multicast buffer. 381 1.10 thorpej */ 382 1.12 christos if ((ws.state & WS_ST_RIP2_ALL) 383 1.10 thorpej || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { 384 1.10 thorpej /* use the RIPv2-only buffer */ 385 1.12 christos wb = &v2buf; 386 1.10 thorpej 387 1.10 thorpej } else { 388 1.10 thorpej /* use the RIPv1-or-RIPv2 buffer */ 389 1.12 christos wb = &v12buf; 390 1.10 thorpej 391 1.10 thorpej /* Convert supernet route into corresponding set of network 392 1.10 thorpej * routes for RIPv1, but leave non-contiguous netmasks 393 1.10 thorpej * to ag_check(). 394 1.10 thorpej */ 395 1.10 thorpej if (v1_mask > mask 396 1.10 thorpej && mask + (mask & -mask) == 0) { 397 1.10 thorpej ddst_h = v1_mask & -v1_mask; 398 1.10 thorpej i = (v1_mask & ~mask)/ddst_h; 399 1.10 thorpej 400 1.11 christos if (i > ws.gen_limit) { 401 1.10 thorpej /* Punt if we would have to generate an 402 1.10 thorpej * unreasonable number of routes. 403 1.10 thorpej */ 404 1.15 thorpej if (TRACECONTENTS) 405 1.15 thorpej trace_misc("sending %s-->%s as 1" 406 1.15 thorpej " instead of %d routes", 407 1.15 thorpej addrname(htonl(dst_h), mask, 408 1.15 thorpej 1), 409 1.15 thorpej naddr_ntoa(ws.to.sin_addr 410 1.15 thorpej .s_addr), 411 1.15 thorpej i+1); 412 1.10 thorpej i = 0; 413 1.10 thorpej 414 1.10 thorpej } else { 415 1.10 thorpej mask = v1_mask; 416 1.11 christos ws.gen_limit -= i; 417 1.10 thorpej } 418 1.10 thorpej } 419 1.10 thorpej } 420 1.10 thorpej 421 1.10 thorpej do { 422 1.10 thorpej wb->n->n_family = RIP_AF_INET; 423 1.10 thorpej wb->n->n_dst = htonl(dst_h); 424 1.10 thorpej /* If the route is from router-discovery or we are 425 1.10 thorpej * shutting down, admit only a bad metric. 426 1.10 thorpej */ 427 1.10 thorpej wb->n->n_metric = ((stopint || ag->ag_metric < 1) 428 1.10 thorpej ? HOPCNT_INFINITY 429 1.10 thorpej : ag->ag_metric); 430 1.25 christos wb->n->n_metric = htonl(wb->n->n_metric); 431 1.12 christos /* Any non-zero bits in the supposedly unused RIPv1 fields 432 1.12 christos * cause the old `routed` to ignore the route. 433 1.12 christos * That means the mask and so forth cannot be sent 434 1.12 christos * in the hybrid RIPv1/RIPv2 mode. 435 1.12 christos */ 436 1.12 christos if (ws.state & WS_ST_RIP2_ALL) { 437 1.10 thorpej if (ag->ag_nhop != 0 438 1.10 thorpej && ((ws.state & WS_ST_QUERY) 439 1.10 thorpej || (ag->ag_nhop != ws.ifp->int_addr 440 1.10 thorpej && on_net(ag->ag_nhop, 441 1.10 thorpej ws.ifp->int_net, 442 1.10 thorpej ws.ifp->int_mask)))) 443 1.10 thorpej wb->n->n_nhop = ag->ag_nhop; 444 1.12 christos wb->n->n_mask = htonl(mask); 445 1.10 thorpej wb->n->n_tag = ag->ag_tag; 446 1.10 thorpej } 447 1.10 thorpej dst_h += ddst_h; 448 1.10 thorpej 449 1.10 thorpej if (++wb->n >= wb->lim) 450 1.10 thorpej supply_write(wb); 451 1.10 thorpej } while (i-- != 0); 452 1.10 thorpej } 453 1.10 thorpej 454 1.1 cgd 455 1.10 thorpej /* supply one route from the table 456 1.1 cgd */ 457 1.10 thorpej /* ARGSUSED */ 458 1.10 thorpej static int 459 1.16 christos walk_supply(struct radix_node *rn, 460 1.17 christos struct walkarg *argp UNUSED) 461 1.10 thorpej { 462 1.10 thorpej #define RT ((struct rt_entry *)rn) 463 1.11 christos u_short ags; 464 1.10 thorpej char metric, pref; 465 1.10 thorpej naddr dst, nhop; 466 1.12 christos struct rt_spare *rts; 467 1.12 christos int i; 468 1.10 thorpej 469 1.10 thorpej 470 1.12 christos /* Do not advertise external remote interfaces or passive interfaces. 471 1.10 thorpej */ 472 1.11 christos if ((RT->rt_state & RS_IF) 473 1.11 christos && RT->rt_ifp != 0 474 1.18 thorpej && (RT->rt_ifp->int_state & IS_PASSIVE) 475 1.10 thorpej && !(RT->rt_state & RS_MHOME)) 476 1.10 thorpej return 0; 477 1.10 thorpej 478 1.10 thorpej /* If being quiet about our ability to forward, then 479 1.12 christos * do not say anything unless responding to a query, 480 1.12 christos * except about our main interface. 481 1.10 thorpej */ 482 1.12 christos if (!supplier && !(ws.state & WS_ST_QUERY) 483 1.12 christos && !(RT->rt_state & RS_MHOME)) 484 1.10 thorpej return 0; 485 1.10 thorpej 486 1.10 thorpej dst = RT->rt_dst; 487 1.10 thorpej 488 1.10 thorpej /* do not collide with the fake default route */ 489 1.10 thorpej if (dst == RIP_DEFAULT 490 1.10 thorpej && (ws.state & WS_ST_DEFAULT)) 491 1.10 thorpej return 0; 492 1.10 thorpej 493 1.10 thorpej if (RT->rt_state & RS_NET_SYN) { 494 1.10 thorpej if (RT->rt_state & RS_NET_INT) { 495 1.10 thorpej /* Do not send manual synthetic network routes 496 1.10 thorpej * into the subnet. 497 1.10 thorpej */ 498 1.10 thorpej if (on_net(ws.to.sin_addr.s_addr, 499 1.10 thorpej ntohl(dst), RT->rt_mask)) 500 1.10 thorpej return 0; 501 1.10 thorpej 502 1.10 thorpej } else { 503 1.10 thorpej /* Do not send automatic synthetic network routes 504 1.15 thorpej * if they are not needed because no RIPv1 listeners 505 1.10 thorpej * can hear them. 506 1.10 thorpej */ 507 1.10 thorpej if (ws.state & WS_ST_RIP2_ALL) 508 1.10 thorpej return 0; 509 1.10 thorpej 510 1.10 thorpej /* Do not send automatic synthetic network routes to 511 1.10 thorpej * the real subnet. 512 1.10 thorpej */ 513 1.10 thorpej if (on_net(ws.to.sin_addr.s_addr, 514 1.10 thorpej ntohl(dst), RT->rt_mask)) 515 1.10 thorpej return 0; 516 1.10 thorpej } 517 1.10 thorpej nhop = 0; 518 1.10 thorpej 519 1.10 thorpej } else { 520 1.10 thorpej /* Advertise the next hop if this is not a route for one 521 1.10 thorpej * of our interfaces and the next hop is on the same 522 1.10 thorpej * network as the target. 523 1.15 thorpej * The final determination is made by supply_out(). 524 1.10 thorpej */ 525 1.10 thorpej if (!(RT->rt_state & RS_IF) 526 1.10 thorpej && RT->rt_gate != myaddr 527 1.10 thorpej && RT->rt_gate != loopaddr) 528 1.10 thorpej nhop = RT->rt_gate; 529 1.10 thorpej else 530 1.10 thorpej nhop = 0; 531 1.10 thorpej } 532 1.10 thorpej 533 1.11 christos metric = RT->rt_metric; 534 1.11 christos ags = 0; 535 1.10 thorpej 536 1.10 thorpej if (RT->rt_state & RS_MHOME) { 537 1.10 thorpej /* retain host route of multi-homed servers */ 538 1.10 thorpej ; 539 1.10 thorpej 540 1.10 thorpej } else if (RT_ISHOST(RT)) { 541 1.15 thorpej /* We should always suppress (into existing network routes) 542 1.15 thorpej * the host routes for the local end of our point-to-point 543 1.15 thorpej * links. 544 1.10 thorpej * If we are suppressing host routes in general, then do so. 545 1.10 thorpej * Avoid advertising host routes onto their own network, 546 1.10 thorpej * where they should be handled by proxy-ARP. 547 1.10 thorpej */ 548 1.10 thorpej if ((RT->rt_state & RS_LOCAL) 549 1.10 thorpej || ridhosts 550 1.10 thorpej || on_net(dst, ws.to_net, ws.to_mask)) 551 1.10 thorpej ags |= AGS_SUPPRESS; 552 1.10 thorpej 553 1.15 thorpej /* Aggregate stray host routes into network routes if allowed. 554 1.15 thorpej * We cannot aggregate host routes into small network routes 555 1.15 thorpej * without confusing RIPv1 listeners into thinking the 556 1.15 thorpej * network routes are host routes. 557 1.15 thorpej */ 558 1.22 christos if ((ws.state & WS_ST_AG) && (ws.state & WS_ST_RIP2_ALL)) 559 1.15 thorpej ags |= AGS_AGGREGATE; 560 1.10 thorpej 561 1.15 thorpej } else { 562 1.15 thorpej /* Always suppress network routes into other, existing 563 1.15 thorpej * network routes 564 1.10 thorpej */ 565 1.10 thorpej ags |= AGS_SUPPRESS; 566 1.10 thorpej 567 1.10 thorpej /* Generate supernets if allowed. 568 1.10 thorpej * If we can be heard by RIPv1 systems, we will 569 1.10 thorpej * later convert back to ordinary nets. 570 1.10 thorpej * This unifies dealing with received supernets. 571 1.10 thorpej */ 572 1.15 thorpej if ((ws.state & WS_ST_AG) 573 1.15 thorpej && ((RT->rt_state & RS_SUBNET) 574 1.15 thorpej || (ws.state & WS_ST_SUPER_AG))) 575 1.15 thorpej ags |= AGS_AGGREGATE; 576 1.10 thorpej } 577 1.10 thorpej 578 1.10 thorpej /* Do not send RIPv1 advertisements of subnets to other 579 1.10 thorpej * networks. If possible, multicast them by RIPv2. 580 1.10 thorpej */ 581 1.10 thorpej if ((RT->rt_state & RS_SUBNET) 582 1.10 thorpej && !(ws.state & WS_ST_RIP2_ALL) 583 1.15 thorpej && !on_net(dst, ws.to_std_net, ws.to_std_mask)) 584 1.15 thorpej ags |= AGS_RIPV2 | AGS_AGGREGATE; 585 1.15 thorpej 586 1.1 cgd 587 1.10 thorpej /* Do not send a route back to where it came from, except in 588 1.10 thorpej * response to a query. This is "split-horizon". That means not 589 1.10 thorpej * advertising back to the same network and so via the same interface. 590 1.10 thorpej * 591 1.10 thorpej * We want to suppress routes that might have been fragmented 592 1.10 thorpej * from this route by a RIPv1 router and sent back to us, and so we 593 1.10 thorpej * cannot forget this route here. Let the split-horizon route 594 1.15 thorpej * suppress the fragmented routes and then itself be forgotten. 595 1.10 thorpej * 596 1.10 thorpej * Include the routes for both ends of point-to-point interfaces 597 1.12 christos * among those suppressed by split-horizon, since the other side 598 1.12 christos * should knows them as well as we do. 599 1.12 christos * 600 1.12 christos * Notice spare routes with the same metric that we are about to 601 1.16 christos * advertise, to split the horizon on redundant, inactive paths. 602 1.22 christos * 603 1.22 christos * Do not suppress advertisements of interface-related addresses on 604 1.22 christos * non-point-to-point interfaces. This ensures that we have something 605 1.22 christos * to say every 30 seconds to help detect broken Ethernets or 606 1.22 christos * other interfaces where one packet every 30 seconds costs nothing. 607 1.10 thorpej */ 608 1.12 christos if (ws.ifp != 0 609 1.10 thorpej && !(ws.state & WS_ST_QUERY) 610 1.10 thorpej && (ws.state & WS_ST_TO_ON_NET) 611 1.10 thorpej && (!(RT->rt_state & RS_IF) 612 1.10 thorpej || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { 613 1.12 christos for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { 614 1.15 thorpej if (rts->rts_metric > metric 615 1.15 thorpej || rts->rts_ifp != ws.ifp) 616 1.15 thorpej continue; 617 1.15 thorpej 618 1.12 christos /* If we do not mark the route with AGS_SPLIT_HZ here, 619 1.12 christos * it will be poisoned-reverse, or advertised back 620 1.12 christos * toward its source with an infinite metric. 621 1.12 christos * If we have recently advertised the route with a 622 1.12 christos * better metric than we now have, then we should 623 1.12 christos * poison-reverse the route before suppressing it for 624 1.12 christos * split-horizon. 625 1.12 christos * 626 1.12 christos * In almost all cases, if there is no spare for the 627 1.12 christos * route then it is either old and dead or a brand 628 1.12 christos * new route. If it is brand new, there is no need 629 1.12 christos * for poison-reverse. If it is old and dead, it 630 1.12 christos * is already poisoned. 631 1.12 christos */ 632 1.12 christos if (RT->rt_poison_time < now_expire 633 1.12 christos || RT->rt_poison_metric >= metric 634 1.12 christos || RT->rt_spares[1].rts_gate == 0) { 635 1.12 christos ags |= AGS_SPLIT_HZ; 636 1.15 thorpej ags &= ~AGS_SUPPRESS; 637 1.12 christos } 638 1.12 christos metric = HOPCNT_INFINITY; 639 1.15 thorpej break; 640 1.11 christos } 641 1.11 christos } 642 1.11 christos 643 1.12 christos /* Keep track of the best metric with which the 644 1.12 christos * route has been advertised recently. 645 1.12 christos */ 646 1.12 christos if (RT->rt_poison_metric >= metric 647 1.12 christos || RT->rt_poison_time < now_expire) { 648 1.12 christos RT->rt_poison_time = now.tv_sec; 649 1.12 christos RT->rt_poison_metric = metric; 650 1.12 christos } 651 1.12 christos 652 1.11 christos /* Adjust the outgoing metric by the cost of the link. 653 1.12 christos * Avoid aggregation when a route is counting to infinity. 654 1.11 christos */ 655 1.12 christos pref = RT->rt_poison_metric + ws.metric; 656 1.12 christos metric += ws.metric; 657 1.11 christos 658 1.12 christos /* Do not advertise stable routes that will be ignored, 659 1.12 christos * unless we are answering a query. 660 1.12 christos * If the route recently was advertised with a metric that 661 1.12 christos * would have been less than infinity through this interface, 662 1.12 christos * we need to continue to advertise it in order to poison it. 663 1.12 christos */ 664 1.12 christos if (metric >= HOPCNT_INFINITY) { 665 1.12 christos if (!(ws.state & WS_ST_QUERY) 666 1.12 christos && (pref >= HOPCNT_INFINITY 667 1.12 christos || RT->rt_poison_time < now_garbage)) 668 1.11 christos return 0; 669 1.11 christos 670 1.11 christos metric = HOPCNT_INFINITY; 671 1.1 cgd } 672 1.10 thorpej 673 1.10 thorpej ag_check(dst, RT->rt_mask, 0, nhop, metric, pref, 674 1.10 thorpej RT->rt_seqno, RT->rt_tag, ags, supply_out); 675 1.10 thorpej return 0; 676 1.10 thorpej #undef RT 677 1.1 cgd } 678 1.1 cgd 679 1.10 thorpej 680 1.10 thorpej /* Supply dst with the contents of the routing tables. 681 1.10 thorpej * If this won't fit in one packet, chop it up into several. 682 1.1 cgd */ 683 1.9 christos void 684 1.10 thorpej supply(struct sockaddr_in *dst, 685 1.10 thorpej struct interface *ifp, /* output interface */ 686 1.10 thorpej enum output_type type, 687 1.10 thorpej int flash, /* 1=flash update */ 688 1.12 christos int vers, /* RIP version */ 689 1.12 christos int passwd_ok) /* OK to include cleartext password */ 690 1.1 cgd { 691 1.10 thorpej struct rt_entry *rt; 692 1.12 christos int def_metric; 693 1.10 thorpej 694 1.10 thorpej 695 1.10 thorpej ws.state = 0; 696 1.11 christos ws.gen_limit = 1024; 697 1.10 thorpej 698 1.10 thorpej ws.to = *dst; 699 1.10 thorpej ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); 700 1.10 thorpej ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; 701 1.10 thorpej 702 1.10 thorpej if (ifp != 0) { 703 1.10 thorpej ws.to_mask = ifp->int_mask; 704 1.10 thorpej ws.to_net = ifp->int_net; 705 1.10 thorpej if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask)) 706 1.10 thorpej ws.state |= WS_ST_TO_ON_NET; 707 1.10 thorpej 708 1.10 thorpej } else { 709 1.10 thorpej ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0); 710 1.10 thorpej ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; 711 1.10 thorpej rt = rtfind(dst->sin_addr.s_addr); 712 1.10 thorpej if (rt) 713 1.10 thorpej ifp = rt->rt_ifp; 714 1.10 thorpej } 715 1.10 thorpej 716 1.10 thorpej ws.npackets = 0; 717 1.10 thorpej if (flash) 718 1.10 thorpej ws.state |= WS_ST_FLASH; 719 1.10 thorpej 720 1.10 thorpej if ((ws.ifp = ifp) == 0) { 721 1.10 thorpej ws.metric = 1; 722 1.10 thorpej } else { 723 1.10 thorpej /* Adjust the advertised metric by the outgoing interface 724 1.10 thorpej * metric. 725 1.10 thorpej */ 726 1.22 christos ws.metric = ifp->int_metric + 1 + ifp->int_adj_outmetric; 727 1.10 thorpej } 728 1.10 thorpej 729 1.10 thorpej ripv12_buf.rip.rip_vers = vers; 730 1.10 thorpej 731 1.10 thorpej switch (type) { 732 1.10 thorpej case OUT_MULTICAST: 733 1.23 christos if (ifp != NULL && ifp->int_if_flags & IFF_MULTICAST) 734 1.15 thorpej v2buf.type = OUT_MULTICAST; 735 1.15 thorpej else 736 1.15 thorpej v2buf.type = NO_OUT_MULTICAST; 737 1.12 christos v12buf.type = OUT_BROADCAST; 738 1.10 thorpej break; 739 1.15 thorpej 740 1.15 thorpej case OUT_QUERY: 741 1.15 thorpej ws.state |= WS_ST_QUERY; 742 1.15 thorpej /* fall through */ 743 1.15 thorpej case OUT_BROADCAST: 744 1.10 thorpej case OUT_UNICAST: 745 1.12 christos v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; 746 1.12 christos v12buf.type = type; 747 1.10 thorpej break; 748 1.15 thorpej 749 1.15 thorpej case NO_OUT_MULTICAST: 750 1.15 thorpej case NO_OUT_RIPV2: 751 1.15 thorpej break; /* no output */ 752 1.10 thorpej } 753 1.10 thorpej 754 1.10 thorpej if (vers == RIPv2) { 755 1.10 thorpej /* full RIPv2 only if cannot be heard by RIPv1 listeners */ 756 1.10 thorpej if (type != OUT_BROADCAST) 757 1.10 thorpej ws.state |= WS_ST_RIP2_ALL; 758 1.15 thorpej if ((ws.state & WS_ST_QUERY) 759 1.15 thorpej || !(ws.state & WS_ST_TO_ON_NET)) { 760 1.10 thorpej ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); 761 1.12 christos } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { 762 1.10 thorpej ws.state |= WS_ST_AG; 763 1.10 thorpej if (type != OUT_BROADCAST 764 1.15 thorpej && (ifp == 0 765 1.15 thorpej || !(ifp->int_state & IS_NO_SUPER_AG))) 766 1.10 thorpej ws.state |= WS_ST_SUPER_AG; 767 1.10 thorpej } 768 1.10 thorpej } 769 1.10 thorpej 770 1.12 christos ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; 771 1.12 christos if (!passwd_ok && ws.a != 0 && ws.a->type == RIP_AUTH_PW) 772 1.12 christos ws.a = 0; 773 1.12 christos clr_ws_buf(&v12buf,ws.a); 774 1.12 christos clr_ws_buf(&v2buf,ws.a); 775 1.12 christos 776 1.12 christos /* Fake a default route if asked and if there is not already 777 1.12 christos * a better, real default route. 778 1.12 christos */ 779 1.24 christos if (supplier && ifp && (def_metric = ifp->int_d_metric) != 0) { 780 1.12 christos if (0 == (rt = rtget(RIP_DEFAULT, 0)) 781 1.12 christos || rt->rt_metric+ws.metric >= def_metric) { 782 1.10 thorpej ws.state |= WS_ST_DEFAULT; 783 1.12 christos ag_check(0, 0, 0, 0, def_metric, def_metric, 784 1.10 thorpej 0, 0, 0, supply_out); 785 1.12 christos } else { 786 1.12 christos def_metric = rt->rt_metric+ws.metric; 787 1.10 thorpej } 788 1.12 christos 789 1.12 christos /* If both RIPv2 and the poor-man's router discovery 790 1.12 christos * kludge are on, arrange to advertise an extra 791 1.12 christos * default route via RIPv1. 792 1.12 christos */ 793 1.10 thorpej if ((ws.state & WS_ST_RIP2_ALL) 794 1.10 thorpej && (ifp->int_state & IS_PM_RDISC)) { 795 1.10 thorpej ripv12_buf.rip.rip_vers = RIPv1; 796 1.12 christos v12buf.n->n_family = RIP_AF_INET; 797 1.12 christos v12buf.n->n_dst = htonl(RIP_DEFAULT); 798 1.12 christos v12buf.n->n_metric = htonl(def_metric); 799 1.12 christos v12buf.n++; 800 1.10 thorpej } 801 1.10 thorpej } 802 1.10 thorpej 803 1.10 thorpej (void)rn_walktree(rhead, walk_supply, 0); 804 1.10 thorpej ag_flush(0,0,supply_out); 805 1.1 cgd 806 1.10 thorpej /* Flush the packet buffers, provided they are not empty and 807 1.10 thorpej * do not contain only the password. 808 1.10 thorpej */ 809 1.12 christos if (v12buf.n != v12buf.base 810 1.12 christos && (v12buf.n > v12buf.base+1 811 1.12 christos || v12buf.base->n_family != RIP_AF_AUTH)) 812 1.12 christos supply_write(&v12buf); 813 1.12 christos if (v2buf.n != v2buf.base 814 1.12 christos && (v2buf.n > v2buf.base+1 815 1.12 christos || v2buf.base->n_family != RIP_AF_AUTH)) 816 1.12 christos supply_write(&v2buf); 817 1.10 thorpej 818 1.10 thorpej /* If we sent nothing and this is an answer to a query, send 819 1.10 thorpej * an empty buffer. 820 1.10 thorpej */ 821 1.10 thorpej if (ws.npackets == 0 822 1.10 thorpej && (ws.state & WS_ST_QUERY)) 823 1.12 christos supply_write(&v12buf); 824 1.1 cgd } 825 1.1 cgd 826 1.10 thorpej 827 1.10 thorpej /* send all of the routing table or just do a flash update 828 1.1 cgd */ 829 1.9 christos void 830 1.10 thorpej rip_bcast(int flash) 831 1.10 thorpej { 832 1.10 thorpej #ifdef _HAVE_SIN_LEN 833 1.20 christos static struct sockaddr_in dst = {sizeof(dst), AF_INET, 0, {0}, {0}}; 834 1.10 thorpej #else 835 1.10 thorpej static struct sockaddr_in dst = {AF_INET}; 836 1.10 thorpej #endif 837 1.9 christos struct interface *ifp; 838 1.10 thorpej enum output_type type; 839 1.10 thorpej int vers; 840 1.10 thorpej struct timeval rtime; 841 1.10 thorpej 842 1.10 thorpej 843 1.10 thorpej need_flash = 0; 844 1.10 thorpej intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); 845 1.10 thorpej no_flash = rtime; 846 1.10 thorpej timevaladd(&no_flash, &now); 847 1.10 thorpej 848 1.10 thorpej if (rip_sock < 0) 849 1.10 thorpej return; 850 1.10 thorpej 851 1.12 christos trace_act("send %s and inhibit dynamic updates for %.3f sec", 852 1.10 thorpej flash ? "dynamic update" : "all routes", 853 1.10 thorpej rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); 854 1.10 thorpej 855 1.10 thorpej for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 856 1.12 christos /* Skip interfaces not doing RIP. 857 1.12 christos * Do try broken interfaces to see if they have healed. 858 1.1 cgd */ 859 1.12 christos if (IS_RIP_OUT_OFF(ifp->int_state)) 860 1.1 cgd continue; 861 1.10 thorpej 862 1.10 thorpej /* skip turned off interfaces */ 863 1.15 thorpej if (!iff_up(ifp->int_if_flags)) 864 1.1 cgd continue; 865 1.10 thorpej 866 1.12 christos vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; 867 1.10 thorpej 868 1.10 thorpej if (ifp->int_if_flags & IFF_BROADCAST) { 869 1.10 thorpej /* ordinary, hardware interface */ 870 1.10 thorpej dst.sin_addr.s_addr = ifp->int_brdaddr; 871 1.12 christos 872 1.10 thorpej if (vers == RIPv2 873 1.25 christos && !(ifp->int_state & IS_NO_RIP_MCAST)) { 874 1.10 thorpej type = OUT_MULTICAST; 875 1.10 thorpej } else { 876 1.10 thorpej type = OUT_BROADCAST; 877 1.10 thorpej } 878 1.10 thorpej 879 1.10 thorpej } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 880 1.10 thorpej /* point-to-point hardware interface */ 881 1.10 thorpej dst.sin_addr.s_addr = ifp->int_dstaddr; 882 1.25 christos /* use multicast if the interface allows (e.g. GRE) */ 883 1.25 christos if (vers == RIPv2 884 1.25 christos && (ifp->int_if_flags & IFF_MULTICAST) 885 1.25 christos && !(ifp->int_state & IS_NO_RIP_MCAST)) { 886 1.25 christos type = OUT_MULTICAST; 887 1.25 christos } else { 888 1.25 christos type = OUT_UNICAST; 889 1.25 christos } 890 1.10 thorpej 891 1.12 christos } else if (ifp->int_state & IS_REMOTE) { 892 1.10 thorpej /* remote interface */ 893 1.10 thorpej dst.sin_addr.s_addr = ifp->int_addr; 894 1.10 thorpej type = OUT_UNICAST; 895 1.12 christos 896 1.12 christos } else { 897 1.12 christos /* ATM, HIPPI, etc. */ 898 1.12 christos continue; 899 1.10 thorpej } 900 1.10 thorpej 901 1.12 christos supply(&dst, ifp, type, flash, vers, 1); 902 1.10 thorpej } 903 1.10 thorpej 904 1.10 thorpej update_seqno++; /* all routes are up to date */ 905 1.10 thorpej } 906 1.10 thorpej 907 1.10 thorpej 908 1.10 thorpej /* Ask for routes 909 1.10 thorpej * Do it only once to an interface, and not even after the interface 910 1.10 thorpej * was broken and recovered. 911 1.10 thorpej */ 912 1.10 thorpej void 913 1.10 thorpej rip_query(void) 914 1.10 thorpej { 915 1.10 thorpej #ifdef _HAVE_SIN_LEN 916 1.20 christos static struct sockaddr_in dst = {sizeof(dst), AF_INET, 0, {0}, {0}}; 917 1.10 thorpej #else 918 1.10 thorpej static struct sockaddr_in dst = {AF_INET}; 919 1.10 thorpej #endif 920 1.10 thorpej struct interface *ifp; 921 1.10 thorpej struct rip buf; 922 1.10 thorpej enum output_type type; 923 1.10 thorpej 924 1.10 thorpej 925 1.10 thorpej if (rip_sock < 0) 926 1.10 thorpej return; 927 1.10 thorpej 928 1.13 lukem memset(&buf, 0, sizeof(buf)); 929 1.10 thorpej 930 1.10 thorpej for (ifp = ifnet; ifp; ifp = ifp->int_next) { 931 1.12 christos /* Skip interfaces those already queried. 932 1.12 christos * Do not ask via interfaces through which we don't 933 1.12 christos * accept input. Do not ask via interfaces that cannot 934 1.12 christos * send RIP packets. 935 1.12 christos * Do try broken interfaces to see if they have healed. 936 1.1 cgd */ 937 1.12 christos if (IS_RIP_IN_OFF(ifp->int_state) 938 1.12 christos || ifp->int_query_time != NEVER) 939 1.10 thorpej continue; 940 1.10 thorpej 941 1.10 thorpej /* skip turned off interfaces */ 942 1.15 thorpej if (!iff_up(ifp->int_if_flags)) 943 1.1 cgd continue; 944 1.10 thorpej 945 1.12 christos buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; 946 1.10 thorpej buf.rip_cmd = RIPCMD_REQUEST; 947 1.10 thorpej buf.rip_nets[0].n_family = RIP_AF_UNSPEC; 948 1.10 thorpej buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 949 1.10 thorpej 950 1.15 thorpej /* Send a RIPv1 query only if allowed and if we will 951 1.15 thorpej * listen to RIPv1 routers. 952 1.15 thorpej */ 953 1.15 thorpej if ((ifp->int_state & IS_NO_RIPV1_OUT) 954 1.15 thorpej || (ifp->int_state & IS_NO_RIPV1_IN)) { 955 1.15 thorpej buf.rip_vers = RIPv2; 956 1.15 thorpej } else { 957 1.15 thorpej buf.rip_vers = RIPv1; 958 1.15 thorpej } 959 1.15 thorpej 960 1.10 thorpej if (ifp->int_if_flags & IFF_BROADCAST) { 961 1.10 thorpej /* ordinary, hardware interface */ 962 1.10 thorpej dst.sin_addr.s_addr = ifp->int_brdaddr; 963 1.15 thorpej 964 1.15 thorpej /* Broadcast RIPv1 queries and RIPv2 queries 965 1.15 thorpej * when the hardware cannot multicast. 966 1.1 cgd */ 967 1.10 thorpej if (buf.rip_vers == RIPv2 968 1.15 thorpej && (ifp->int_if_flags & IFF_MULTICAST) 969 1.25 christos && !(ifp->int_state & IS_NO_RIP_MCAST)) { 970 1.10 thorpej type = OUT_MULTICAST; 971 1.10 thorpej } else { 972 1.10 thorpej type = OUT_BROADCAST; 973 1.10 thorpej } 974 1.10 thorpej 975 1.10 thorpej } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 976 1.10 thorpej /* point-to-point hardware interface */ 977 1.10 thorpej dst.sin_addr.s_addr = ifp->int_dstaddr; 978 1.25 christos /* use multicast if the interface allows (e.g. GRE) */ 979 1.25 christos if (buf.rip_vers == RIPv2 980 1.25 christos && (ifp->int_if_flags & IFF_MULTICAST) 981 1.25 christos && !(ifp->int_state & IS_NO_RIP_MCAST)) { 982 1.25 christos type = OUT_MULTICAST; 983 1.25 christos } else { 984 1.25 christos type = OUT_UNICAST; 985 1.25 christos } 986 1.10 thorpej 987 1.12 christos } else if (ifp->int_state & IS_REMOTE) { 988 1.10 thorpej /* remote interface */ 989 1.10 thorpej dst.sin_addr.s_addr = ifp->int_addr; 990 1.10 thorpej type = OUT_UNICAST; 991 1.12 christos 992 1.12 christos } else { 993 1.12 christos /* ATM, HIPPI, etc. */ 994 1.12 christos continue; 995 1.10 thorpej } 996 1.10 thorpej 997 1.12 christos ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; 998 1.10 thorpej if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0) 999 1.10 thorpej if_sick(ifp); 1000 1.1 cgd } 1001 1.1 cgd } 1002