Annotation of XNU/bsd/netinet/ip_dummynet.c, revision 1.1

1.1     ! root        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) 1998 Luigi Rizzo
        !            24:  *
        !            25:  * Redistribution and use in source forms, with and without modification,
        !            26:  * are permitted provided that this entire comment appears intact.
        !            27:  *
        !            28:  * Redistribution in binary form may occur without any restrictions.
        !            29:  * Obviously, it would be nice if you gave credit where credit is due
        !            30:  * but requiring it would be too onerous.
        !            31:  *
        !            32:  * This software is provided ``AS IS'' without any warranties of any kind.
        !            33:  *
        !            34:  */
        !            35: 
        !            36: /*
        !            37:  * This module implements IP dummynet, a bandwidth limiter/delay emulator
        !            38:  * used in conjunction with the ipfw package.
        !            39:  *
        !            40:  * Changes:
        !            41:  *
        !            42:  * 980821: changed conventions in the queueing logic
        !            43:  *     packets passed from dummynet to ip_in/out are prepended with
        !            44:  *     a vestigial mbuf type MT_DUMMYNET which contains a pointer
        !            45:  *     to the matching rule.
        !            46:  *     ip_input/output will extract the parameters, free the vestigial mbuf,
        !            47:  *     and do the processing.
        !            48:  *     
        !            49:  * 980519:     fixed behaviour when deleting rules.
        !            50:  * 980518:     added splimp()/splx() to protect against races
        !            51:  * 980513:     initial release
        !            52:  */
        !            53: 
        !            54: /* include files marked with XXX are probably not needed */
        !            55: 
        !            56: #include <sys/param.h>
        !            57: #include <sys/systm.h>
        !            58: #include <sys/malloc.h>
        !            59: #include <sys/mbuf.h>
        !            60: #include <sys/queue.h>                 /* XXX */
        !            61: #include <sys/kernel.h>
        !            62: #include <sys/socket.h>
        !            63: #include <sys/socketvar.h>
        !            64: #include <sys/time.h>
        !            65: #include <sys/sysctl.h>
        !            66: #include <net/if.h>
        !            67: #include <net/route.h>
        !            68: #include <netinet/in.h>
        !            69: #include <netinet/in_systm.h>
        !            70: #include <netinet/in_var.h>
        !            71: #include <netinet/ip.h>
        !            72: #include <netinet/ip_fw.h>
        !            73: #include <netinet/ip_dummynet.h>
        !            74: #include <netinet/ip_var.h>
        !            75: 
        !            76: #if BRIDGE
        !            77: #include <netinet/if_ether.h> /* for struct arpcom */
        !            78: #include <net/bridge.h>
        !            79: #endif
        !            80: 
        !            81: static struct dn_pipe *all_pipes = NULL ;      /* list of all pipes */
        !            82: 
        !            83: static int dn_debug = 0 ;                      /* verbose */
        !            84: static int dn_calls = 0 ;                      /* number of calls */
        !            85: static int dn_idle = 1;
        !            86: #ifdef SYSCTL_NODE
        !            87: SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
        !            88: SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, &dn_debug, 0, "");
        !            89: SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, calls, CTLFLAG_RD, &dn_calls, 0, "");
        !            90: SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, idle, CTLFLAG_RD, &dn_idle, 0, "");
        !            91: #endif
        !            92: 
        !            93: static int ip_dn_ctl(struct sockopt *sopt);
        !            94: 
        !            95: static void rt_unref(struct rtentry *);
        !            96: static void dummynet(void *);
        !            97: static void dn_restart(void);
        !            98: static void dn_move(struct dn_pipe *pipe, int immediate);
        !            99: static void dummynet_flush(void);
        !           100: 
        !           101: /*
        !           102:  * the following is needed when deleting a pipe, because rules can
        !           103:  * hold references to the pipe.
        !           104:  */
        !           105: extern LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
        !           106: 
        !           107: /*
        !           108:  * invoked to reschedule the periodic task if necessary.
        !           109:  * Should only be called when dn_idle = 1 ;
        !           110:  */
        !           111: static void
        !           112: dn_restart()
        !           113: {
        !           114:     struct dn_pipe *pipe;
        !           115: 
        !           116:     if (!dn_idle)
        !           117:        return;
        !           118:        
        !           119:     for (pipe = all_pipes ; pipe ; pipe = pipe->next ) {
        !           120:        /* if there any pipe that needs work, restart */
        !           121:        if (pipe->r.head || pipe->p.head || pipe->numbytes < 0 ) {
        !           122:            dn_idle = 0;
        !           123:            timeout(dummynet, NULL, 1);
        !           124:            return ;
        !           125:        }
        !           126:     }
        !           127: }
        !           128: 
        !           129: static void
        !           130: rt_unref(struct rtentry *rt)
        !           131: {
        !           132:     if (rt == NULL)
        !           133:        return ;
        !           134:     if (rt->rt_refcnt <= 0)
        !           135:        printf("-- warning, refcnt now %d, decreasing\n", rt->rt_refcnt);
        !           136:     RTFREE(rt);
        !           137: }
        !           138: 
        !           139: /*
        !           140:  * move packets from R-queue to P-queue
        !           141:  */
        !           142: static void
        !           143: dn_move(struct dn_pipe *pipe, int immediate)
        !           144: {
        !           145:     struct dn_pkt *pkt;
        !           146:  
        !           147:     /*
        !           148:      * consistency check, should catch new pipes which are
        !           149:      * not initialized properly.
        !           150:      */
        !           151:     if ( pipe->p.head == NULL &&
        !           152:                pipe->ticks_from_last_insert != pipe->delay) {
        !           153:        printf("Warning, empty pipe and delay %d (should be %d)\n",
        !           154:                pipe->ticks_from_last_insert, pipe->delay);
        !           155:        pipe->ticks_from_last_insert = pipe->delay;
        !           156:     }
        !           157:     /* this ought to go in dn_dequeue() */
        !           158:     if (!immediate && pipe->ticks_from_last_insert < pipe->delay)
        !           159:        pipe->ticks_from_last_insert++;
        !           160:     if ( pkt = pipe->r.head ) {
        !           161:        /*
        !           162:         * Move at most numbytes bytes from src and move to dst.
        !           163:         * delay is set to ticks_from_last_insert, which
        !           164:         * is reset after the first insertion;
        !           165:         */
        !           166:        while ( pkt ) {
        !           167:            struct ip *ip=mtod(pkt->dn_m, struct ip *);
        !           168: 
        !           169:            /*
        !           170:             * queue limitation: pass packets down if the len is
        !           171:             * such that the pkt would go out before the next tick.
        !           172:             */
        !           173:            if (pipe->bandwidth) {
        !           174:                if (pipe->numbytes < ip->ip_len)
        !           175:                    break;
        !           176:                pipe->numbytes -= ip->ip_len;
        !           177:            }
        !           178:            pipe->r_len--; /* elements in queue */
        !           179:            pipe->r_len_bytes -= ip->ip_len ;
        !           180: 
        !           181:            /*
        !           182:             * to add delay jitter, must act here. A lower value
        !           183:             * (bounded to 0) means lower delay.
        !           184:             */
        !           185:            pkt->delay = pipe->ticks_from_last_insert;
        !           186:            pipe->ticks_from_last_insert = 0;
        !           187:            /* compensate the decrement done next in dn_dequeue */
        !           188:            if (!immediate && pkt->delay >0 && pipe->p.head==NULL)
        !           189:                pkt->delay++;
        !           190:            if (pipe->p.head == NULL)
        !           191:                pipe->p.head = pkt;
        !           192:            else
        !           193:                (struct dn_pkt *)pipe->p.tail->dn_next = pkt;
        !           194:            pipe->p.tail = pkt;
        !           195:            pkt = (struct dn_pkt *)pkt->dn_next;
        !           196:            pipe->p.tail->dn_next = NULL;
        !           197:        }
        !           198:        pipe->r.head = pkt;
        !           199:  
        !           200:        /*** XXX just a sanity check */
        !           201:        if ( ( pkt == NULL && pipe->r_len != 0) ||
        !           202:             ( pkt != NULL && pipe->r_len == 0) )
        !           203:            printf("-- Warning, pipe head %p len %d\n",
        !           204:                    (void *)pkt, pipe->r_len);
        !           205:     }
        !           206:  
        !           207:     /*
        !           208:      * deliver packets downstream after the delay in the P-queue.
        !           209:      */
        !           210: 
        !           211:     if (pipe->p.head == NULL)
        !           212:        return;
        !           213:     if (!immediate)
        !           214:        pipe->p.head->delay--;
        !           215:     while ( (pkt = pipe->p.head) && pkt->delay < 1) {
        !           216:        /*
        !           217:         * first unlink, then call procedures since ip_input()
        !           218:         * can result in a call to ip_output cnd viceversa,
        !           219:         * thus causing nested calls
        !           220:         */
        !           221:        pipe->p.head = (struct dn_pkt *) pkt->dn_next ;
        !           222: 
        !           223:        /*
        !           224:         * the trick to avoid flow-id settings here is to prepend a
        !           225:         * vestigial mbuf to the packet, with the following values:
        !           226:         * m_type = MT_DUMMYNET
        !           227:         * m_next = the actual mbuf to be processed by ip_input/output
        !           228:         * m_data = the matching rule
        !           229:         * The vestigial element is the same memory area used by
        !           230:         * the dn_pkt, and IS FREED IN ip_input/ip_output. IT IS
        !           231:         * NOT A REAL MBUF, just a block of memory acquired with malloc().
        !           232:         */
        !           233:        switch (pkt->dn_dir) {
        !           234:        case DN_TO_IP_OUT: {
        !           235:            struct rtentry *tmp_rt = pkt->ro.ro_rt ;
        !           236: 
        !           237:            (void)ip_output((struct mbuf *)pkt, (struct mbuf *)pkt->ifp,
        !           238:                        &(pkt->ro), pkt->dn_hlen, NULL);
        !           239:            rt_unref (tmp_rt) ;
        !           240:            }
        !           241:            break ;
        !           242:        case DN_TO_IP_IN :
        !           243:            ip_input((struct mbuf *)pkt) ;
        !           244:            break ;
        !           245: #if BRIDGE
        !           246:        case DN_TO_BDG_FWD :
        !           247:            bdg_forward((struct mbuf **)&pkt, pkt->ifp);
        !           248:            break ;
        !           249: #endif
        !           250:        default:
        !           251:            printf("dummynet: bad switch %d!\n", pkt->dn_dir);
        !           252:            m_freem(pkt->dn_m);
        !           253:            FREE(pkt, M_IPFW);
        !           254:            break ;
        !           255:        }
        !           256:     }
        !           257: }
        !           258: /*
        !           259:  * this is the periodic task that moves packets between the R-
        !           260:  * and the P- queue
        !           261:  */
        !           262: /*ARGSUSED*/
        !           263: void
        !           264: dummynet(void * __unused unused)
        !           265: {
        !           266:     struct dn_pipe *p ;
        !           267:     int s ;
        !           268: 
        !           269:     dn_calls++ ;
        !           270:     for (p = all_pipes ; p ; p = p->next ) {
        !           271:        /*
        !           272:         * Increment the amount of data that can be sent. However,
        !           273:         * don't do that if the channel is idle
        !           274:         * (r.head == NULL && numbytes >= bandwidth).
        !           275:         * This bug fix is from tim shepard ([email protected])
        !           276:         */
        !           277:         s = splimp();
        !           278:        if (p->r.head != NULL || p->numbytes < p->bandwidth )
        !           279:                p->numbytes += p->bandwidth ;
        !           280:        dn_move(p, 0); /* is it really 0 (also below) ? */
        !           281:        splx(s);
        !           282:     }
        !           283:  
        !           284:     /*
        !           285:      * finally, if some queue has data, restart the timer.
        !           286:      */
        !           287:     dn_idle = 1;
        !           288:     dn_restart();
        !           289: }
        !           290: 
        !           291: /*
        !           292:  * dummynet hook for packets.
        !           293:  * input and output use the same code, so i use bit 16 in the pipe
        !           294:  * number to chose the direction: 1 for output packets, 0 for input.
        !           295:  * for input, only m is significant. For output, also the others.
        !           296:  */
        !           297: int
        !           298: dummynet_io(int pipe_nr, int dir,
        !           299:        struct mbuf *m, struct ifnet *ifp, struct route *ro, int hlen,
        !           300:        struct ip_fw_chain *rule)
        !           301: {
        !           302:     struct dn_pkt *pkt;
        !           303:     struct dn_pipe *pipe;
        !           304:     struct ip *ip=mtod(m, struct ip *);
        !           305: 
        !           306:     int s=splimp();
        !           307: 
        !           308:     pipe_nr &= 0xffff ;
        !           309:     /*
        !           310:      * locate pipe. First time is expensive, next have direct access.
        !           311:      */
        !           312: 
        !           313:     if ( (pipe = rule->rule->pipe_ptr) == NULL ) {
        !           314:        for (pipe=all_pipes; pipe && pipe->pipe_nr !=pipe_nr; pipe=pipe->next)
        !           315:            ;
        !           316:        if (pipe == NULL) {
        !           317:            splx(s);
        !           318:            if (dn_debug)
        !           319:                printf("warning, pkt for no pipe %d\n", pipe_nr);
        !           320:            m_freem(m);
        !           321:            return 0 ;
        !           322:        } else
        !           323:            rule->rule->pipe_ptr = pipe ;
        !           324:     }
        !           325:  
        !           326:     /*
        !           327:      * should i drop ?
        !           328:      * This section implements random packet drop.
        !           329:      */
        !           330:     if ( (pipe->plr && random() < pipe->plr) ||
        !           331:          (pipe->queue_size && pipe->r_len >= pipe->queue_size) ||
        !           332:          (pipe->queue_size_bytes &&
        !           333:            ip->ip_len + pipe->r_len_bytes > pipe->queue_size_bytes) ||
        !           334:                (pkt = (struct dn_pkt *) _MALLOC(sizeof (*pkt),
        !           335:                        M_IPFW, M_NOWAIT) ) == NULL ) {
        !           336:        splx(s);
        !           337:        if (dn_debug)
        !           338:            printf("-- dummynet: drop from pipe %d, have %d pks, %d bytes\n",
        !           339:                pipe_nr,  pipe->r_len, pipe->r_len_bytes);
        !           340:        pipe->r_drops++ ;
        !           341:        m_freem(m);
        !           342:        return 0 ; /* XXX error */
        !           343:     }
        !           344:     bzero(pkt, sizeof(*pkt) );
        !           345:     /* build and enqueue packet */
        !           346:     pkt->hdr.mh_type = MT_DUMMYNET ;
        !           347:     (struct ip_fw_chain *)pkt->hdr.mh_data = rule ;
        !           348:     pkt->dn_next = NULL;
        !           349:     pkt->dn_m = m;
        !           350:     pkt->dn_dir = dir ;
        !           351:     pkt->delay = 0;
        !           352: 
        !           353:     pkt->ifp = ifp;
        !           354:     if (dir == DN_TO_IP_OUT) {
        !           355:        pkt->ro = *ro; /* XXX copied! */
        !           356:        if (ro->ro_rt)
        !           357:            ro->ro_rt->rt_refcnt++ ; /* XXX */
        !           358:     }
        !           359:     pkt->dn_hlen = hlen;
        !           360:     if (pipe->r.head == NULL)
        !           361:        pipe->r.head = pkt;
        !           362:     else
        !           363:        (struct dn_pkt *)pipe->r.tail->dn_next = pkt;
        !           364:     pipe->r.tail = pkt;
        !           365:     pipe->r_len++;
        !           366:     pipe->r_len_bytes += ip->ip_len ;
        !           367: 
        !           368:     /* 
        !           369:      * here we could implement RED if we like to
        !           370:      */
        !           371: 
        !           372:     if (pipe->r.head == pkt) {       /* process immediately */
        !           373:         dn_move(pipe, 1);
        !           374:     }
        !           375:     splx(s);
        !           376:     if (dn_idle)
        !           377:        dn_restart();
        !           378:     return 0;
        !           379: }
        !           380: 
        !           381: /*
        !           382:  * dispose all packets queued on a pipe
        !           383:  */
        !           384: static void
        !           385: purge_pipe(struct dn_pipe *pipe)
        !           386: {
        !           387:     struct dn_pkt *pkt, *n ;
        !           388:     struct rtentry *tmp_rt ;
        !           389: 
        !           390:     for (pkt = pipe->r.head ; pkt ; ) {
        !           391:        rt_unref (tmp_rt = pkt->ro.ro_rt ) ;
        !           392:        m_freem(pkt->dn_m);
        !           393:        n = pkt ;
        !           394:        pkt = (struct dn_pkt *)pkt->dn_next ;
        !           395:        FREE(n, M_IPFW) ;
        !           396:     }
        !           397:     for (pkt = pipe->p.head ; pkt ; ) {
        !           398:        rt_unref (tmp_rt = pkt->ro.ro_rt ) ;
        !           399:        m_freem(pkt->dn_m);
        !           400:        n = pkt ;
        !           401:        pkt = (struct dn_pkt *)pkt->dn_next ;
        !           402:        FREE(n, M_IPFW) ;
        !           403:     }
        !           404: }
        !           405: 
        !           406: /*
        !           407:  * delete all pipes returning memory
        !           408:  */
        !           409: static void
        !           410: dummynet_flush()
        !           411: {
        !           412:     struct dn_pipe *q, *p = all_pipes ;
        !           413:     int s = splnet() ;
        !           414: 
        !           415:     all_pipes = NULL ;
        !           416:     splx(s) ;
        !           417:     /*
        !           418:      * purge all queued pkts and delete all pipes
        !           419:      */
        !           420:     for ( ; p ; ) {
        !           421:        purge_pipe(p);
        !           422:        q = p ;
        !           423:        p = p->next ;   
        !           424:        FREE(q, M_IPFW);
        !           425:     }
        !           426: }
        !           427: 
        !           428: extern struct ip_fw_chain *ip_fw_default_rule ;
        !           429: /*
        !           430:  * when a firewall rule is deleted, scan all pipes and remove the flow-id
        !           431:  * from packets matching this rule.
        !           432:  */
        !           433: void
        !           434: dn_rule_delete(void *r)
        !           435: {
        !           436:     struct dn_pipe *p ;
        !           437:     int matches = 0 ;
        !           438: 
        !           439:     for ( p = all_pipes ; p ; p = p->next ) {
        !           440:        struct dn_pkt *x ;
        !           441:        for (x = p->r.head ; x ; x = (struct dn_pkt *)x->dn_next )
        !           442:            if (x->hdr.mh_data == r) {
        !           443:                matches++ ;
        !           444:                x->hdr.mh_data = (void *)ip_fw_default_rule ;
        !           445:            }
        !           446:        for (x = p->p.head ; x ; x = (struct dn_pkt *)x->dn_next )
        !           447:            if (x->hdr.mh_data == r) {
        !           448:                matches++ ;
        !           449:                x->hdr.mh_data = (void *)ip_fw_default_rule ;
        !           450:            }
        !           451:     }
        !           452:     printf("dn_rule_delete, r %p, default %p%s, %d matches\n",
        !           453:            (void *)r, (void *)ip_fw_default_rule,
        !           454:            r == ip_fw_default_rule ? "  AARGH!":"",  matches);
        !           455: }
        !           456: 
        !           457: /*
        !           458:  * handler for the various dummynet socket options
        !           459:  * (get, flush, config, del)
        !           460:  */
        !           461: static int
        !           462: ip_dn_ctl(struct sockopt *sopt)
        !           463: {
        !           464:     int error = 0 ;
        !           465:     size_t size ;
        !           466:     char *buf, *bp ;
        !           467:     struct dn_pipe *p, tmp_pipe ;
        !           468: 
        !           469:     struct dn_pipe *x, *a, *b ;
        !           470: 
        !           471:     /* Disallow sets in really-really secure mode. */
        !           472:     if (sopt->sopt_dir == SOPT_SET && securelevel >= 3)
        !           473:        return (EPERM);
        !           474: 
        !           475:     switch (sopt->sopt_name) {
        !           476:     default :
        !           477:        panic("ip_dn_ctl -- unknown option");
        !           478: 
        !           479:     case IP_DUMMYNET_GET :
        !           480:        for (p = all_pipes, size = 0 ; p ; p = p->next )
        !           481:            size += sizeof( *p ) ;
        !           482:        buf = _MALLOC(size, M_TEMP, M_WAITOK);
        !           483:        if (buf == 0) {
        !           484:            error = ENOBUFS ;
        !           485:            break ;
        !           486:        }
        !           487:        for (p = all_pipes, bp = buf ; p ; p = p->next ) {
        !           488:            struct dn_pipe *q = (struct dn_pipe *)bp ;
        !           489: 
        !           490:            bcopy(p, bp, sizeof( *p ) );
        !           491:                /*
        !           492:                 * return bw and delay in bits/s and ms, respectively
        !           493:                 */
        !           494:                q->bandwidth *= (8*hz) ;
        !           495:                q->delay = (q->delay * 1000) / hz ;
        !           496:            bp += sizeof( *p ) ;
        !           497:        }
        !           498:        error = sooptcopyout(sopt, buf, size);
        !           499:        FREE(buf, M_TEMP);
        !           500:        break ;
        !           501:     case IP_DUMMYNET_FLUSH :
        !           502:            dummynet_flush() ;
        !           503:        break ;
        !           504:     case IP_DUMMYNET_CONFIGURE :
        !           505:        p = &tmp_pipe ;
        !           506:        error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
        !           507:        if (error)
        !           508:            break ;
        !           509:            /*
        !           510:             * The config program passes parameters as follows:
        !           511:             * bandwidth = bits/second (0 = no limits);
        !           512:             *    must be translated in bytes/tick.
        !           513:             * delay = ms
        !           514:             *    must be translated in ticks.
        !           515:             * queue_size = slots (0 = no limit)
        !           516:             * queue_size_bytes = bytes (0 = no limit)
        !           517:             *    only one can be set, must be bound-checked
        !           518:             */
        !           519:            if ( p->bandwidth > 0 ) {
        !           520:                p->bandwidth = p->bandwidth / 8 / hz ;
        !           521:                if (p->bandwidth == 0)  /* too little does not make sense! */
        !           522:                        p->bandwidth = 10 ;
        !           523:            }
        !           524:            p->delay = ( p->delay * hz ) / 1000 ;
        !           525:            if (p->queue_size == 0 && p->queue_size_bytes == 0)
        !           526:                p->queue_size = 100 ;
        !           527:            if (p->queue_size != 0 )    /* buffers are prevailing */
        !           528:                p->queue_size_bytes = 0 ;
        !           529:            if (p->queue_size > 100)
        !           530:                p->queue_size = 100 ;
        !           531:            if (p->queue_size_bytes > 1024*1024)
        !           532:                p->queue_size_bytes = 1024*1024 ;
        !           533: #if 0
        !           534:            printf("ip_dn: config pipe %d %d bit/s %d ms %d bufs\n",
        !           535:                p->pipe_nr,
        !           536:                p->bandwidth * 8 * hz ,
        !           537:                p->delay * 1000 / hz , p->queue_size);
        !           538: #endif
        !           539:            for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
        !           540:                 a = b , b = b->next) ;
        !           541:            if (b && b->pipe_nr == p->pipe_nr) {
        !           542:                /* XXX should spl and flush old pipe... */
        !           543:                b->bandwidth = p->bandwidth ;
        !           544:                b->delay = p->delay ;
        !           545:                b->ticks_from_last_insert = p->delay ;
        !           546:                b->queue_size = p->queue_size ;
        !           547:                b->queue_size_bytes = p->queue_size_bytes ;
        !           548:                b->plr = p->plr ;
        !           549:            } else {
        !           550:                int s ;
        !           551:                x = _MALLOC(sizeof(struct dn_pipe), M_IPFW, M_DONTWAIT) ;
        !           552:                if (x == NULL) {
        !           553:                    printf("ip_dummynet.c: sorry no memory\n");
        !           554:                error = ENOSPC ;
        !           555:                break ;
        !           556:                }
        !           557:                bzero(x, sizeof(*x) );
        !           558:                x->bandwidth = p->bandwidth ;
        !           559:                x->delay = p->delay ;
        !           560:                x->ticks_from_last_insert = p->delay ;
        !           561:                x->pipe_nr = p->pipe_nr ;
        !           562:                x->queue_size = p->queue_size ;
        !           563:                x->queue_size_bytes = p->queue_size_bytes ;
        !           564:                x->plr = p->plr ;
        !           565: 
        !           566:                s = splnet() ;
        !           567:                x->next = b ;
        !           568:                if (a == NULL)
        !           569:                    all_pipes = x ;
        !           570:                else
        !           571:                    a->next = x ;
        !           572:                splx(s);
        !           573:            }
        !           574:        break ;
        !           575: 
        !           576:     case IP_DUMMYNET_DEL :
        !           577:        p = &tmp_pipe ;
        !           578:        error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
        !           579:        if (error)
        !           580:            break ;
        !           581: 
        !           582:            for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
        !           583:                 a = b , b = b->next) ;
        !           584:            if (b && b->pipe_nr == p->pipe_nr) {        /* found pipe */
        !           585:                int s = splnet() ;
        !           586:                struct ip_fw_chain *chain = ip_fw_chain.lh_first;
        !           587: 
        !           588:                if (a == NULL)
        !           589:                    all_pipes = b->next ;
        !           590:                else
        !           591:                    a->next = b->next ;
        !           592:                /*
        !           593:                 * remove references to this pipe from the ip_fw rules.
        !           594:                 */
        !           595:                for (; chain; chain = chain->chain.le_next) {
        !           596:                    register struct ip_fw *const f = chain->rule;
        !           597:                    if (f->pipe_ptr == b)
        !           598:                        f->pipe_ptr = NULL ;
        !           599:                }
        !           600:                splx(s);
        !           601:                purge_pipe(b);  /* remove pkts from here */
        !           602:                FREE(b, M_IPFW);
        !           603:            }
        !           604:        break ;
        !           605:        }
        !           606:     return error ;
        !           607: }
        !           608: 
        !           609: void
        !           610: ip_dn_init(void)
        !           611: {
        !           612:     printf("DUMMYNET initialized (980901) -- size dn_pkt %d\n",
        !           613:        sizeof(struct dn_pkt));
        !           614:     all_pipes = NULL ;
        !           615:     ip_dn_ctl_ptr = ip_dn_ctl;
        !           616: }
        !           617: 
        !           618: #if DUMMYNET_MODULE
        !           619: 
        !           620: #include <sys/exec.h>
        !           621: #include <sys/sysent.h>
        !           622: #include <sys/lkm.h>
        !           623: 
        !           624: MOD_MISC(dummynet);
        !           625: 
        !           626: static ip_dn_ctl_t *old_dn_ctl_ptr ;
        !           627: 
        !           628: static int
        !           629: dummynet_load(struct lkm_table *lkmtp, int cmd)
        !           630: {
        !           631:        int s=splnet();
        !           632:        old_dn_ctl_ptr = ip_dn_ctl_ptr;
        !           633:        ip_dn_init();
        !           634:        splx(s);
        !           635:        return 0;
        !           636: }
        !           637: 
        !           638: static int
        !           639: dummynet_unload(struct lkm_table *lkmtp, int cmd)
        !           640: {
        !           641:        int s=splnet();
        !           642:        ip_dn_ctl_ptr =  old_dn_ctl_ptr;
        !           643:        splx(s);
        !           644:        dummynet_flush();
        !           645:        printf("DUMMYNET unloaded\n");
        !           646:        return 0;
        !           647: }
        !           648: 
        !           649: int
        !           650: dummynet_mod(struct lkm_table *lkmtp, int cmd, int ver)
        !           651: {
        !           652:     DISPATCH(lkmtp, cmd, ver, dummynet_load, dummynet_unload, lkm_nullcmd);
        !           653: }
        !           654: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.