2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * The contents of this file constitute Original Code as defined in and 
   7  * are subject to the Apple Public Source License Version 1.1 (the 
   8  * "License").  You may not use this file except in compliance with the 
   9  * License.  Please obtain a copy of the License at 
  10  * http://www.apple.com/publicsource and read it before using this file. 
  12  * This Original Code and all software distributed under the License are 
  13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the 
  17  * License for the specific language governing rights and limitations 
  20  * @APPLE_LICENSE_HEADER_END@ 
  23  *      Copyright (c) 1993-1998 Apple Computer, Inc. 
  24  *      All Rights Reserved. 
  28  *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. 
  31 #include <sys/errno.h> 
  32 #include <sys/types.h> 
  33 #include <sys/param.h> 
  34 #include <machine/spl.h> 
  35 #include <sys/systm.h> 
  36 #include <sys/kernel.h> 
  38 #include <sys/filedesc.h> 
  39 #include <sys/fcntl.h> 
  41 #include <sys/ioctl.h> 
  42 #include <sys/malloc.h> 
  43 #include <sys/socket.h> 
  44 #include <sys/socketvar.h> 
  48 #include <netat/sysglue.h> 
  49 #include <netat/appletalk.h> 
  50 #include <netat/at_var.h> 
  51 #include <netat/ddp.h> 
  52 #include <netat/rtmp.h> 
  53 #include <netat/zip.h> 
  54 #include <netat/routing_tables.h> 
  55 #include <netat/debug.h> 
  56 #include <netat/at_pcb.h> 
  58 #include <sys/kern_event.h> 
  60 extern void rtmp_router_input(); 
  62 /****************************************************************/ 
  68 /****************************************************************/ 
  71 /* rtmp.c: , 1.6; 2/26/93; Apple Computer, Inc." */ 
  74 #define NROUTERS2TRAK   8 
  76 #define NODE(r)         ((r)->ifARouter.s_node) 
  77 #define NET(r)          ((r)->ifARouter.s_net) 
  78 #define INUSE(r)        (NODE(r)) 
  80 void ddp_age_router(); 
  82 static struct routerinfo 
{ 
  83         struct at_addr ifARouter
; 
  86 } trackedrouters
[NROUTERS2TRAK
]; 
  88 void trackrouter_rem_if(ifID
) 
  89      register at_ifaddr_t 
*ifID
; 
  92         register struct routerinfo 
