Changeset 904 in MondoRescue for trunk/mindi-busybox/networking/zcip.c


Ignore:
Timestamp:
Oct 25, 2006, 1:51:57 AM (17 years ago)
Author:
Bruno Cornec
Message:

merge -r890:902 $SVN_M/branches/stable

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/mindi-busybox/networking/zcip.c

    r821 r904  
    1515 */
    1616
    17 // #define      DEBUG
     17//#define DEBUG
    1818
    1919// TODO:
     
    4343struct arp_packet {
    4444    struct ether_header hdr;
    45     // FIXME this part is netinet/if_ether.h "struct ether_arp"
    46     struct arphdr arp;
    47     struct ether_addr source_addr;
    48     struct in_addr source_ip;
    49     struct ether_addr target_addr;
    50     struct in_addr target_ip;
     45    struct ether_arp arp;
    5146} ATTRIBUTE_PACKED;
    5247
     
    6863};
    6964
    70 static const struct in_addr null_ip = { 0 };
    71 static const struct ether_addr null_addr = { {0, 0, 0, 0, 0, 0} };
    72 
    73 static int verbose = 0;
     65/* States during the configuration process. */
     66enum {
     67    PROBE = 0,
     68    RATE_LIMIT_PROBE,
     69    ANNOUNCE,
     70    MONITOR,
     71    DEFEND
     72};
     73
     74/* Implicitly zero-initialized */
     75static const struct in_addr null_ip;
     76static const struct ether_addr null_addr;
     77static int verbose;
    7478
    7579#define DBG(fmt,args...) \
     
    100104{
    101105    struct arp_packet p;
     106    memset(&p, 0, sizeof(p));
    102107
    103108    // ether header
     
    107112
    108113    // arp request
    109     p.arp.ar_hrd = htons(ARPHRD_ETHER);
    110     p.arp.ar_pro = htons(ETHERTYPE_IP);
    111     p.arp.ar_hln = ETH_ALEN;
    112     p.arp.ar_pln = 4;
    113     p.arp.ar_op = htons(op);
    114     memcpy(&p.source_addr, source_addr, ETH_ALEN);
    115     memcpy(&p.source_ip, &source_ip, sizeof (p.source_ip));
    116     memcpy(&p.target_addr, target_addr, ETH_ALEN);
    117     memcpy(&p.target_ip, &target_ip, sizeof (p.target_ip));
     114    p.arp.arp_hrd = htons(ARPHRD_ETHER);
     115    p.arp.arp_pro = htons(ETHERTYPE_IP);
     116    p.arp.arp_hln = ETH_ALEN;
     117    p.arp.arp_pln = 4;
     118    p.arp.arp_op = htons(op);
     119    memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN);
     120    memcpy(&p.arp.arp_spa, &source_ip, sizeof (p.arp.arp_spa));
     121    memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN);
     122    memcpy(&p.arp.arp_tpa, &target_ip, sizeof (p.arp.arp_tpa));
    118123
    119124    // send it
     
    196201    int ready = 0;
    197202    suseconds_t timeout = 0;    // milliseconds
    198     time_t defend = 0;
    199203    unsigned conflicts = 0;
    200204    unsigned nprobes = 0;
    201205    unsigned nclaims = 0;
    202206    int t;
     207    int state = PROBE;
    203208
    204209    // parse commandline: prog [options] ifname script
     
    307312        fds[0].revents = 0;
    308313
     314        int source_ip_conflict = 0;
     315        int target_ip_conflict = 0;
     316
    309317        // poll, being ready to adjust current timeout
    310318        if (!timeout) {
     
    314322            // ones we'd care about.
    315323        }
     324        // set tv1 to the point in time when we timeout
    316325        gettimeofday(&tv1, NULL);
    317326        tv1.tv_usec += (timeout % 1000) * 1000;
     
    326335        switch (poll(fds, 1, timeout)) {
    327336
    328         // timeouts trigger protocol transitions
     337        // timeout
    329338        case 0:
    330             // probes
    331             if (nprobes < PROBE_NUM) {
    332                 nprobes++;
    333                 VDBG("probe/%d %s@%s\n",
    334                         nprobes, intf, inet_ntoa(ip));
    335                 (void)arp(fd, &saddr, ARPOP_REQUEST,
    336                         &addr, null_ip,
    337                         &null_addr, ip);
     339            VDBG("state = %d\n", state);
     340            switch (state) {
     341            case PROBE:
     342                // timeouts in the PROBE state means no conflicting ARP packets
     343                // have been received, so we can progress through the states
    338344                if (nprobes < PROBE_NUM) {
     345                    nprobes++;
     346                    VDBG("probe/%d %s@%s\n",
     347                            nprobes, intf, inet_ntoa(ip));
     348                    (void)arp(fd, &saddr, ARPOP_REQUEST,
     349                            &addr, null_ip,
     350                            &null_addr, ip);
    339351                    timeout = PROBE_MIN * 1000;
    340352                    timeout += ms_rdelay(PROBE_MAX
    341353                            - PROBE_MIN);
    342                 } else
    343                     timeout = ANNOUNCE_WAIT * 1000;
    344             }
    345             // then announcements
    346             else if (nclaims < ANNOUNCE_NUM) {
    347                 nclaims++;
     354                }
     355                else {
     356                    // Switch to announce state.
     357                    state = ANNOUNCE;
     358                    nclaims = 0;
     359                    VDBG("announce/%d %s@%s\n",
     360                            nclaims, intf, inet_ntoa(ip));
     361                    (void)arp(fd, &saddr, ARPOP_REQUEST,
     362                            &addr, ip,
     363                            &addr, ip);
     364                    timeout = ANNOUNCE_INTERVAL * 1000;
     365                }
     366                break;
     367            case RATE_LIMIT_PROBE:
     368                // timeouts in the RATE_LIMIT_PROBE state means no conflicting ARP packets
     369                // have been received, so we can move immediately to the announce state
     370                state = ANNOUNCE;
     371                nclaims = 0;
    348372                VDBG("announce/%d %s@%s\n",
    349373                        nclaims, intf, inet_ntoa(ip));
     
    351375                        &addr, ip,
    352376                        &addr, ip);
     377                timeout = ANNOUNCE_INTERVAL * 1000;
     378                break;
     379            case ANNOUNCE:
     380                // timeouts in the ANNOUNCE state means no conflicting ARP packets
     381                // have been received, so we can progress through the states
    353382                if (nclaims < ANNOUNCE_NUM) {
     383                    nclaims++;
     384                    VDBG("announce/%d %s@%s\n",
     385                            nclaims, intf, inet_ntoa(ip));
     386                    (void)arp(fd, &saddr, ARPOP_REQUEST,
     387                            &addr, ip,
     388                            &addr, ip);
    354389                    timeout = ANNOUNCE_INTERVAL * 1000;
    355                 } else {
     390                }
     391                else {
     392                    // Switch to monitor state.
     393                    state = MONITOR;
    356394                    // link is ok to use earlier
     395                    // FIXME update filters
    357396                    run(script, "config", intf, &ip);
    358397                    ready = 1;
    359398                    conflicts = 0;
    360                     timeout = -1;
     399                    timeout = -1; // Never timeout in the monitor state.
    361400
    362401                    // NOTE:  all other exit paths
     
    364403                    if (quit)
    365404                        return EXIT_SUCCESS;
    366                     // FIXME update filters
    367                 }
    368             }
    369             break;
    370 
     405                }
     406                break;
     407            case DEFEND:
     408                // We won!  No ARP replies, so just go back to monitor.
     409                state = MONITOR;
     410                timeout = -1;
     411                conflicts = 0;
     412                break;
     413            default:
     414                // Invalid, should never happen.  Restart the whole protocol.
     415                state = PROBE;
     416                pick(&ip);
     417                timeout = 0;
     418                nprobes = 0;
     419                nclaims = 0;
     420                break;
     421            } // switch (state)
     422            break; // case 0 (timeout)
    371423        // packets arriving
    372424        case 1:
    373             // maybe adjust timeout
     425            // We need to adjust the timeout in case we didn't receive
     426            // a conflicting packet.
    374427            if (timeout > 0) {
    375428                struct timeval tv2;
     
    377430                gettimeofday(&tv2, NULL);
    378431                if (timercmp(&tv1, &tv2, <)) {
     432                    // Current time is greater than the expected timeout time.
     433                    // Should never happen.
     434                    VDBG("missed an expected timeout\n");
    379435                    timeout = 0;
    380436                } else {
     437                    VDBG("adjusting timeout\n");
    381438                    timersub(&tv1, &tv2, &tv1);
    382439                    timeout = 1000 * tv1.tv_sec
     
    384441                }
    385442            }
     443
    386444            if ((fds[0].revents & POLLIN) == 0) {
    387445                if (fds[0].revents & POLLERR) {
     
    397455                continue;
    398456            }
     457
    399458            // read ARP packet
    400459            if (recv(fd, &p, sizeof (p), 0) < 0) {
     
    405464                continue;
    406465
    407             VDBG("%s recv arp type=%d, op=%d,\n",
     466#ifdef DEBUG
     467            {
     468                struct ether_addr * sha = (struct ether_addr *) p.arp.arp_sha;
     469                struct ether_addr * tha = (struct ether_addr *) p.arp.arp_tha;
     470                struct in_addr * spa = (struct in_addr *) p.arp.arp_spa;
     471                struct in_addr * tpa = (struct in_addr *) p.arp.arp_tpa;
     472                VDBG("%s recv arp type=%d, op=%d,\n",
    408473                    intf, ntohs(p.hdr.ether_type),
    409                     ntohs(p.arp.ar_op));
    410             VDBG("\tsource=%s %s\n",
    411                     ether_ntoa(&p.source_addr),
    412                     inet_ntoa(p.source_ip));
    413             VDBG("\ttarget=%s %s\n",
    414                     ether_ntoa(&p.target_addr),
    415                     inet_ntoa(p.target_ip));
    416             if (p.arp.ar_op != htons(ARPOP_REQUEST)
    417                     && p.arp.ar_op != htons(ARPOP_REPLY))
     474                    ntohs(p.arp.arp_op));
     475                VDBG("\tsource=%s %s\n",
     476                    ether_ntoa(sha),
     477                    inet_ntoa(*spa));
     478                VDBG("\ttarget=%s %s\n",
     479                    ether_ntoa(tha),
     480                    inet_ntoa(*tpa));
     481            }
     482#endif
     483            if (p.arp.arp_op != htons(ARPOP_REQUEST)
     484                    && p.arp.arp_op != htons(ARPOP_REPLY))
    418485                continue;
    419486
    420             // some cases are always conflicts
    421             if ((p.source_ip.s_addr == ip.s_addr)
    422                     && (memcmp(&addr, &p.source_addr,
    423                             ETH_ALEN) != 0)) {
    424 collision:
    425                 VDBG("%s ARP conflict from %s\n", intf,
    426                         ether_ntoa(&p.source_addr));
    427                 if (ready) {
    428                     time_t now = time(0);
    429 
    430                     if ((defend + DEFEND_INTERVAL)
    431                             < now) {
    432                         defend = now;
    433                         (void)arp(fd, &saddr,
    434                                 ARPOP_REQUEST,
    435                                 &addr, ip,
    436                                 &addr, ip);
    437                         VDBG("%s defend\n", intf);
    438                         timeout = -1;
    439                         continue;
     487            if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
     488                memcmp(&addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
     489                source_ip_conflict = 1;
     490            }
     491            if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
     492                p.arp.arp_op == htons(ARPOP_REQUEST) &&
     493                memcmp(&addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
     494                target_ip_conflict = 1;
     495            }
     496
     497            VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
     498                state, source_ip_conflict, target_ip_conflict);
     499            switch (state) {
     500            case PROBE:
     501            case ANNOUNCE:
     502                // When probing or announcing, check for source IP conflicts
     503                // and other hosts doing ARP probes (target IP conflicts).
     504                if (source_ip_conflict || target_ip_conflict) {
     505                    conflicts++;
     506                    if (conflicts >= MAX_CONFLICTS) {
     507                        VDBG("%s ratelimit\n", intf);
     508                        timeout = RATE_LIMIT_INTERVAL * 1000;
     509                        state = RATE_LIMIT_PROBE;
    440510                    }
    441                     defend = now;
     511
     512                    // restart the whole protocol
     513                    pick(&ip);
     514                    timeout = 0;
     515                    nprobes = 0;
     516                    nclaims = 0;
     517                }
     518                break;
     519            case MONITOR:
     520                // If a conflict, we try to defend with a single ARP probe.
     521                if (source_ip_conflict) {
     522                    VDBG("monitor conflict -- defending\n");
     523                    state = DEFEND;
     524                    timeout = DEFEND_INTERVAL * 1000;
     525                    (void)arp(fd, &saddr,
     526                            ARPOP_REQUEST,
     527                            &addr, ip,
     528                            &addr, ip);
     529                }
     530                break;
     531            case DEFEND:
     532                // Well, we tried.  Start over (on conflict).
     533                if (source_ip_conflict) {
     534                    state = PROBE;
     535                    VDBG("defend conflict -- starting over\n");
    442536                    ready = 0;
    443537                    run(script, "deconfig", intf, &ip);
    444                     // FIXME rm filters: setsockopt(fd,
    445                     // SO_DETACH_FILTER, ...)
    446                 }
    447                 conflicts++;
    448                 if (conflicts >= MAX_CONFLICTS) {
    449                     VDBG("%s ratelimit\n", intf);
    450                     sleep(RATE_LIMIT_INTERVAL);
    451                 }
    452                 // restart the whole protocol
     538
     539                    // restart the whole protocol
     540                    pick(&ip);
     541                    timeout = 0;
     542                    nprobes = 0;
     543                    nclaims = 0;
     544                }
     545                break;
     546            default:
     547                // Invalid, should never happen.  Restart the whole protocol.
     548                VDBG("invalid state -- starting over\n");
     549                state = PROBE;
    453550                pick(&ip);
    454551                timeout = 0;
    455552                nprobes = 0;
    456553                nclaims = 0;
    457             }
    458             // two hosts probing one address is a collision too
    459             else if (p.target_ip.s_addr == ip.s_addr
    460                     && nclaims == 0
    461                     && p.arp.ar_op == htons(ARPOP_REQUEST)
    462                     && memcmp(&addr, &p.target_addr,
    463                             ETH_ALEN) != 0) {
    464                 goto collision;
    465             }
    466             break;
    467 
     554                break;
     555            } // switch state
     556
     557            break; // case 1 (packets arriving)
    468558        default:
    469559            why = "poll";
    470560            goto bad;
    471         }
     561        } // switch poll
    472562    }
    473563bad:
Note: See TracChangeset for help on using the changeset viewer.