1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1993-1998 Apple Computer, Inc. 30 * All Rights Reserved. 31 */ 32 33/* 34 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. 35 */ 36 37#include <sys/errno.h> 38#include <sys/types.h> 39#include <sys/param.h> 40#include <machine/spl.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/proc.h> 44#include <sys/filedesc.h> 45#include <sys/fcntl.h> 46#include <sys/mbuf.h> 47#include <sys/ioctl.h> 48#include <sys/malloc.h> 49#include <sys/socket.h> 50#include <sys/socketvar.h> 51 52#include <net/if.h> 53 54#include <netat/sysglue.h> 55#include <netat/appletalk.h> 56#include <netat/at_pcb.h> 57#include <netat/at_var.h> 58#include <netat/ddp.h> 59#include <netat/rtmp.h> 60#include <netat/zip.h> 61#include <netat/routing_tables.h> 62#include <netat/debug.h> 63 64#include <sys/kern_event.h> 65 66 67/****************************************************************/ 68/* */ 69/* */ 70/* RTMP Protocol */ 71/* */ 72/* */ 73/****************************************************************/ 74 75 76/* rtmp.c: , 1.6; 2/26/93; Apple Computer, Inc." */ 77 78 79#define NROUTERS2TRAK 8 80#define FIFTYSECS 10 81#define NODE(r) ((r)->ifARouter.s_node) 82#define NET(r) ((r)->ifARouter.s_net) 83#define INUSE(r) (NODE(r)) 84 85void ddp_age_router(void *arg); 86 87static struct routerinfo { 88 struct at_addr ifARouter; 89 at_ifaddr_t *ifID; 90 void *tmo; 91} trackedrouters[NROUTERS2TRAK]; 92 93void trackrouter_rem_if(ifID) 94 register at_ifaddr_t *ifID; 95{ 96 int i; 97 register struct routerinfo *router; 98 99 for (i = NROUTERS2TRAK; --i >= 0;) { 100 router = &trackedrouters[i]; 101 if (trackedrouters[i].ifID == ifID) { 102 untimeout(ddp_age_router, (caddr_t)router); 103 break; 104 } 105 } 106} 107 108 109void routershutdown(void) 110{ 111 int i; 112 113 for (i = NROUTERS2TRAK; --i >= 0;) { 114 register struct routerinfo *router; 115 116 router = &trackedrouters[i]; 117 if (INUSE(router)) { 118 untimeout(ddp_age_router, (caddr_t) router); 119 bzero((caddr_t) router, sizeof(struct routerinfo)); 120 } 121 } 122} 123 124int router_added = 0; 125int router_killed = 0; 126 127 128 129void trackrouter(ifID, net, node) 130 register at_ifaddr_t *ifID; 131 register unsigned short net; 132 register unsigned char node; 133{ 134 register struct routerinfo *unused = NULL; 135 int i; 136 137 for (i = NROUTERS2TRAK; --i >= 0;) { 138 register struct routerinfo *router; 139 140 router = &trackedrouters[(i + node) & (NROUTERS2TRAK-1)]; 141 if ((NODE(router) == node) && (NET(router) == net)) { 142 untimeout(ddp_age_router, (caddr_t) router); 143 timeout(ddp_age_router, (caddr_t) router, 50*SYS_HZ); 144 unused = NULL; 145 break; 146 } 147 else if (!INUSE(router) && !unused) 148 unused = router; 149 } 150 if (unused) { 151 router_added++; 152 153 if (ifID->ifARouter.s_net == 0) { 154 /* Send event that this interface just got a router. This does not 155 discriminate on whether this router is valid or not. If it is not 156 valid rtmp_input will send a KEV_ATALK_ROUTERUP_INVALID event. */ 157 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP, 0, 0); 158 } 159 160 unused->ifID = ifID; 161 NET(unused) = net; 162 NODE(unused) = node; 163 ifID->ifRouterState = ROUTER_AROUND; 164 timeout(ddp_age_router, (caddr_t) unused, 50*SYS_HZ); 165 166 if (NET(ifID) == 0 && NODE(ifID) == 0) { 167 NET(ifID) = net; 168 NODE(ifID) = node; 169 } 170 } 171} 172 173/* 174 * This is the timeout function that is called after 50 seconds, 175 * if no router packets come in. That way we won't send extended 176 * frames to something that is not there. Untimeout is called if 177 * an RTMP packet comes in so this routine will not be called. 178 */ 179void ddp_age_router(void *arg) 180{ 181 struct routerinfo *deadrouter = (struct routerinfo*)arg; 182 register at_ifaddr_t *ourrouter; 183 184 atalk_lock(); 185 186 ourrouter = deadrouter->ifID; 187 if (ourrouter == NULL) { 188 atalk_unlock(); 189 return; 190 } 191 192 dPrintf(D_M_RTMP, D_L_INFO, 193 ("ddp_age_router called deadrouter=%d:%d\n", NODE(deadrouter), NET(deadrouter))); 194 195 router_killed++; 196 197 if (NODE(ourrouter) == NODE(deadrouter) && 198 NET(ourrouter) == NET(deadrouter)) { 199 register unsigned long atrandom = random(); 200 register struct routerinfo *newrouter = NULL; 201 int i; 202 203 bzero((caddr_t) deadrouter, sizeof(struct routerinfo)); 204 for (i = NROUTERS2TRAK; --i >= 0;) { 205 newrouter = &trackedrouters[(i + atrandom) & (NROUTERS2TRAK-1)]; 206 if (INUSE(newrouter)) 207 break; 208 else 209 newrouter = NULL; 210 } 211 if (newrouter) { 212 /* Set our router to another on the list and go on with life */ 213 NET(ourrouter) = NET(newrouter); 214 NODE(ourrouter) = NODE(newrouter); 215 } 216 else { 217 /* from gorouterless() */ 218 /* We have no other routers. */ 219 ATTRACE(AT_MID_DDP, AT_SID_TIMERS, AT_LV_WARNING, FALSE, 220 "ddp_age_router entry : ARouter = 0x%x, RouterState = 0x%x", 221 ATALK_VALUE(ourrouter->ifARouter), ourrouter->ifRouterState, 0); 222 223 switch (ourrouter->ifRouterState) { 224 case ROUTER_AROUND : 225 /* This is where we lose our cable. 226 Reset router fields and state accordingly. */ 227 ourrouter->ifARouter.s_net = 0; 228 ourrouter->ifARouter.s_node = 0; 229 ourrouter->ifThisCableStart = DDP_MIN_NETWORK; 230 ourrouter->ifThisCableEnd = DDP_MAX_NETWORK; 231 ourrouter->ifRouterState = NO_ROUTER; 232 233 /* Send event to indicate that we've lost our seed router. */ 234 atalk_post_msg(ourrouter->aa_ifp, KEV_ATALK_ROUTERDOWN, 0, 0); 235 236 zip_control(ourrouter, ZIP_NO_ROUTER); 237 break; 238 case ROUTER_WARNING : 239 /* there was a router that we were ignoring... 240 * now, even that's gone. But we want to tackle the 241 * case where another router may come up after all 242 * of them have died... 243 */ 244 ourrouter->ifRouterState = NO_ROUTER; 245 break; 246 } 247 } 248 } else 249 bzero((caddr_t) deadrouter, sizeof(struct routerinfo)); 250 251 atalk_unlock(); 252 253} /* ddp_age_router */ 254 255void rtmp_input (mp, ifID) 256 register gbuf_t *mp; 257 register at_ifaddr_t *ifID; 258{ 259 register at_net_al this_net; 260 register at_net_al range_start, range_end; 261 register at_ddp_t *ddp = (at_ddp_t *)gbuf_rptr(mp); 262 /* NOTE: there is an assumption here that the 263 * DATA follows the header. */ 264 register at_rtmp *rtmp = (at_rtmp *)ddp->data; 265 266 if (gbuf_type(mp) != MSG_DATA) { 267 /* If this is a M_ERROR message, DDP is shutting down, 268 * nothing to do here...If it's something else, we don't 269 * understand what it is 270 */ 271 gbuf_freem(mp); 272 return; 273 } 274 275 if (!ifID) { 276 gbuf_freem(mp); 277 return; 278 } 279 if (gbuf_len(mp) < (DDP_X_HDR_SIZE + sizeof(at_rtmp))) { 280 gbuf_freem(mp); 281 return; 282 } 283 this_net = ifID->ifThisNode.s_net; 284 if (rtmp->at_rtmp_id_length != 8) { 285 gbuf_freem(mp); 286 return; 287 } 288 289 { 290 at_rtmp_tuple *tp; 291 tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[1]); 292 range_start = NET_VALUE(tp->at_rtmp_net); 293 tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[4]); 294 range_end = NET_VALUE(tp->at_rtmp_net); 295 296 if (ifID->ifRouterState == ROUTER_AROUND) { 297 if ((ifID->ifThisCableStart == range_start) && 298 (ifID->ifThisCableEnd == range_end)) { 299 trackrouter(ifID, 300 NET_VALUE(rtmp->at_rtmp_this_net), 301 rtmp->at_rtmp_id[0] 302 ); 303 } 304 } else { 305 /* There was no router around earlier, one 306 * probably just came up. 307 */ 308 if ((this_net >= DDP_STARTUP_LOW) && 309 (this_net <= DDP_STARTUP_HIGH)) { 310 /* we're operating in the startup range, 311 * ignore the presence of router 312 */ 313 if (ifID->ifRouterState == NO_ROUTER) { 314 dPrintf(D_M_RTMP, D_L_INFO, ("rtmp_input: new router came up, INVALID: net \ 315 in startup range.\n")); 316 /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that 317 a new router has come up when we had none before. */ 318 trackrouter(ifID, 319 NET_VALUE(rtmp->at_rtmp_this_net), 320 rtmp->at_rtmp_id[0] 321 ); 322 ifID->ifRouterState = ROUTER_WARNING; 323 324 /* This router is invalid. Send event. */ 325 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0); 326 } 327 } else { 328 /* our address 329 * is not in startup range; Is our 330 * address good for the cable?? 331 */ 332 if ((this_net >= range_start) && 333 (this_net <= range_end)) { 334 /* Our address is in the range 335 * valid for this cable... Note 336 * the router address and then 337 * get ZIP rolling to get the 338 * zone info. 339 */ 340 ifID->ifThisCableStart = range_start; 341 ifID->ifThisCableEnd = range_end; 342 343 /* A seed router that gives us back our cable range came up. 344 It's a valid router and gives us our network back. */ 345 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP, 0, 0); 346 347 trackrouter(ifID, 348 NET_VALUE(rtmp->at_rtmp_this_net), 349 rtmp->at_rtmp_id[0] 350 ); 351 zip_control(ifID, ZIP_LATE_ROUTER); 352 } else { 353 /* Our address is not in the 354 * range valid for this cable.. 355 * ignore presence of the 356 * router 357 */ 358 if (ifID->ifRouterState == NO_ROUTER) { 359 /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that 360 a new router has come up when we had none before. */ 361 trackrouter(ifID, 362 NET_VALUE(rtmp->at_rtmp_this_net), 363 rtmp->at_rtmp_id[0] 364 ); 365 ifID->ifRouterState = ROUTER_WARNING; 366 367 /* A new seed router came up, but the cable range is different 368 than what we had before. */ 369 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0); 370 } 371 } 372 } 373 } 374 } 375 376 gbuf_freem(mp); 377 return; 378} 379 380 381void rtmp_init() 382{ 383 bzero((caddr_t)trackedrouters, sizeof(struct routerinfo)*NROUTERS2TRAK); 384} 385 386 387