*router
; 
  94         for (i 
= NROUTERS2TRAK
; --i 
>= 0;) { 
  95                 router 
= &trackedrouters
[i
]; 
  96                 if (trackedrouters
[i
].ifID 
== ifID
) { 
  97                         untimeout(ddp_age_router
, (caddr_t
)router
); 
 104 void routershutdown() 
 108         for (i 
= NROUTERS2TRAK
; --i 
>= 0;) { 
 109                 register struct routerinfo 
*router
; 
 111                 router 
= &trackedrouters
[i
]; 
 113                         untimeout(ddp_age_router
, (caddr_t
) router
); 
 114                         bzero((caddr_t
) router
, sizeof(struct routerinfo
)); 
 119 int router_added  
= 0; 
 120 int router_killed 
= 0; 
 124 void trackrouter(ifID
, net
, node
) 
 125      register at_ifaddr_t 
*ifID
; 
 126      register unsigned short    net
; 
 127      register unsigned char     node
; 
 129         register struct routerinfo 
*unused 
= NULL
; 
 132         for (i 
= NROUTERS2TRAK
; --i 
>= 0;) { 
 133                 register struct routerinfo 
*router
; 
 135                 router 
= &trackedrouters
[(i 
+ node
) & (NROUTERS2TRAK
-1)]; 
 136                 if ((NODE(router
) == node
) && (NET(router
) == net
)) { 
 137                         untimeout(ddp_age_router
, (caddr_t
) router
); 
 138                         timeout(ddp_age_router
, (caddr_t
) router
, 50*SYS_HZ
); 
 142                 else if (!INUSE(router
) && !unused
) 
 148                 if (ifID
->ifARouter
.s_net 
== 0) { 
 149                         /* Send event that this interface just got a router. This does not 
 150                                 discriminate on whether this router is valid or not. If it is not 
 151                                 valid rtmp_input will send a KEV_ATALK_ROUTERUP_INVALID event. */ 
 152                         atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ROUTERUP
, 0, 0); 
 158                 ifID
->ifRouterState 
= ROUTER_AROUND
; 
 159                 timeout(ddp_age_router
, (caddr_t
) unused
, 50*SYS_HZ
); 
 161                 if (NET(ifID
) == 0 && NODE(ifID
) == 0) { 
 169  * This is the timeout function that is called after 50 seconds,  
 170  * if no router packets come in. That way we won't send extended  
 171  * frames to something that is not there. Untimeout is called if  
 172  * an RTMP packet comes in so this routine will not be called. 
 174 void ddp_age_router(deadrouter
) 
 175      register struct routerinfo 
*deadrouter
; 
 177         register at_ifaddr_t 
*ourrouter 
= deadrouter
->ifID
; 
 178         boolean_t       funnel_state
; 
 180         funnel_state 
= thread_funnel_set(network_flock
, TRUE
); 
 182         dPrintf(D_M_RTMP
, D_L_INFO
,  
 183                 ("ddp_age_router called deadrouter=%d:%d\n", NODE(deadrouter
), NET(deadrouter
))); 
 187         if (NODE(ourrouter
) == NODE(deadrouter
) &&  
 188             NET(ourrouter
) == NET(deadrouter
)) { 
 189                 register unsigned long  atrandom 
= random(); 
 190                 register struct routerinfo 
*newrouter
; 
 193                 bzero((caddr_t
) deadrouter
, sizeof(struct routerinfo
)); 
 194                 for (i 
= NROUTERS2TRAK
; --i 
>= 0;) { 
 195                         newrouter 
= &trackedrouters
[(i 
+ atrandom
) & (NROUTERS2TRAK
-1)]; 
 196                         if (INUSE(newrouter
)) 
 202                         /* Set our router to another on the list and go on with life */ 
 203                         NET(ourrouter
) = NET(newrouter
); 
 204                         NODE(ourrouter
) = NODE(newrouter
); 
 207                         /* from gorouterless() */ 
 208                         /* We have no other routers. */ 
 209                         ATTRACE(AT_MID_DDP
, AT_SID_TIMERS
, AT_LV_WARNING
, FALSE
, 
 210                                 "ddp_age_router entry : ARouter = 0x%x, RouterState = 0x%x", 
 211                                 ATALK_VALUE(ourrouter
->ifARouter
), ourrouter
->ifRouterState
, 0); 
 213                         switch (ourrouter
->ifRouterState
) { 
 215                                 /* This is where we lose our cable. 
 216                                         Reset router fields and state accordingly. */ 
 217                                 ourrouter
->ifARouter
.s_net 
= 0; 
 218                                 ourrouter
->ifARouter
.s_node 
= 0; 
 219                                 ourrouter
->ifThisCableStart 
= DDP_MIN_NETWORK
; 
 220                                 ourrouter
->ifThisCableEnd 
= DDP_MAX_NETWORK
; 
 221                                 ourrouter
->ifRouterState 
= NO_ROUTER
; 
 223                                 /* Send event to indicate that we've lost our seed router. */ 
 224                                 atalk_post_msg(ourrouter
->aa_ifp
, KEV_ATALK_ROUTERDOWN
, 0, 0); 
 226                                 zip_control(ourrouter
, ZIP_NO_ROUTER
); 
 228                         case ROUTER_WARNING 
: 
 229                                 /* there was a router that we were ignoring... 
 230                                  * now, even that's gone.  But we want to tackle the 
 231                                  * case where another router may come up after all 
 232                                  * of them have died... 
 234                                 ourrouter
->ifRouterState 
= NO_ROUTER
; 
 239                 bzero((caddr_t
) deadrouter
, sizeof(struct routerinfo
)); 
 241         (void) thread_funnel_set(network_flock
, FALSE
); 
 243 } /* ddp_age_router */ 
 245 void rtmp_input (mp
, ifID
) 
 247      register at_ifaddr_t 
*ifID
; 
 249         register at_net_al      this_net
; 
 250         register at_net_al      range_start
, range_end
; 
 251         register at_ddp_t       
*ddp 
= (at_ddp_t 
*)gbuf_rptr(mp
); 
 252                                 /* NOTE: there is an assumption here that the  
 253                                  * DATA follows the header. */ 
 254         register at_rtmp        
*rtmp 
= (at_rtmp 
*)ddp
->data
; 
 256         if (gbuf_type(mp
) != MSG_DATA
) { 
 257                 /* If this is a M_ERROR message, DDP is shutting down,  
 258                  * nothing to do here...If it's something else, we don't  
 259                  * understand what it is 
 269         if (gbuf_len(mp
) < (DDP_X_HDR_SIZE 
+ sizeof(at_rtmp
))) { 
 273         this_net 
= ifID
->ifThisNode
.s_net
; 
 274         if (rtmp
->at_rtmp_id_length  
!= 8) { 
 281                 tp 
= ((at_rtmp_tuple 
*)&rtmp
->at_rtmp_id
[1]); 
 282                 range_start 
= NET_VALUE(tp
->at_rtmp_net
); 
 283                 tp 
= ((at_rtmp_tuple 
*)&rtmp
->at_rtmp_id
[4]); 
 284                 range_end 
= NET_VALUE(tp
->at_rtmp_net
); 
 286                 if (ifID
->ifRouterState 
== ROUTER_AROUND
) { 
 287                         if ((ifID
->ifThisCableStart 
== range_start
) && 
 288                             (ifID
->ifThisCableEnd 
== range_end
)) { 
 290                                             NET_VALUE(rtmp
->at_rtmp_this_net
), 
 295                         /* There was no router around earlier, one 
 296                          * probably just came up. 
 298                         if ((this_net 
>= DDP_STARTUP_LOW
) &&  
 299                             (this_net 
<= DDP_STARTUP_HIGH
)) { 
 300                                 /* we're operating in the startup range, 
 301                                  * ignore the presence of router 
 303                                 if (ifID
->ifRouterState 
== NO_ROUTER
) { 
 304                                         dPrintf(D_M_RTMP
, D_L_INFO
, ("rtmp_input: new router came up, INVALID: net \ 
 305                                                 in startup range.\n")); 
 306                                         /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that 
 307                                                 a new router has come up when we had none before. */ 
 309                                                     NET_VALUE(rtmp
->at_rtmp_this_net
), 
 312                                         ifID
->ifRouterState 
= ROUTER_WARNING
; 
 314                                         /* This router is invalid. Send event. */ 
 315                                         atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ROUTERUP_INVALID
, 0, 0); 
 319                                  * is not in startup range; Is our 
 320                                  * address good for the cable?? 
 322                                 if ((this_net 
>= range_start
) && 
 323                                     (this_net 
<= range_end
)) { 
 324                                         /* Our address is in the range 
 325                                          * valid for this cable... Note 
 326                                          * the router address and then 
 327                                          * get ZIP rolling to get the 
 330                                         ifID
->ifThisCableStart 
= range_start
; 
 331                                         ifID
->ifThisCableEnd 
= range_end
; 
 333                                         /* A seed router that gives us back our cable range came up. 
 334                                                 It's a valid router and gives us our network back. */ 
 335                                         atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ROUTERUP
, 0, 0); 
 338                                                     NET_VALUE(rtmp
->at_rtmp_this_net
), 
 341                                         zip_control(ifID
, ZIP_LATE_ROUTER
); 
 343                                         /* Our address is not in the 
 344                                          * range valid for this cable.. 
 345                                          * ignore presence of the  
 348                                         if (ifID
->ifRouterState 
== NO_ROUTER
) { 
 349                                                 /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that 
 350                                                         a new router has come up when we had none before. */ 
 352                                                             NET_VALUE(rtmp
->at_rtmp_this_net
), 
 355                                                 ifID
->ifRouterState 
= ROUTER_WARNING
; 
 357                                                 /* A new seed router came up, but the cable range is different 
 358                                                         than what we had before. */ 
 359                                                 atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ROUTERUP_INVALID
, 0, 0); 
 373   bzero((caddr_t
)trackedrouters
, sizeof(struct routerinfo
)*NROUTERS2TRAK
);