Goto sanos source index

//
// netif.c
//
// Network interface
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
// Portions Copyright (C) 2001, Swedish Institute of Computer Science.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <net/net.h>

struct netif *netif_list = NULL;
struct netif *netif_default = NULL;

static int netif_proc(struct proc_file *pf, void *arg) {
  struct netif *netif;
  
  for (netif = netif_list; netif != NULL; netif = netif->next) {
    pprintf(pf, "%s: addr %a mask %a gw %a\n", netif->name, &netif->ipaddr, &netif->netmask, &netif->gw);
  }

  return 0;
}

void netif_init() {
  register_proc_inode("netif", netif_proc, NULL);
}

struct netif *netif_add(char *name, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw) {
  struct netif *netif;
  
  netif = kmalloc(sizeof(struct netif));
  if (!netif) return NULL;
  memset(netif, 0, sizeof(struct netif));

  strcpy(netif->name, name);
  netif->input = ip_input;
  netif->output = NULL;
  netif->flags = NETIF_ALLMULTI;

  ip_addr_set(&netif->ipaddr, ipaddr);
  ip_addr_set(&netif->netmask, netmask);
  ip_addr_set(&netif->gw, gw);
  netif->broadcast.addr = (ipaddr->addr & netmask->addr) | ~netmask->addr;

  netif->mclist = NULL;
  netif->mccount = 0;

  netif->next = netif_list;
  netif_list = netif;

  return netif;
}

struct netif *netif_find(char *name) {
  struct netif *netif;

  if (!name) return NULL;

  for (netif = netif_list; netif != NULL; netif = netif->next) {
    if (strcmp(name, netif->name) == 0) return netif;
  }

  return NULL;
}

void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) {
  ip_addr_set(&netif->ipaddr, ipaddr);
}

void netif_set_gw(struct netif *netif, struct ip_addr *gw) {
  ip_addr_set(&netif->gw, gw);
}

void netif_set_netmask(struct netif *netif, struct ip_addr *netmask) {
  ip_addr_set(&netif->netmask, netmask);
}

void netif_set_default(struct netif *netif) {
  netif_default = netif;
}

int netif_ioctl_list(void *data, size_t size) {
  int numifs;
  struct netif *netif;
  struct ifcfg *ifcfg;
  struct sockaddr_in *sin;

  if (!data) return -EFAULT;

  // Find number of network interfaces
  numifs = 0;
  netif = netif_list;
  while (netif) {
    numifs++;
    netif = netif->next;
  }

  // Fill interface info into buffer
  if (size >= (size_t) (numifs * sizeof(struct ifcfg))) {
    netif = netif_list;
    ifcfg = (struct ifcfg *) data;
    while (netif) {
      memset(ifcfg, 0, sizeof(struct ifcfg));

      strcpy(ifcfg->name, netif->name);

      sin = (struct sockaddr_in *) &ifcfg->addr;
      sin->sin_family = AF_INET;
      sin->sin_addr.s_addr = netif->ipaddr.addr;

      sin = (struct sockaddr_in *) &ifcfg->gw;
      sin->sin_family = AF_INET;
      sin->sin_addr.s_addr = netif->gw.addr;

      sin = (struct sockaddr_in *) &ifcfg->netmask;
      sin->sin_family = AF_INET;
      sin->sin_addr.s_addr = netif->netmask.addr;

      sin = (struct sockaddr_in *) &ifcfg->broadcast;
      sin->sin_family = AF_INET;
      sin->sin_addr.s_addr = netif->broadcast.addr;

      memcpy(ifcfg->hwaddr, &netif->hwaddr, sizeof(struct eth_addr));

      if (netif->flags & NETIF_UP) ifcfg->flags |= IFCFG_UP;
      if (netif->flags & NETIF_DHCP) ifcfg->flags |= IFCFG_DHCP;
      if (netif->flags & NETIF_LOOPBACK) ifcfg->flags |= IFCFG_LOOPBACK;
      if (netif == netif_default) ifcfg->flags |= IFCFG_DEFAULT;

      netif = netif->next;
      ifcfg++;
    }
  }

  return numifs * sizeof(struct ifcfg);
}

int netif_ioctl_cfg(void *data, size_t size) {
  struct netif *netif;
  struct ifcfg *ifcfg;
  struct dhcp_state *state;

  if (!data) return -EFAULT;
  if (size != sizeof(struct ifcfg)) return -EINVAL;
  ifcfg = (struct ifcfg *) data;

  netif = netif_find(ifcfg->name);
  if (!netif) return -ENXIO;

  // Check for interface down
  if ((ifcfg->flags & IFCFG_UP) == 0 && (netif->flags & NETIF_UP) == 1) {
    // Release DHCP lease
    dhcp_stop(netif);
    netif->flags &= ~NETIF_UP;
  }

  // Update network interface configuration
  if (ifcfg->flags & IFCFG_DHCP) {
    netif->flags |= NETIF_DHCP;
  } else {
    netif->flags &= ~NETIF_DHCP;
  }

  netif->ipaddr.addr = ((struct sockaddr_in *) &ifcfg->addr)->sin_addr.s_addr;
  netif->netmask.addr = ((struct sockaddr_in *) &ifcfg->netmask)->sin_addr.s_addr;
  netif->gw.addr = ((struct sockaddr_in *) &ifcfg->gw)->sin_addr.s_addr;
  netif->broadcast.addr = ((struct sockaddr_in *) &ifcfg->broadcast)->sin_addr.s_addr;

  if (netif->broadcast.addr == IP_ADDR_ANY) {
    netif->broadcast.addr = (netif->ipaddr.addr & netif->netmask.addr) | ~(netif->netmask.addr);
  }

  if (ifcfg->flags & IFCFG_DEFAULT) {
    netif_default = netif;
  } else if (netif == netif_default) {
    netif_default = NULL;
  }

  // Copy hwaddr into ifcfg as info
  memcpy(ifcfg->hwaddr, &netif->hwaddr, sizeof(struct eth_addr));

  // Check for interface up
  if ((ifcfg->flags & IFCFG_UP) == 1 && (netif->flags & NETIF_UP) == 0) {
    netif->flags |= NETIF_UP;

    if (netif->flags & NETIF_DHCP) {
      // Obtain network parameters using DHCP
      state = dhcp_start(netif);
      if (state) {
        if (wait_for_object(&state->binding_complete, 30000)  < 0) return -ETIMEDOUT;

        ((struct sockaddr_in *) &ifcfg->addr)->sin_addr.s_addr = netif->ipaddr.addr;
        ((struct sockaddr_in *) &ifcfg->netmask)->sin_addr.s_addr = netif->netmask.addr;
        ((struct sockaddr_in *) &ifcfg->gw)->sin_addr.s_addr = netif->gw.addr;
        ((struct sockaddr_in *) &ifcfg->broadcast)->sin_addr.s_addr = netif->broadcast.addr;
      }
    }
  }

  return 0;
}