darwin-xnu/bsd/netat/ddp_rtmp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   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.
  11 * 
  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
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 *      Copyright (c) 1993-1998 Apple Computer, Inc.
  24 *      All Rights Reserved.
  25 */
  26
  27/*
  28 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
  29 */
  30
  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>
  37#include <sys/proc.h>
  38#include <sys/filedesc.h>
  39#include <sys/fcntl.h>
  40#include <sys/mbuf.h>
  41#include <sys/ioctl.h>
  42#include <sys/malloc.h>
  43#include <sys/socket.h>
  44#include <sys/socketvar.h>
  45
  46#include <net/if.h>
  47
  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>
  57
  58#include <sys/kern_event.h>
  59
  60extern void rtmp_router_input();
  61
  62/****************************************************************/
  63/*                                                              */
  64/*                                                              */
  65/*                      RTMP Protocol                           */
  66/*                                                              */
  67/*                                                              */
  68/****************************************************************/
  69
  70
  71/* rtmp.c: , 1.6; 2/26/93; Apple Computer, Inc." */
  72
  73
  74#define NROUTERS2TRAK   8
  75#define FIFTYSECS       10
  76#define NODE(r)         ((r)->ifARouter.s_node)
  77#define NET(r)          ((r)->ifARouter.s_net)
  78#define INUSE(r)        (NODE(r))
  79
  80void ddp_age_router();
  81
  82static struct routerinfo {
  83        struct at_addr ifARouter;
  84        at_ifaddr_t       *ifID;
  85        void              *tmo;
  86} trackedrouters[NROUTERS2TRAK];
  87
  88void trackrouter_rem_if(ifID)
  89     register at_ifaddr_t *ifID;
  90{
  91        register i;
  92        register struct routerinfo *router;
  93
  94        for (i = NROUTERS2TRAK; --i >= 0;) {
  95                router = &trackedrouters[i];
  96                if (trackedrouters[i].ifID == ifID) {
  97                        untimeout(ddp_age_router, (caddr_t)router);
  98                        break;
  99                }
 100        }
 101}
 102
 103
 104void routershutdown()
 105{
 106        register i;
 107
 108        for (i = NROUTERS2TRAK; --i >= 0;) {
 109                register struct routerinfo *router;
 110
 111                router = &trackedrouters[i];
 112                if (INUSE(router)) {
 113                        untimeout(ddp_age_router, (caddr_t) router);
 114                        bzero((caddr_t) router, sizeof(struct routerinfo));
 115                }
 116        }
 117}
 118
 119int router_added  = 0;
 120int router_killed = 0;
 121
 122
 123
 124void trackrouter(ifID, net, node)
 125     register at_ifaddr_t *ifID;
 126     register unsigned short    net;
 127     register unsigned char     node;
 128{
 129        register struct routerinfo *unused = NULL;
 130        register i;
 131
 132        for (i = NROUTERS2TRAK; --i >= 0;) {
 133                register struct routerinfo *router;
 134
 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);
 139                        unused = NULL;
 140                        break;
 141                }
 142                else if (!INUSE(router) && !unused)
 143                        unused = router;
 144        }
 145        if (unused) {
 146                router_added++;
 147
 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);
 153                }
 154                
 155                unused->ifID = ifID;
 156                NET(unused) =  net;
 157                NODE(unused) = node;
 158                ifID->ifRouterState = ROUTER_AROUND;
 159                timeout(ddp_age_router, (caddr_t) unused, 50*SYS_HZ);
 160                
 161                if (NET(ifID) == 0 && NODE(ifID) == 0) {
 162                        NET(ifID) = net;
 163                        NODE(ifID) = node;
 164                }
 165        }
 166}
 167
 168/*
 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.
 173 */
 174void ddp_age_router(deadrouter)
 175     register struct routerinfo *deadrouter;
 176{
 177        register at_ifaddr_t *ourrouter;
 178
 179        atalk_lock();
 180                        
 181        ourrouter = deadrouter->ifID;
 182        if (ourrouter == NULL) {
 183                atalk_unlock();
 184                return;
 185        }
 186        
 187        dPrintf(D_M_RTMP, D_L_INFO, 
 188                ("ddp_age_router called deadrouter=%d:%d\n", NODE(deadrouter), NET(deadrouter)));
 189
 190        router_killed++;
 191
 192        if (NODE(ourrouter) == NODE(deadrouter) && 
 193            NET(ourrouter) == NET(deadrouter)) {
 194                register unsigned long  atrandom = random();
 195                register struct routerinfo *newrouter;
 196                register i;
 197
 198                bzero((caddr_t) deadrouter, sizeof(struct routerinfo));
 199                for (i = NROUTERS2TRAK; --i >= 0;) {
 200                        newrouter = &trackedrouters[(i + atrandom) & (NROUTERS2TRAK-1)];
 201                        if (INUSE(newrouter))
 202                                break;
 203                        else
 204                                newrouter = NULL;
 205                }
 206                if (newrouter) {
 207                        /* Set our router to another on the list and go on with life */
 208                        NET(ourrouter) = NET(newrouter);
 209                        NODE(ourrouter) = NODE(newrouter);
 210                }
 211                else {
 212                        /* from gorouterless() */
 213                        /* We have no other routers. */
 214                        ATTRACE(AT_MID_DDP, AT_SID_TIMERS, AT_LV_WARNING, FALSE,
 215                                "ddp_age_router entry : ARouter = 0x%x, RouterState = 0x%x",
 216                                ATALK_VALUE(ourrouter->ifARouter), ourrouter->ifRouterState, 0);
 217
 218                        switch (ourrouter->ifRouterState) {
 219                        case ROUTER_AROUND :
 220                                /* This is where we lose our cable.
 221                                        Reset router fields and state accordingly. */
 222                                ourrouter->ifARouter.s_net = 0;
 223                                ourrouter->ifARouter.s_node = 0;
 224                                ourrouter->ifThisCableStart = DDP_MIN_NETWORK;
 225                                ourrouter->ifThisCableEnd = DDP_MAX_NETWORK;
 226                                ourrouter->ifRouterState = NO_ROUTER;
 227
 228                                /* Send event to indicate that we've lost our seed router. */
 229                                atalk_post_msg(ourrouter->aa_ifp, KEV_ATALK_ROUTERDOWN, 0, 0);
 230
 231                                zip_control(ourrouter, ZIP_NO_ROUTER);
 232                                break;
 233                        case ROUTER_WARNING :
 234                                /* there was a router that we were ignoring...
 235                                 * now, even that's gone.  But we want to tackle the
 236                                 * case where another router may come up after all
 237                                 * of them have died...
 238                                 */
 239                                ourrouter->ifRouterState = NO_ROUTER;
 240                                break;
 241                        }
 242                }
 243        } else
 244                bzero((caddr_t) deadrouter, sizeof(struct routerinfo));
 245
 246        atalk_unlock();
 247        
 248} /* ddp_age_router */
 249
 250void rtmp_input (mp, ifID)
 251     register gbuf_t *mp;
 252     register at_ifaddr_t *ifID;
 253{
 254        register at_net_al      this_net;
 255        register at_net_al      range_start, range_end;
 256        register at_ddp_t       *ddp = (at_ddp_t *)gbuf_rptr(mp);
 257                                /* NOTE: there is an assumption here that the 
 258                                 * DATA follows the header. */
 259        register at_rtmp        *rtmp = (at_rtmp *)ddp->data;
 260
 261        if (gbuf_type(mp) != MSG_DATA) {
 262                /* If this is a M_ERROR message, DDP is shutting down, 
 263                 * nothing to do here...If it's something else, we don't 
 264                 * understand what it is
 265                 */
 266                gbuf_freem(mp);
 267                return;
 268        }
 269
 270        if (!ifID) {
 271                gbuf_freem(mp);
 272                return;
 273        }
 274        if (gbuf_len(mp) < (DDP_X_HDR_SIZE + sizeof(at_rtmp))) {
 275                gbuf_freem(mp);
 276                return;
 277        }
 278        this_net = ifID->ifThisNode.s_net;
 279        if (rtmp->at_rtmp_id_length  != 8) {
 280                gbuf_freem(mp);
 281                return;
 282        }
 283
 284        {
 285                at_rtmp_tuple *tp;
 286                tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[1]);
 287                range_start = NET_VALUE(tp->at_rtmp_net);
 288                tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[4]);
 289                range_end = NET_VALUE(tp->at_rtmp_net);
 290
 291                if (ifID->ifRouterState == ROUTER_AROUND) {
 292                        if ((ifID->ifThisCableStart == range_start) &&
 293                            (ifID->ifThisCableEnd == range_end)) {
 294                                trackrouter(ifID,
 295                                            NET_VALUE(rtmp->at_rtmp_this_net),
 296                                            rtmp->at_rtmp_id[0]
 297                                            );
 298                        }
 299                } else {
 300                        /* There was no router around earlier, one
 301                         * probably just came up.
 302                         */
 303                        if ((this_net >= DDP_STARTUP_LOW) && 
 304                            (this_net <= DDP_STARTUP_HIGH)) {
 305                                /* we're operating in the startup range,
 306                                 * ignore the presence of router
 307                                 */
 308                                if (ifID->ifRouterState == NO_ROUTER) {
 309                                        dPrintf(D_M_RTMP, D_L_INFO, ("rtmp_input: new router came up, INVALID: net \
 310                                                in startup range.\n"));
 311                                        /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that
 312                                                a new router has come up when we had none before. */
 313                                        trackrouter(ifID,
 314                                                    NET_VALUE(rtmp->at_rtmp_this_net),
 315                                                    rtmp->at_rtmp_id[0]
 316                                                    );
 317                                        ifID->ifRouterState = ROUTER_WARNING;
 318                                        
 319                                        /* This router is invalid. Send event. */
 320                                        atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0);
 321                                }
 322                        } else {
 323                                /* our address
 324                                 * is not in startup range; Is our
 325                                 * address good for the cable??
 326                                 */
 327                                if ((this_net >= range_start) &&
 328                                    (this_net <= range_end)) {
 329                                        /* Our address is in the range
 330                                         * valid for this cable... Note
 331                                         * the router address and then
 332                                         * get ZIP rolling to get the
 333                                         * zone info.
 334                                         */
 335                                        ifID->ifThisCableStart = range_start;
 336                                        ifID->ifThisCableEnd = range_end;
 337
 338                                        /* A seed router that gives us back our cable range came up.
 339                                                It's a valid router and gives us our network back. */
 340                                        atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP, 0, 0);
 341
 342                                        trackrouter(ifID,
 343                                                    NET_VALUE(rtmp->at_rtmp_this_net),
 344                                                    rtmp->at_rtmp_id[0]
 345                                                    );
 346                                        zip_control(ifID, ZIP_LATE_ROUTER);
 347                                } else {
 348                                        /* Our address is not in the
 349                                         * range valid for this cable..
 350                                         * ignore presence of the 
 351                                         * router
 352                                         */
 353                                        if (ifID->ifRouterState == NO_ROUTER) {
 354                                                /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that
 355                                                        a new router has come up when we had none before. */
 356                                                trackrouter(ifID,
 357                                                            NET_VALUE(rtmp->at_rtmp_this_net),
 358                                                            rtmp->at_rtmp_id[0]
 359                                                            );
 360                                                ifID->ifRouterState = ROUTER_WARNING;
 361
 362                                                /* A new seed router came up, but the cable range is different
 363                                                        than what we had before. */
 364                                                atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0);
 365                                        }
 366                                }
 367                        }
 368                }
 369        }
 370
 371        gbuf_freem(mp);
 372        return;
 373}
 374
 375
 376void rtmp_init()
 377{
 378  bzero((caddr_t)trackedrouters, sizeof(struct routerinfo)*NROUTERS2TRAK);
 379}
 380
 381
 382
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.