diff -Nuarp a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c --- a/drivers/net/bonding/bond_alb.c Sun Dec 21 16:09:01 2003 +++ b/drivers/net/bonding/bond_alb.c Sun Dec 21 16:09:01 2003 @@ -146,6 +146,7 @@ static inline void tlb_init_table_entry( BOND_TLB_REBALANCE_INTERVAL; entry->tx_bytes = 0; } + entry->tx_slave = NULL; entry->next = TLB_NULL_INDEX; entry->prev = TLB_NULL_INDEX; @@ -164,6 +165,7 @@ static void tlb_clear_slave(struct bondi u32 index; _lock_tx_hashtbl(bond); + /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; @@ -173,6 +175,7 @@ static void tlb_clear_slave(struct bondi tlb_init_table_entry(&tx_hash_table[index], save_load); index = next_index; } + _unlock_tx_hashtbl(bond); tlb_init_slave(slave); @@ -199,9 +202,11 @@ static int tlb_initialize(struct bonding } memset(bond_info->tx_hashtbl, 0, size); + for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); } + _unlock_tx_hashtbl(bond); return 0; @@ -213,8 +218,10 @@ static void tlb_deinitialize(struct bond struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); + kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; + _unlock_tx_hashtbl(bond); } @@ -326,7 +333,6 @@ static void rlb_update_entry_from_arp(st if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && (client_info->ip_dst == arp->ip_src)) { - /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -409,10 +415,12 @@ static void rlb_teach_disabled_mac_on_pr if (!bond->curr_active_slave) { return; } + if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; dev_set_promiscuity(bond->curr_active_slave->dev, 1); } + bond->alb_info.rlb_promisc_timeout_counter = 0; alb_send_learning_packets(bond->curr_active_slave, addr); @@ -435,7 +443,6 @@ static void rlb_clear_slave(struct bondi index = bond_info->rx_hashtbl_head; for (; index != RLB_NULL_INDEX; index = next_index) { next_index = rx_hash_table[index].next; - if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -464,9 +471,11 @@ static void rlb_clear_slave(struct bondi _unlock_rx_hashtbl(bond); write_lock(&bond->curr_slave_lock); + if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } + write_unlock(&bond->curr_slave_lock); } @@ -600,7 +609,6 @@ struct slave *rlb_choose_channel(struct if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); @@ -679,7 +687,6 @@ static struct slave *rlb_arp_xmit(struct } dprintk("Server sent ARP Reply packet\n"); } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { - /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -767,6 +774,7 @@ static int rlb_initialize(struct bonding for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) { rlb_init_table_entry(bond_info->rx_hashtbl + i); } + _unlock_rx_hashtbl(bond); /*initialize packet type*/ @@ -788,8 +796,10 @@ static void rlb_deinitialize(struct bond dev_remove_pack(&(bond_info->rlb_pkt_type)); _lock_rx_hashtbl(bond); + kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; + _unlock_rx_hashtbl(bond); } @@ -817,14 +827,15 @@ static void alb_send_learning_packets(st data = skb_put(skb, size); memcpy(data, &pkt, size); + skb->mac.raw = data; skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + dev_queue_xmit(skb); } - } /* hw is a boolean parameter that determines whether we should try and @@ -992,6 +1003,7 @@ static int alb_handle_addr_collision_on_ break; } } + if (found) { /* a slave was found that is using the mac address * of the new slave @@ -1002,6 +1014,7 @@ static int alb_handle_addr_collision_on_ slave->dev->name); return -EINVAL; } + return 0; } @@ -1179,7 +1192,6 @@ int bond_alb_xmit(struct sk_buff *skb, s hash_start = (char*)&(skb->nh.iph->daddr); hash_size = sizeof(skb->nh.iph->daddr); break; - case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; @@ -1189,7 +1201,6 @@ int bond_alb_xmit(struct sk_buff *skb, s hash_start = (char*)&(skb->nh.ipv6h->daddr); hash_size = sizeof(skb->nh.ipv6h->daddr); break; - case ETH_P_IPX: if (skb->nh.ipxh->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { @@ -1211,14 +1222,12 @@ int bond_alb_xmit(struct sk_buff *skb, s hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; - case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; - default: do_tx_balance = 0; break; @@ -1291,9 +1300,11 @@ void bond_alb_monitor(struct bonding *bo * read. */ read_lock(&bond->curr_slave_lock); + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); } + read_unlock(&bond->curr_slave_lock); bond_info->lp_counter = 0; @@ -1301,7 +1312,9 @@ void bond_alb_monitor(struct bonding *bo /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { + read_lock(&bond->curr_slave_lock); + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); if (slave == bond->curr_active_slave) { @@ -1311,7 +1324,9 @@ void bond_alb_monitor(struct bonding *bo bond_info->unbalanced_load = 0; } } + read_unlock(&bond->curr_slave_lock); + bond_info->tx_rebalance_counter = 0; } @@ -1323,6 +1338,7 @@ void bond_alb_monitor(struct bonding *bo * sets the promiscuity. */ write_lock(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { @@ -1335,6 +1351,7 @@ void bond_alb_monitor(struct bonding *bo dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; } + write_unlock(&bond->curr_slave_lock); if (bond_info->rlb_rebalance) { diff -Nuarp a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c --- a/drivers/net/bonding/bond_main.c Sun Dec 21 16:09:01 2003 +++ b/drivers/net/bonding/bond_main.c Sun Dec 21 16:09:01 2003 @@ -596,7 +596,6 @@ static void bond_change_active_slave(str static void bond_select_active_slave(struct bonding *bond); static struct slave *bond_find_best_slave(struct bonding *bond); - static void bond_arp_send_all(struct slave *slave) { int i; @@ -608,7 +607,6 @@ static void bond_arp_send_all(struct sla } } - static const char *bond_mode_name(void) { switch (bond_mode) { @@ -697,7 +695,6 @@ static void bond_attach_slave(struct bon bond->slave_cnt++; } - /* * Less bad way to call ioctl from within the kernel; this needs to be * done some other way to get the call out of interrupt context. @@ -827,7 +824,6 @@ static int bond_check_dev_link(struct ne return 0; } } - } /* @@ -1068,12 +1064,12 @@ static int bond_mc_list_copy(struct dev_ new_dmi->next = bond->mc_list; bond->mc_list = new_dmi; - new_dmi->dmi_addrlen = dmi->dmi_addrlen; memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); new_dmi->dmi_users = dmi->dmi_users; new_dmi->dmi_gusers = dmi->dmi_gusers; } + return 0; } @@ -1083,7 +1079,7 @@ static int bond_mc_list_copy(struct dev_ static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) { return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && - dmi1->dmi_addrlen == dmi2->dmi_addrlen; + dmi1->dmi_addrlen == dmi2->dmi_addrlen; } /* @@ -1096,7 +1092,6 @@ static void bond_set_promiscuity(struct if (bond->curr_active_slave) { dev_set_promiscuity(bond->curr_active_slave->dev, inc); } - } else { struct slave *slave; int i; @@ -1137,6 +1132,7 @@ static struct dev_mc_list *bond_mc_list_ return idmi; } } + return NULL; } @@ -1183,7 +1179,6 @@ static void bond_set_multicast_list(stru } } - /* save master's multicast list */ bond_mc_list_destroy(bond); bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC); @@ -1211,9 +1206,11 @@ static void bond_mc_swap(struct bonding if (bond->dev->flags & IFF_PROMISC) { dev_set_promiscuity(old_active->dev, -1); } + if (bond->dev->flags & IFF_ALLMULTI) { dev_set_allmulti(old_active->dev, -1); } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } @@ -1223,9 +1220,11 @@ static void bond_mc_swap(struct bonding if (bond->dev->flags & IFF_PROMISC) { dev_set_promiscuity(new_active->dev, 1); } + if (bond->dev->flags & IFF_ALLMULTI) { dev_set_allmulti(new_active->dev, 1); } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } @@ -1248,7 +1247,6 @@ static int bond_enslave(struct net_devic slave_dev->name); } - /* bond must be initialized by bond_open() before enslaving */ if (!(bond_dev->flags & IFF_UP)) { dprintk("Error, master_dev is not up\n"); @@ -1308,6 +1306,7 @@ static int bond_enslave(struct net_devic if (!new_slave) { return -ENOMEM; } + memset(new_slave, 0, sizeof(struct slave)); /* save slave's original flags before calling @@ -1375,6 +1374,7 @@ static int bond_enslave(struct net_devic if (bond_dev->flags & IFF_PROMISC) { dev_set_promiscuity(slave_dev, 1); } + /* set allmulti level to new slave */ if (bond_dev->flags & IFF_ALLMULTI) { dev_set_allmulti(slave_dev, 1); @@ -1396,6 +1396,7 @@ static int bond_enslave(struct net_devic write_lock_bh(&bond->lock); bond_attach_slave(bond, new_slave); + new_slave->delay = 0; new_slave->link_failure_count = 0; @@ -1453,11 +1454,11 @@ static int bond_enslave(struct net_devic if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - printk(KERN_WARNING DRV_NAME ": Warning: failed to get speed/duplex from %s, speed " "forced to 100Mbps, duplex forced to Full.\n", new_slave->dev->name); + if (bond_mode == BOND_MODE_8023AD) { printk(KERN_WARNING "Operation of 802.3ad mode requires ETHTOOL " @@ -1528,6 +1529,7 @@ static int bond_enslave(struct net_devic break; default: dprintk("This slave is always active in trunk mode\n"); + /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; @@ -1562,6 +1564,7 @@ static int bond_enslave(struct net_devic break; } } + if (ndx == bond_dev->addr_len) { /* * We got all the way through the address and it was @@ -1647,7 +1650,9 @@ static int bond_ioctl_change_active(stru } else { res = -EINVAL; } + write_unlock_bh(&bond->lock); + return res; } @@ -1800,7 +1805,6 @@ static void bond_select_active_slave(str struct slave *best_slave; best_slave = bond_find_best_slave(bond); - if (best_slave != bond->curr_active_slave) { bond_change_active_slave(bond, best_slave); } @@ -1921,10 +1925,12 @@ static int bond_release(struct net_devic if (bond_dev->flags & IFF_PROMISC) { dev_set_promiscuity(slave_dev, -1); } + /* unset allmulti level from slave */ if (bond_dev->flags & IFF_ALLMULTI) { dev_set_allmulti(slave_dev, -1); } + /* flush master's mc_list from slave */ bond_mc_list_flush (slave_dev, bond_dev); } @@ -2016,10 +2022,12 @@ static int bond_release_all(struct net_d if (bond_dev->flags & IFF_PROMISC) { dev_set_promiscuity(slave_dev, -1); } + /* unset allmulti level from slave */ if (bond_dev->flags & IFF_ALLMULTI) { dev_set_allmulti(slave_dev, -1); } + /* flush master's mc_list from slave */ bond_mc_list_flush(slave_dev, bond_dev); } @@ -2111,9 +2119,11 @@ static void bond_mii_monitor(struct net_ } else { /* link going down */ slave->link = BOND_LINK_FAIL; slave->delay = downdelay; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + if (downdelay) { printk(KERN_INFO DRV_NAME ": %s: link status down for %s " @@ -2139,6 +2149,7 @@ static void bond_mii_monitor(struct net_ if (slave->delay <= 0) { /* link down for too long time */ slave->link = BOND_LINK_DOWN; + /* in active/backup mode, we must * completely disable this interface */ @@ -2211,6 +2222,7 @@ static void bond_mii_monitor(struct net_ if (link_state != BMSR_LSTATUS) { /* link down again */ slave->link = BOND_LINK_DOWN; + printk(KERN_INFO DRV_NAME ": %s: link status down again after %d " "ms for interface %s.\n", @@ -2273,6 +2285,7 @@ static void bond_mii_monitor(struct net_ if (old_speed != slave->speed) { bond_3ad_adapter_speed_changed(slave); } + if (old_duplex != slave->duplex) { bond_3ad_adapter_duplex_changed(slave); } @@ -2338,9 +2351,7 @@ static void bond_loadbalance_arp_mon(str * so it can wait */ bond_for_each_slave(bond, slave, i) { - if (slave->link != BOND_LINK_UP) { - if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { @@ -2376,11 +2387,14 @@ static void bond_loadbalance_arp_mon(str if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && my_ip)) { + slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + printk(KERN_INFO DRV_NAME ": %s: interface %s is now down.\n", bond_dev->name, @@ -2408,6 +2422,7 @@ static void bond_loadbalance_arp_mon(str write_lock(&bond->curr_slave_lock); bond_select_active_slave(bond); + if (oldcurrent && !bond->curr_active_slave) { printk(KERN_INFO DRV_NAME ": %s: now running without any active " @@ -2462,12 +2477,13 @@ static void bond_activebackup_arp_mon(st * so it can wait */ bond_for_each_slave(bond, slave, i) { - if (slave->link != BOND_LINK_UP) { if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { slave->link = BOND_LINK_UP; + write_lock(&bond->curr_slave_lock); + if ((!bond->curr_active_slave) && ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { bond_change_active_slave(bond, slave); @@ -2501,6 +2517,7 @@ static void bond_activebackup_arp_mon(st } } else { read_lock(&bond->curr_slave_lock); + if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && @@ -2515,12 +2532,17 @@ static void bond_activebackup_arp_mon(st * down - this gives each slave a chance to * tx/rx traffic before being taken out */ + read_unlock(&bond->curr_slave_lock); + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + bond_set_slave_inactive_flags(slave); + printk(KERN_INFO DRV_NAME ": %s: backup interface %s is now down\n", bond_dev->name, @@ -2536,7 +2558,6 @@ static void bond_activebackup_arp_mon(st read_unlock(&bond->curr_slave_lock); if (slave) { - /* if we have sent traffic in the past 2*arp_intervals but * haven't xmit and rx traffic in that time interval, select * a different slave. slave->jiffies is only updated when @@ -2551,23 +2572,29 @@ static void bond_activebackup_arp_mon(st ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + printk(KERN_INFO DRV_NAME ": %s: link status down for active interface " "%s, disabling it", bond_dev->name, slave->dev->name); + write_lock(&bond->curr_slave_lock); + bond_select_active_slave(bond); slave = bond->curr_active_slave; + write_unlock(&bond->curr_slave_lock); + bond->current_arp_slave = slave; + if (slave) { slave->jiffies = jiffies; } - } else if ((bond->primary_slave) && (bond->primary_slave != slave) && (bond->primary_slave->link == BOND_LINK_UP)) { @@ -2583,6 +2610,7 @@ static void bond_activebackup_arp_mon(st write_lock(&bond->curr_slave_lock); bond_change_active_slave(bond, bond->primary_slave); write_unlock(&bond->curr_slave_lock); + slave = bond->primary_slave; slave->jiffies = jiffies; } else { @@ -2635,6 +2663,7 @@ static void bond_activebackup_arp_mon(st } bond_set_slave_inactive_flags(slave); + printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " "now down.\n", @@ -2685,12 +2714,14 @@ static int bond_slave_info_query(struct } read_lock_bh(&bond->lock); + bond_for_each_slave(bond, slave, i) { if (i == (int)info->slave_id) { found = 1; break; } } + read_unlock_bh(&bond->lock); if (found) { @@ -2717,7 +2748,6 @@ static int bond_ethtool_ioctl(struct net } switch (cmd) { - case ETHTOOL_GDRVINFO: if (copy_from_user(&info, addr, sizeof(info))) { return -EFAULT; @@ -2772,7 +2802,6 @@ static int bond_do_ioctl(struct net_devi switch (cmd) { case SIOCETHTOOL: return bond_ethtool_ioctl(bond_dev, ifr); - case SIOCGMIIPHY: mii = (struct mii_ioctl_data *)&ifr->ifr_data; if (!mii) { @@ -2789,6 +2818,7 @@ static int bond_do_ioctl(struct net_devi if (!mii) { return -EINVAL; } + if (mii->reg_num == 1) { struct bonding *bond = (struct bonding *)bond_dev->priv; mii->val_out = 0; @@ -2800,32 +2830,39 @@ static int bond_do_ioctl(struct net_devi read_unlock(&bond->curr_slave_lock); read_unlock_bh(&bond->lock); } + return 0; case BOND_INFO_QUERY_OLD: case SIOCBONDINFOQUERY: u_binfo = (struct ifbond *)ifr->ifr_data; + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { return -EFAULT; } + res = bond_info_query(bond_dev, &k_binfo); if (res == 0) { if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { return -EFAULT; } } + return res; case BOND_SLAVE_INFO_QUERY_OLD: case SIOCBONDSLAVEINFOQUERY: u_sinfo = (struct ifslave *)ifr->ifr_data; + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { return -EFAULT; } + res = bond_slave_info_query(bond_dev, &k_sinfo); if (res == 0) { if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { return -EFAULT; } } + return res; default: /* Go on */ @@ -2883,6 +2920,7 @@ static int bond_do_ioctl(struct net_devi default: res = -EOPNOTSUPP; } + dev_put(slave_dev); } @@ -2992,7 +3030,6 @@ static int bond_xmit_roundrobin(struct s if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { - skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); @@ -3049,7 +3086,6 @@ static int bond_xmit_xor(struct sk_buff if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { - skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); @@ -3152,10 +3188,10 @@ static struct net_device_stats *bond_get stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; - } read_unlock_bh(&bond->lock); + return stats; } @@ -3327,6 +3363,7 @@ static int bond_info_open(struct inode * proc = PDE(inode); seq->private = proc->data; } + return res; } @@ -3465,6 +3502,7 @@ static int bond_set_mac_address(struct n bond_for_each_slave(bond, slave, i) { dprintk("slave %p %s\n", slave, slave->dev->name); + if (slave->dev->set_mac_address == NULL) { res = -EOPNOTSUPP; dprintk("EOPNOTSUPP %s\n", slave->dev->name); @@ -3560,8 +3598,8 @@ static int bond_change_mtu(struct net_de } bond_dev->mtu = new_mtu; - return 0; + return 0; unwind: /* unwind from the first slave that failed to head */ @@ -3846,7 +3884,6 @@ static inline int bond_parse_parm(char * return -1; } - static int bond_check_params(void) { /* @@ -3873,7 +3910,6 @@ static int bond_check_params(void) printk(KERN_ERR DRV_NAME ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); - return -EINVAL; } } @@ -4026,7 +4062,6 @@ static int bond_check_params(void) } } - if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ printk(KERN_WARNING DRV_NAME @@ -4150,3 +4185,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" * tab-width: 8 * End: */ + diff -Nuarp a/include/linux/if_bonding.h b/include/linux/if_bonding.h --- a/include/linux/if_bonding.h Sun Dec 21 16:09:01 2003 +++ b/include/linux/if_bonding.h Sun Dec 21 16:09:01 2003 @@ -111,3 +111,4 @@ struct ad_info { * tab-width: 8 * End: */ +