ia64/xen-unstable

changeset 1457:744f3757de91

bitkeeper revision 1.946.1.2 (40c9c331_5fgp6L-qPgvCmkAXREm4Q)

Add support for more than one network interface per domain.
author mjw@wray-m-3.hpl.hp.com
date Fri Jun 11 14:35:29 2004 +0000 (2004-06-11)
parents 5d1068f385df
children 1d69c0528a2e
files linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c
line diff
     1.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile	Fri Jun 11 14:25:13 2004 +0000
     1.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile	Fri Jun 11 14:35:29 2004 +0000
     1.3 @@ -1,3 +1,4 @@
     1.4  O_TARGET := drv.o
     1.5 +export-objs := interface.o
     1.6  obj-y := main.o control.o interface.o
     1.7  include $(TOPDIR)/Rules.make
     2.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Fri Jun 11 14:25:13 2004 +0000
     2.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Fri Jun 11 14:35:29 2004 +0000
     2.3 @@ -71,13 +71,14 @@ void __netif_disconnect_complete(netif_t
     2.4  
     2.5  void netif_create(netif_be_create_t *create)
     2.6  {
     2.7 +    int                err = 0;
     2.8      domid_t            domid  = create->domid;
     2.9      unsigned int       handle = create->netif_handle;
    2.10      struct net_device *dev;
    2.11      netif_t          **pnetif, *netif;
    2.12 -    char               name[IFNAMSIZ];
    2.13 +    char               name[IFNAMSIZ] = {};
    2.14  
    2.15 -    snprintf(name, IFNAMSIZ, "vif%u.%u", domid, handle);
    2.16 +    snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
    2.17      dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
    2.18      if ( dev == NULL )
    2.19      {
    2.20 @@ -123,9 +124,9 @@ void netif_create(netif_be_create_t *cre
    2.21      /* XXX In bridge mode we should force a different MAC from remote end. */
    2.22      dev->dev_addr[2] ^= 1;
    2.23  
    2.24 -    if ( register_netdev(dev) != 0 )
    2.25 -    {
    2.26 -        DPRINTK("Could not register new net device\n");
    2.27 +    err = register_netdev(dev);
    2.28 +    if (err) {
    2.29 +        DPRINTK("Could not register new net device %s: err=%d\n", dev->name, err);
    2.30          create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
    2.31          kfree(dev);
    2.32          return;
    2.33 @@ -302,3 +303,13 @@ void netif_interface_init(void)
    2.34      bridge_br->bridge_forward_delay = bridge_br->forward_delay = 0;
    2.35      bridge_br->stp_enabled = 0;
    2.36  }
    2.37 +
    2.38 +#ifndef CONFIG_BRIDGE
    2.39 +#error Must configure Ethernet bridging in Network Options
    2.40 +#endif
    2.41 +EXPORT_SYMBOL(br_add_bridge);
    2.42 +EXPORT_SYMBOL(br_del_bridge);
    2.43 +EXPORT_SYMBOL(br_add_if);
    2.44 +EXPORT_SYMBOL(br_del_if);
    2.45 +EXPORT_SYMBOL(br_get_bridge_ifindices);
    2.46 +EXPORT_SYMBOL(br_get_port_ifindices);
     3.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c	Fri Jun 11 14:25:13 2004 +0000
     3.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c	Fri Jun 11 14:35:29 2004 +0000
     3.3 @@ -99,6 +99,72 @@ static struct net_device *find_dev_by_ha
     3.4      return NULL;
     3.5  }
     3.6  
     3.7 +#define MULTIVIF
     3.8 +//#ifdef MULTIVIF
     3.9 +
    3.10 +/** Network interface info. */
    3.11 +struct netif_ctrl {
    3.12 +    /** Number of interfaces. */
    3.13 +    int interface_n;
    3.14 +    /** Number of connected interfaces. */
    3.15 +    int connected_n;
    3.16 +    /** Error code. */
    3.17 +    int err;
    3.18 +};
    3.19 +
    3.20 +static struct netif_ctrl netctrl = {};
    3.21 +
    3.22 +static void netctrl_init(void){
    3.23 +    netctrl = (struct netif_ctrl){};
    3.24 +    netctrl.interface_n = -1;
    3.25 +}
    3.26 +
    3.27 +/** Get or set a network interface error.
    3.28 + */
    3.29 +static int netctrl_err(int err)
    3.30 +{
    3.31 +    if(err < 0 && !netctrl.err){
    3.32 +        netctrl.err = err;
    3.33 +        printk(KERN_WARNING "%s> err=%d\n", __FUNCTION__, err);
    3.34 +    }
    3.35 +    return netctrl.err;
    3.36 +}
    3.37 +
    3.38 +/** Test if all network interfaces are connected.
    3.39 + *
    3.40 + * @return 1 if all connected, 0 if not, negative error code otherwise
    3.41 + */
    3.42 +static int netctrl_connected(void)
    3.43 +{
    3.44 +    int ok = 0;
    3.45 +    ok = (netctrl.err ? netctrl.err : (netctrl.connected_n == netctrl.interface_n));
    3.46 +    return ok;
    3.47 +}
    3.48 +
    3.49 +/** Count the connected network interfaces.
    3.50 + *
    3.51 + * @return connected count
    3.52 + */
    3.53 +static int netctrl_connected_count(void)
    3.54 +{
    3.55 +    
    3.56 +    struct list_head *ent;
    3.57 +    struct net_private *np;
    3.58 +    unsigned int connected;
    3.59 +
    3.60 +    connected = 0;
    3.61 +    
    3.62 +    list_for_each(ent, &dev_list) {
    3.63 +        np = list_entry(ent, struct net_private, list);
    3.64 +        if ( np->state == NETIF_STATE_CONNECTED){
    3.65 +            connected++;
    3.66 +        }
    3.67 +    }
    3.68 +    netctrl.connected_n = connected;
    3.69 +    return connected;
    3.70 +}
    3.71 +
    3.72 +//#endif
    3.73  
    3.74  static int network_open(struct net_device *dev)
    3.75  {
    3.76 @@ -488,21 +554,100 @@ static struct net_device_stats *network_
    3.77  }
    3.78  
    3.79  
    3.80 +static void network_reconnect(struct net_device *dev, netif_fe_interface_status_changed_t *status)
    3.81 +{
    3.82 +    struct net_private *np;
    3.83 +    int i, requeue_idx;
    3.84 +    netif_tx_request_t *tx;
    3.85 +
    3.86 +    np = dev->priv;
    3.87 +    spin_lock_irq(&np->rx_lock);
    3.88 +    spin_lock(&np->tx_lock);
    3.89 +
    3.90 +    /* Recovery procedure: */
    3.91 +
    3.92 +    /* Step 1: Reinitialise variables. */
    3.93 +    np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
    3.94 +    np->rx->event = 1;
    3.95 +
    3.96 +    /* Step 2: Rebuild the RX and TX ring contents.
    3.97 +     * NB. We could just free the queued TX packets now but we hope
    3.98 +     * that sending them out might do some good.  We have to rebuild
    3.99 +     * the RX ring because some of our pages are currently flipped out
   3.100 +     * so we can't just free the RX skbs.
   3.101 +     * NB2. Freelist index entries are always going to be less than
   3.102 +     *  __PAGE_OFFSET, whereas pointers to skbs will always be equal or
   3.103 +     * greater than __PAGE_OFFSET: we use this property to distinguish
   3.104 +     * them.
   3.105 +     */
   3.106 +
   3.107 +    /* Rebuild the TX buffer freelist and the TX ring itself.
   3.108 +     * NB. This reorders packets.  We could keep more private state
   3.109 +     * to avoid this but maybe it doesn't matter so much given the
   3.110 +     * interface has been down.
   3.111 +     */
   3.112 +    for( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ ){
   3.113 +            if( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET ) {
   3.114 +                struct sk_buff *skb = np->tx_skbs[i];
   3.115 +                
   3.116 +                tx = &np->tx->ring[requeue_idx++].req;
   3.117 +                
   3.118 +                tx->id   = i;
   3.119 +                tx->addr = virt_to_machine(skb->data);
   3.120 +                tx->size = skb->len;
   3.121 +                
   3.122 +                np->stats.tx_bytes += skb->len;
   3.123 +                np->stats.tx_packets++;
   3.124 +            }
   3.125 +    }
   3.126 +    wmb();
   3.127 +    np->tx->req_prod = requeue_idx;
   3.128 +
   3.129 +    /* Rebuild the RX buffer freelist and the RX ring itself. */
   3.130 +    for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ )
   3.131 +        if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET )
   3.132 +            np->rx->ring[requeue_idx++].req.id = i;
   3.133 +    wmb();                
   3.134 +    np->rx->req_prod = requeue_idx;
   3.135 +
   3.136 +    /* Step 3: All public and private state should now be sane.  Get
   3.137 +     * ready to start sending and receiving packets and give the driver
   3.138 +     * domain a kick because we've probably just requeued some
   3.139 +     * packets.
   3.140 +     */
   3.141 +    netif_carrier_on(dev);
   3.142 +    netif_start_queue(dev);
   3.143 +    np->state = NETIF_STATE_ACTIVE;
   3.144 +
   3.145 +    notify_via_evtchn(status->evtchn);  
   3.146 +
   3.147 +    network_tx_buf_gc(dev);
   3.148 +
   3.149 +    printk(KERN_INFO "Recovery completed\n");
   3.150 +
   3.151 +    spin_unlock(&np->tx_lock);
   3.152 +    spin_unlock_irq(&np->rx_lock);
   3.153 +}
   3.154 +
   3.155  static void netif_status_change(netif_fe_interface_status_changed_t *status)
   3.156  {
   3.157      ctrl_msg_t                   cmsg;
   3.158      netif_fe_interface_connect_t up;
   3.159      struct net_device *dev;
   3.160      struct net_private *np;
   3.161 -
   3.162 -    if ( status->handle != 0 )
   3.163 -    {
   3.164 -        printk(KERN_WARNING "Status change on unsupported netif %d\n",
   3.165 -               status->handle);
   3.166 +    
   3.167 +//#ifdef MULTIVIF
   3.168 +    if(netctrl.interface_n <= 0){
   3.169 +        printk(KERN_WARNING "Status change: no interfaces\n");
   3.170          return;
   3.171      }
   3.172 -
   3.173 -    dev = find_dev_by_handle(0);
   3.174 +//#endif
   3.175 +    dev = find_dev_by_handle(status->handle);
   3.176 +    if(!dev){
   3.177 +        printk(KERN_WARNING "Status change: invalid netif handle %u\n",
   3.178 +               status->handle);
   3.179 +         return;
   3.180 +    }
   3.181      np  = dev->priv;
   3.182      
   3.183      switch ( status->status )
   3.184 @@ -560,7 +705,7 @@ static void netif_status_change(netif_fe
   3.185          cmsg.type      = CMSG_NETIF_FE;
   3.186          cmsg.subtype   = CMSG_NETIF_FE_INTERFACE_CONNECT;
   3.187          cmsg.length    = sizeof(netif_fe_interface_connect_t);
   3.188 -        up.handle      = 0;
   3.189 +        up.handle      = status->handle;
   3.190          up.tx_shmem_frame = virt_to_machine(np->tx) >> PAGE_SHIFT;
   3.191          up.rx_shmem_frame = virt_to_machine(np->rx) >> PAGE_SHIFT;
   3.192          memcpy(cmsg.msg, &up, sizeof(up));
   3.193 @@ -570,8 +715,7 @@ static void netif_status_change(netif_fe
   3.194          break;
   3.195  
   3.196      case NETIF_INTERFACE_STATUS_CONNECTED:
   3.197 -        if ( np->state == NETIF_STATE_CLOSED )
   3.198 -        {
   3.199 +        if ( np->state == NETIF_STATE_CLOSED ){
   3.200              printk(KERN_WARNING "Unexpected netif-CONNECTED message"
   3.201                     " in state %d\n", np->state);
   3.202              break;
   3.203 @@ -579,87 +723,20 @@ static void netif_status_change(netif_fe
   3.204  
   3.205          memcpy(dev->dev_addr, status->mac, ETH_ALEN);
   3.206  
   3.207 -        if(netif_carrier_ok(dev))
   3.208 +        if(netif_carrier_ok(dev)){
   3.209              np->state = NETIF_STATE_CONNECTED;
   3.210 -        else
   3.211 -        {
   3.212 -            int i, requeue_idx;
   3.213 -            netif_tx_request_t *tx;
   3.214 -
   3.215 -            spin_lock_irq(&np->rx_lock);
   3.216 -            spin_lock(&np->tx_lock);
   3.217 -
   3.218 -            /* Recovery procedure: */
   3.219 -
   3.220 -            /* Step 1: Reinitialise variables. */
   3.221 -            np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
   3.222 -            np->rx->event = 1;
   3.223 -
   3.224 -            /* Step 2: Rebuild the RX and TX ring contents.
   3.225 -             * NB. We could just free the queued TX packets now but we hope
   3.226 -             * that sending them out might do some good.  We have to rebuild
   3.227 -             * the RX ring because some of our pages are currently flipped out
   3.228 -             * so we can't just free the RX skbs.
   3.229 -	     * NB2. Freelist index entries are always going to be less than
   3.230 -	     *  __PAGE_OFFSET, whereas pointers to skbs will always be equal or
   3.231 -	     * greater than __PAGE_OFFSET: we use this property to distinguish
   3.232 -             * them.
   3.233 -             */
   3.234 -
   3.235 -            /* Rebuild the TX buffer freelist and the TX ring itself.
   3.236 -             * NB. This reorders packets.  We could keep more private state
   3.237 -             * to avoid this but maybe it doesn't matter so much given the
   3.238 -             * interface has been down.
   3.239 -             */
   3.240 -            for ( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ )
   3.241 -            {
   3.242 -                if ( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET )
   3.243 -                {
   3.244 -                    struct sk_buff *skb = np->tx_skbs[i];
   3.245 -                    
   3.246 -                    tx = &np->tx->ring[requeue_idx++].req;
   3.247 -                    
   3.248 -                    tx->id   = i;
   3.249 -                    tx->addr = virt_to_machine(skb->data);
   3.250 -                    tx->size = skb->len;
   3.251 -                    
   3.252 -                    np->stats.tx_bytes += skb->len;
   3.253 -                    np->stats.tx_packets++;
   3.254 -                }
   3.255 -            }
   3.256 -            wmb();
   3.257 -            np->tx->req_prod = requeue_idx;
   3.258 -
   3.259 -            /* Rebuild the RX buffer freelist and the RX ring itself. */
   3.260 -            for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ )
   3.261 -                if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET )
   3.262 -                    np->rx->ring[requeue_idx++].req.id = i;
   3.263 -            wmb();                
   3.264 -            np->rx->req_prod = requeue_idx;
   3.265 -
   3.266 -            /* Step 3: All public and private state should now be sane.  Get
   3.267 -             * ready to start sending and receiving packets and give the driver
   3.268 -             * domain a kick because we've probably just requeued some
   3.269 -             * packets.
   3.270 -             */
   3.271 -            netif_carrier_on(dev);
   3.272 -            netif_start_queue(dev);
   3.273 -            np->state = NETIF_STATE_ACTIVE;
   3.274 -
   3.275 -            notify_via_evtchn(status->evtchn);  
   3.276 -
   3.277 -	    network_tx_buf_gc(dev);
   3.278 -
   3.279 -            printk(KERN_INFO "Recovery completed\n");
   3.280 -
   3.281 -            spin_unlock(&np->tx_lock);
   3.282 -            spin_unlock_irq(&np->rx_lock);
   3.283 +        } else {
   3.284 +            network_reconnect(dev, status);
   3.285          }
   3.286  
   3.287          np->evtchn = status->evtchn;
   3.288          np->irq = bind_evtchn_to_irq(np->evtchn);
   3.289          (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, 
   3.290                            dev->name, dev);
   3.291 +        
   3.292 +#ifdef MULTIVIF
   3.293 +        netctrl_connected_count();
   3.294 +#endif
   3.295          break;
   3.296  
   3.297      default:
   3.298 @@ -669,27 +746,102 @@ static void netif_status_change(netif_fe
   3.299      }
   3.300  }
   3.301  
   3.302 +/** Create a network devices.
   3.303 + *
   3.304 + * @param handle device handle
   3.305 + * @param val return parameter for created device
   3.306 + * @return 0 on success, error code otherwise
   3.307 + */
   3.308 +static int create_netdev(int handle, struct net_device **val){
   3.309 +    int err = 0;
   3.310 +    struct net_device *dev = NULL;
   3.311 +    struct net_private *np = NULL;
   3.312 +
   3.313 +    dev = alloc_etherdev(sizeof(struct net_private));
   3.314 +    if (!dev){
   3.315 +        printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__);
   3.316 +        err = -ENOMEM;
   3.317 +        goto exit;
   3.318 +    }
   3.319 +    np         = dev->priv;
   3.320 +    np->state  = NETIF_STATE_CLOSED;
   3.321 +    np->handle = handle;
   3.322 +    
   3.323 +    dev->open            = network_open;
   3.324 +    dev->hard_start_xmit = network_start_xmit;
   3.325 +    dev->stop            = network_close;
   3.326 +    dev->get_stats       = network_get_stats;
   3.327 +    dev->poll            = netif_poll;
   3.328 +    dev->weight          = 64;
   3.329 +    
   3.330 +    err = register_netdev(dev);
   3.331 +    if (err){
   3.332 +        printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err);
   3.333 +        goto exit;
   3.334 +    }
   3.335 +    np->dev = dev;
   3.336 +    list_add(&np->list, &dev_list);
   3.337 +  exit:
   3.338 +    if(err){
   3.339 +        if(dev) kfree(dev);
   3.340 +        dev = NULL;
   3.341 +    }
   3.342 +    if(val) *val = dev;
   3.343 +    return err;
   3.344 +}
   3.345 +
   3.346 +//#ifdef MULTIVIF
   3.347 +/** Initialize the network control interface. Set the number of network devices
   3.348 + * and create them.
   3.349 + */
   3.350 +static void netif_driver_status_change(netif_fe_driver_status_changed_t *status)
   3.351 +{
   3.352 +    int err = 0;
   3.353 +    int i;
   3.354 +    
   3.355 +    netctrl.interface_n = status->nr_interfaces;
   3.356 +    netctrl.connected_n = 0;
   3.357 +
   3.358 +    for(i = 0; i < netctrl.interface_n; i++){
   3.359 +        err = create_netdev(i, NULL);
   3.360 +        if(err){
   3.361 +            netctrl_err(err);
   3.362 +            break;
   3.363 +        }
   3.364 +    }
   3.365 +}
   3.366 +//#endif
   3.367 +
   3.368  
   3.369  static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
   3.370  {
   3.371 +    int respond = 1;
   3.372      switch ( msg->subtype )
   3.373      {
   3.374      case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
   3.375          if ( msg->length != sizeof(netif_fe_interface_status_changed_t) )
   3.376 -            goto parse_error;
   3.377 +            goto error;
   3.378          netif_status_change((netif_fe_interface_status_changed_t *)
   3.379                              &msg->msg[0]);
   3.380          break;
   3.381 +//#ifdef MULTIVIF
   3.382 +    case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
   3.383 +        if ( msg->length != sizeof(netif_fe_driver_status_changed_t) )
   3.384 +            goto error;
   3.385 +        netif_driver_status_change((netif_fe_driver_status_changed_t *)
   3.386 +                                   &msg->msg[0]);
   3.387 +        // Message is a response, so do not respond.
   3.388 +        respond = 0;
   3.389 +        break;
   3.390 +//#endif
   3.391 +      error:
   3.392      default:
   3.393 -        goto parse_error;
   3.394 +        msg->length = 0;
   3.395 +        break;
   3.396      }
   3.397 -
   3.398 -    ctrl_if_send_response(msg);
   3.399 -    return;
   3.400 -
   3.401 - parse_error:
   3.402 -    msg->length = 0;
   3.403 -    ctrl_if_send_response(msg);
   3.404 +    if(respond){
   3.405 +        ctrl_if_send_response(msg);
   3.406 +    }
   3.407  }
   3.408  
   3.409  
   3.410 @@ -697,9 +849,11 @@ static int __init init_module(void)
   3.411  {
   3.412      ctrl_msg_t                       cmsg;
   3.413      netif_fe_driver_status_changed_t st;
   3.414 -    int err;
   3.415 -    struct net_device *dev;
   3.416 -    struct net_private *np;
   3.417 +    int err = 0;
   3.418 +#ifdef MULTIVIF
   3.419 +    int wait_n = 20;
   3.420 +    int wait_i;
   3.421 +#endif
   3.422  
   3.423      if ( start_info.flags & SIF_INITDOMAIN
   3.424           || start_info.flags & SIF_NET_BE_DOMAIN )
   3.425 @@ -708,32 +862,9 @@ static int __init init_module(void)
   3.426      printk("Initialising Xen virtual ethernet frontend driver");
   3.427  
   3.428      INIT_LIST_HEAD(&dev_list);
   3.429 -
   3.430 -    if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL )
   3.431 -    {
   3.432 -        err = -ENOMEM;
   3.433 -        goto fail;
   3.434 -    }
   3.435 -
   3.436 -    np = dev->priv;
   3.437 -    np->state  = NETIF_STATE_CLOSED;
   3.438 -    np->handle = 0;
   3.439 -
   3.440 -    dev->open            = network_open;
   3.441 -    dev->hard_start_xmit = network_start_xmit;
   3.442 -    dev->stop            = network_close;
   3.443 -    dev->get_stats       = network_get_stats;
   3.444 -    dev->poll            = netif_poll;
   3.445 -    dev->weight          = 64;
   3.446 -    
   3.447 -    if ( (err = register_netdev(dev)) != 0 )
   3.448 -    {
   3.449 -        kfree(dev);
   3.450 -        goto fail;
   3.451 -    }
   3.452 -    
   3.453 -    np->dev = dev;
   3.454 -    list_add(&np->list, &dev_list);
   3.455 +#ifdef MULTIVIF
   3.456 +    netctrl_init();
   3.457 +#endif
   3.458  
   3.459      (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx,
   3.460                                      CALLBACK_IN_BLOCKING_CONTEXT);
   3.461 @@ -743,25 +874,30 @@ static int __init init_module(void)
   3.462      cmsg.subtype   = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED;
   3.463      cmsg.length    = sizeof(netif_fe_driver_status_changed_t);
   3.464      st.status      = NETIF_DRIVER_STATUS_UP;
   3.465 +    st.nr_interfaces = 0;
   3.466      memcpy(cmsg.msg, &st, sizeof(st));
   3.467 -
   3.468      ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
   3.469 -    
   3.470 -    /*
   3.471 -     * We should read 'nr_interfaces' from response message and wait
   3.472 -     * for notifications before proceeding. For now we assume that we
   3.473 -     * will be notified of exactly one interface.
   3.474 -     */
   3.475 -    while ( np->state != NETIF_STATE_CONNECTED )
   3.476 -    {
   3.477 +
   3.478 +#ifdef MULTIVIF
   3.479 +    /* Wait for all interfaces to be connected. */
   3.480 +    for(wait_i = 0; 1; wait_i++) {
   3.481 +        if(wait_i < wait_n){
   3.482 +            err = netctrl_connected();
   3.483 +        } else {
   3.484 +            err = -ENETDOWN;
   3.485 +        }
   3.486 +        if(err < 0) goto exit;
   3.487 +        if(err > 0){
   3.488 +            err = 0;
   3.489 +            break;
   3.490 +        }
   3.491          set_current_state(TASK_INTERRUPTIBLE);
   3.492          schedule_timeout(1);
   3.493 -    }
   3.494 +     }
   3.495 +#endif
   3.496  
   3.497 -    return 0;
   3.498 -
   3.499 - fail:
   3.500 -    cleanup_module();
   3.501 + exit:
   3.502 +    if(err) cleanup_module();
   3.503      return err;
   3.504  }
   3.505