diff -Naur -X exclude-files ac_clean/arch/um/config.in ac/arch/um/config.in --- ac_clean/arch/um/config.in Sun May 27 15:42:43 2001 +++ ac/arch/um/config.in Sun May 27 16:46:01 2001 @@ -56,18 +56,12 @@ mainmenu_option next_comment comment 'Network device support' - bool 'Network device support' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - bool 'Virtual ethernet device' CONFIG_NET_UM_ETH - if [ "$CONFIG_NET_UM_ETH" = "y" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP - fi - fi - fi + bool 'Network device support' CONFIG_UML_NET + if [ "$CONFIG_UML_NET" = "y" ]; then + bool 'Ethertap transport' CONFIG_NET_ETHERTAP + bool 'Daemon transport' CONFIG_NET_DAEMON + bool 'Slip transport' CONFIG_NET_SLIP fi - bool 'Old slip-based network device' CONFIG_NET_UMN endmenu fi diff -Naur -X exclude-files ac_clean/arch/um/defconfig ac/arch/um/defconfig --- ac_clean/arch/um/defconfig Sun May 27 15:42:43 2001 +++ ac/arch/um/defconfig Sun May 27 16:48:47 2001 @@ -88,9 +88,11 @@ # # Network device support # -CONFIG_NETDEVICES=y -CONFIG_NET_UM_ETH=y -CONFIG_NET_UMN=y + +CONFIG_UML_NET=y +CONFIG_NET_ETHERTAP=y +CONFIG_NET_DAEMON=y +CONFIG_NET_SLIP=y # # File systems diff -Naur -X exclude-files ac_clean/arch/um/drivers/Makefile ac/arch/um/drivers/Makefile --- ac_clean/arch/um/drivers/Makefile Sun May 27 15:42:43 2001 +++ ac/arch/um/drivers/Makefile Sun May 27 16:46:50 2001 @@ -20,18 +20,23 @@ CFLAGS_chan_user.o := $(USER_CFLAGS) CFLAGS_ubd.o := $(CFLAGS) CFLAGS_ubd_user.o := $(USER_CFLAGS) -CFLAGS_umn_kern.o := $(CFLAGS) -CFLAGS_umn_user.o := $(USER_CFLAGS) -CFLAGS_eth_kern.o := $(CFLAGS) -CFLAGS_eth_user.o := $(USER_CFLAGS) +CFLAGS_slip_kern.o := $(CFLAGS) +CFLAGS_slip_user.o := $(USER_CFLAGS) +CFLAGS_ethertap_kern.o := $(CFLAGS) +CFLAGS_ethertap_user.o := $(USER_CFLAGS) +CFLAGS_daemon_kern.o := $(CFLAGS) +CFLAGS_daemon_user.o := $(USER_CFLAGS) +CFLAGS_net_kern.o := $(CFLAGS) obj-$(CONFIG_STDIO_CONSOLE) += stdio_console.o stdio_console_user.o obj-$(CONFIG_SSL) += ssl.o obj-$(CONFIG_SSL) += chan_user.o chan_kern.o obj-$(CONFIG_STDIO_CONSOLE) += chan_user.o chan_kern.o obj-$(CONFIG_BLK_DEV_UBD) += ubd.o ubd_user.o -obj-$(CONFIG_NET_UMN) += umn_user.o umn_kern.o -obj-$(CONFIG_NET_UM_ETH) += eth_kern.o eth_user.o +obj-$(CONFIG_UML_NET) += net_kern.o +obj-$(CONFIG_NET_SLIP) += slip_user.o slip_kern.o +obj-$(CONFIG_NET_ETHERTAP) += ethertap_user.o ethertap_kern.o +obj-$(CONFIG_NET_DAEMON) += daemon_kern.o daemon_user.o override CFLAGS = diff -Naur -X exclude-files ac_clean/arch/um/drivers/daemon.h ac/arch/um/drivers/daemon.h --- ac_clean/arch/um/drivers/daemon.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/daemon.h Sun May 27 16:14:35 2001 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#define ETH_ADDR_LEN 6 + +struct daemon_data { + char *sock_type; + char *ctl_sock; + char *data_sock; + void *ctl_addr; + void *data_addr; + void *local_addr; + unsigned char hwaddr[ETH_ADDR_LEN]; + int hw_setup; + int control; + void *dev; +}; + +extern struct net_user_info daemon_user_info; + +extern int daemon_user_set_mac(struct daemon_data *pri, unsigned char *hwaddr, + int len); +extern void daemon_setup(char *str, struct uml_net *dev); +extern int daemon_user_read(int fd, void *buf, int len, + struct daemon_data *data); +extern int daemon_user_write(int fd, void *buf, int len, + struct daemon_data *pri); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/daemon_kern.c ac/arch/um/drivers/daemon_kern.c --- ac_clean/arch/um/drivers/daemon_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/daemon_kern.c Sun May 27 16:14:35 2001 @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/etherdevice.h" +#include "net_kern.h" +#include "net_user.h" +#include "daemon.h" + +struct daemon_data daemon_priv[MAX_UML_NETDEV] = { + [ 0 ... MAX_UML_NETDEV - 1 ] = + { + sock_type: "unix", + ctl_sock: "/tmp/uml.ctl", + data_sock: "/tmp/uml.data", + hwaddr: { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, + hw_setup: 0, + control: -1, + } +}; + +struct net_device *daemon_init(int private_size, int index) +{ + struct net_device *dev; + struct uml_net_private *pri; + struct daemon_data *dpri; + + dev = init_etherdev(NULL, private_size); + if(dev == NULL) return(NULL); + pri = dev->priv; + dpri = (struct daemon_data *) pri->user; + *dpri = daemon_priv[index]; + memcpy(dev->dev_addr, dpri->hwaddr, ETH_ALEN); + printk("daemon backend"); + if(dpri->hw_setup) + printk("- ethernet address = %x:%x:%x:%x:%x:%x\n", + dpri->hwaddr[0], dpri->hwaddr[1], dpri->hwaddr[2], + dpri->hwaddr[3], dpri->hwaddr[4], dpri->hwaddr[5]); + printk("\n"); + return(dev); +} + +static unsigned short daemon_protocol(struct sk_buff *skb) +{ + return(eth_type_trans(skb, skb->dev)); +} + +static int daemon_set_mac(struct sockaddr *addr, void *data) +{ + struct daemon_data *pri = data; + struct net_device *dev = pri->dev; + struct sockaddr *hwaddr = addr; + + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + return(daemon_user_set_mac(pri, hwaddr->sa_data, ETH_ALEN)); +} + +static int daemon_read(int fd, struct sk_buff *skb, + struct uml_net_private *lp) +{ + if((skb != NULL) && (skb_tailroom(skb) < 14)){ + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, 0, 14, GFP_ATOMIC); + dev_kfree_skb(skb); + skb = skb2; + } + if(skb != NULL) skb_put(skb, 14); + return(daemon_user_read(fd, skb->mac.raw, skb->dev->mtu + 14, + (struct daemon_data *) &lp->user)); +} + +static int daemon_write(int fd, struct sk_buff *skb, + struct uml_net_private *lp) +{ + return(daemon_user_write(fd, skb->data, skb->len, + (struct daemon_data *) &lp->user)); +} + +static struct net_kern_info daemon_kern_info = { + init: daemon_init, + protocol: daemon_protocol, + set_mac: daemon_set_mac, + read: daemon_read, + write: daemon_write, +}; + +static int daemon_count = 0; + +void daemon_setup(char *str, struct uml_net *dev) +{ + int err, n = daemon_count; + + dev->user = &daemon_user_info; + dev->kern = &daemon_kern_info; + dev->private_size = sizeof(struct daemon_data); + dev->transport_index = daemon_count++; + if(*str != ',') return; + str++; + if(*str != ','){ + err = setup_etheraddr(str, daemon_priv[n].hwaddr); + if(!err) daemon_priv[n].hw_setup = 1; + } + str = strchr(str, ','); + if(str == NULL) return; + *str++ = '\0'; + if(*str != ',') daemon_priv[n].sock_type = str; + str = strchr(str, ','); + if(str == NULL) return; + *str++ = '\0'; + if(*str != ',') daemon_priv[n].ctl_sock = str; + str = strchr(str, ','); + if(str == NULL) return; + *str++ = '\0'; + if(*str != '\0') daemon_priv[n].data_sock = str; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/daemon_user.c ac/arch/um/drivers/daemon_user.c --- ac_clean/arch/um/drivers/daemon_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/daemon_user.c Sun May 27 16:14:35 2001 @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include +#include +#include +#include +#include +#include "net_user.h" +#include "daemon.h" +#include "kern_util.h" +#include "user_util.h" +#include "user.h" + +#define MAX_PACKET 1514 + +enum request_type { REQ_NEW_CONTROL }; + +struct request { + enum request_type type; + union { + struct { + unsigned char addr[ETH_ADDR_LEN]; + struct sockaddr_un name; + } new_control; + struct { + unsigned long cookie; + } new_data; + } u; +}; + +static struct sockaddr_un *new_addr(void *name, int len) +{ + struct sockaddr_un *sun; + + sun = um_kmalloc(sizeof(struct sockaddr_un)); + if(sun == NULL){ + printk("new_addr: allocation of sockaddr_un failed\n"); + return(NULL); + } + sun->sun_family = AF_UNIX; + memcpy(sun->sun_path, name, len); + return(sun); +} + +static void daemon_user_init(void *data, void *dev) +{ + struct daemon_data *pri = data; + struct timeval tv; + struct { + char zero; + int pid; + int usecs; + } name; + + if(!strcmp(pri->sock_type, "unix")){ + pri->ctl_addr = new_addr(pri->ctl_sock, + strlen(pri->ctl_sock) + 1); + pri->data_addr = new_addr(pri->data_sock, + strlen(pri->data_sock) + 1); + } + name.zero = 0; + name.pid = getpid(); + gettimeofday(&tv, NULL); + name.usecs = tv.tv_usec; + pri->local_addr = new_addr(&name, sizeof(name)); + pri->dev = dev; +} + +static int daemon_open(void *data) +{ + struct daemon_data *pri = data; + struct sockaddr_un *ctl_addr = pri->ctl_addr; + struct sockaddr_un *local_addr = pri->local_addr; + struct request req; + char addr[sizeof("255.255.255.255\0")]; + int fd, n, err; + + if(!pri->hw_setup){ + pri->hwaddr[0] = 0xfe; + pri->hwaddr[1] = 0xfd; + dev_ip_addr(pri->dev, addr, &pri->hwaddr[2]); + set_ether_mac(pri->dev, pri->hwaddr); + } + if((ctl_addr == NULL) || (pri->data_addr == NULL) || + (pri->local_addr == NULL)) + return(-EINVAL); + + if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ + printk("daemon_open : control socket failed, errno = %d\n", + errno); + return(-ENOMEM); + } + + if(connect(pri->control, ctl_addr, sizeof(*ctl_addr)) < 0){ + printk("daemon_open : control connect failed, errno = %d\n", + errno); + err = -ENOTCONN; + goto out; + } + + req.type = REQ_NEW_CONTROL; + memcpy(req.u.new_control.addr, pri->hwaddr, + sizeof(req.u.new_control.addr)); + req.u.new_control.name = *local_addr; + n = write(pri->control, &req, sizeof(req)); + if(n != sizeof(req)){ + printk("daemon_open : control setup request returned %d, " + "errno = %d\n", n, errno); + err = -ENOTCONN; + goto out; + } + + if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ + printk("daemon_open : data socket failed, errno = %d\n", + errno); + err = -ENOMEM; + goto out; + } + if(bind(fd, local_addr, sizeof(*local_addr)) < 0){ + printk("daemon_open : data bind failed, errno = %d\n", + errno); + close(fd); + err = -EINVAL; + goto out; + } + + return(fd); + out: + close(pri->control); + return(err); +} + +static void daemon_close(int fd, void *data) +{ + struct daemon_data *pri = data; + + close(fd); + close(pri->control); +} + +int daemon_user_read(int fd, void *buf, int len, struct daemon_data *data) +{ + int n; + + while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && + (errno == EINTR)) ; + if(n < 0){ + if(errno == EAGAIN) return(0); + return(-errno); + } + else if(n == 0) return(-ENOTCONN); + return(n); +} + +int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) +{ + int n; + struct sockaddr_un *data_addr = pri->data_addr; + + n = sendto(fd, buf, len, 0, data_addr, sizeof(*data_addr)); + if(n < 0) return(-errno); + return(n); +} + +static int daemon_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +int daemon_user_set_mac(struct daemon_data *pri, unsigned char *hwaddr, + int len) +{ + memcpy(pri->hwaddr, hwaddr, len); + return(0); +} + +struct net_user_info daemon_user_info = { + init: daemon_user_init, + open: daemon_open, + close: daemon_close, + set_mtu: daemon_set_mtu, + max_packet: MAX_PACKET - 14 +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/etap.h ac/arch/um/drivers/etap.h --- ac_clean/arch/um/drivers/etap.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/etap.h Sun May 27 16:13:58 2001 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +struct ethertap_data { + char *dev_name; + char *gate_addr; + int helper_fd; + void *dev; + unsigned char hw_addr[6]; + int hw_setup; +}; + +extern struct net_user_info ethertap_user_info; +extern void ethertap_setup(char *str, struct uml_net *dev); +extern int etap_user_write(int fd, void *buf, int len, + struct ethertap_data *pri); +extern int etap_user_read(int fd, void *buf, int len, + struct ethertap_data *pri); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/eth_kern.c ac/arch/um/drivers/eth_kern.c --- ac_clean/arch/um/drivers/eth_kern.c Sun May 27 15:42:43 2001 +++ ac/arch/um/drivers/eth_kern.c Wed Dec 31 19:00:00 1969 @@ -1,384 +0,0 @@ -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "user_util.h" -#include "eth_net.h" -#include "radix.h" - -extern int uml_net_user_mac(void); -extern int uml_net_user_close(int); -extern int uml_net_user_open(struct sockaddr *, void *, int, int); -extern int uml_net_user_join(int, int); -extern int uml_net_user_tx(int, char *, int); -extern int uml_net_user_rx(int, char *, int); - -#define MAC_NODE_NIBBLE 6 -#define MAC_TREE_DEPTH 48 - -struct mac_node { - RADIX_ENTRY(mac_node,MAC_NODE_NIBBLE) next; - int action; -}; - -RADIX_HEAD(mac_tree,mac_node); - -struct uml_net_private { - spinlock_t lock; - int socket; - int net_num; - struct net_device_stats stats; - struct net_device *next; - struct sockaddr addr; -}; - -static struct mac_tree mac_tree; -static struct net_device *uml_net_dev = NULL; - -void uml_net_interrupt(int, void *, struct pt_regs *); - -static int uml_net_rx(struct net_device *); -static int uml_net_open(struct net_device *); -static int uml_net_close(struct net_device *); -static int uml_net_set_mac(struct net_device *, void *); -static void uml_net_tx_timeout(struct net_device *dev); -static void uml_net_set_multicast_list(struct net_device *); -static int uml_net_ioctl(struct net_device *, struct ifreq *, int); -static int uml_net_start_xmit(struct sk_buff *, struct net_device *); -static struct net_device_stats *uml_net_get_stats(struct net_device *); -static int uml_net_insert_mac_tree(long long key,int value); - -int __init uml_net_probe(void) -{ - struct net_device *dev = NULL; - struct uml_net_private *lp; - struct sockaddr_in *sin; - long long key; - char *priv; - int i; - - RADIX_INIT(&mac_tree); - if(uml_net_insert_mac_tree(0xffffffffffff,0)) return -1; - - for (i = 0; i < 4; i++) { - - dev = init_etherdev(NULL, 0); - - if (dev == NULL) - return -ENOMEM; - - printk("User-mode Linux network interface 0.011 (%s)\n", - dev->name); - - if ((priv = kmalloc(sizeof(struct uml_net_private) + 15, - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - lp = (struct uml_net_private *)(((unsigned long)priv + 15) - & ~15); - - memset(lp, 0, sizeof(struct uml_net_private)); - sin = (struct sockaddr_in *)&lp->addr; - - sin->sin_family = AF_INET; - sin->sin_port = htons(UML_NET_PORT); - sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - lp->net_num = 100; - - /* Fill in the generic fields of the device structure. */ - ether_setup(dev); - - dev->priv = lp; - dev->open = uml_net_open; - dev->hard_start_xmit = uml_net_start_xmit; - dev->stop = uml_net_close; - dev->get_stats = uml_net_get_stats; - dev->set_multicast_list = uml_net_set_multicast_list; - dev->tx_timeout = uml_net_tx_timeout; - dev->set_mac_address = 0; // uml_net_set_mac; - dev->do_ioctl = uml_net_ioctl; - dev->watchdog_timeo = (HZ >> 1); - lp->next = uml_net_dev; - uml_net_dev = dev; - - spin_lock_init(&lp->lock); - - key = uml_net_user_mac(); - key <<= 16; - memcpy(dev->dev_addr, &key, ETH_ALEN); - uml_net_insert_mac_tree(key,dev->ifindex); - } - return 0; -} - -static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - - spin_lock(&lp->lock); - - if(dev->flags & IFF_UP) { - spin_unlock(&lp->lock); - return -EBUSY; - } - - switch (cmd) { - case SIOCDEVPRIVATE: - { - /* setting net number */ - lp->net_num = ifr->ifr_flags; - break; - } - case SIOCDEVPRIVATE+1: - { - - /* setting dst addr */ - if(ifr->ifr_dstaddr.sa_family) { - memcpy(&lp->addr, &ifr->ifr_dstaddr, - sizeof(struct sockaddr)); - } - break; - } - } - - spin_unlock(&lp->lock); - return 0; -} - -static int uml_net_open(struct net_device *dev) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - int err = 0; - - spin_lock(&lp->lock); - if(lp->socket) { - spin_unlock(&lp->lock); - return(-ENXIO); - } - lp->socket = uml_net_user_open(&lp->addr, (void *)dev, dev->irq, - lp->net_num); - - if (lp->socket < 0) { - printk("uml_net_open: failed(%d)\n", lp->socket); - lp->socket = 0; - spin_unlock(&lp->lock); - return -ENETUNREACH; - } - - dev->irq = UM_ETH_IRQ; - if((err = um_request_irq(dev->irq, lp->socket, uml_net_interrupt, - SA_INTERRUPT | SA_SHIRQ, dev->name, dev)) != 0) { - spin_unlock(&lp->lock); - uml_net_user_close(lp->socket); - printk("uml_net_open: failed to get irq(%d)\n", err); - return -ENETUNREACH; - } - - spin_unlock(&lp->lock); - - netif_start_queue(dev); - - return 0; -} - -static void uml_net_tx_timeout(struct net_device *dev) -{ - printk("uml_net_tx_timeout enter\n"); - - dev->trans_start = jiffies; - netif_wake_queue(dev); - - printk("uml_net_tx_timeout exit\n"); -} - -static int uml_net_get_mac_node(long long key) -{ - int res = 0; - int value = -1; - RADIX_GET(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, - key,48,action,value,res); - if(res) { - return -1; - } - return value; -} - -static int uml_net_insert_mac_tree(long long key,int value) -{ - int res = 0; - - RADIX_INSERT(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, - key,48,res); - - if(res) { - return -1; - } - RADIX_SET(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, - key,48,action,value,res); - if(res) { - return -1; - } - return 0; -} - -static int uml_net_set_mac(struct net_device *dev, void *addr) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - struct sockaddr *hwaddr = (struct sockaddr *)addr; - long long key = 0; - - memcpy(&key,hwaddr->sa_data,ETH_ALEN); - uml_net_insert_mac_tree(key,dev->ifindex); - - spin_lock(&lp->lock); - memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); - spin_unlock(&lp->lock); - - return 0; -} - -static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - unsigned long flags; - int size; - - netif_stop_queue(dev); - - spin_lock_irqsave(&lp->lock, flags); - - size = uml_net_user_tx(lp->socket, skb->data, skb->len); - if (size == skb->len) { - lp->stats.tx_packets++; - lp->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - netif_start_queue(dev); - /* this is normally done in the interrupt when tx finishes */ - netif_wake_queue(dev); - } else { - printk("uml_net_start_xmit: failed(%d)\n", size); - } - - spin_unlock_irqrestore(&lp->lock, flags); - - dev_kfree_skb(skb); - - return 0; -} - -void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - int count = 0; - int retval = 0; - - spin_lock(&lp->lock); - - while ((retval = uml_net_rx(dev)) > 0) { - count++; - if(count > 100) { - break; - } - } - - spin_unlock(&lp->lock); - - if (retval < 0) { - uml_net_close(dev); - } -} - -static int uml_net_rx(struct net_device *dev) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - unsigned char buffer[MAX_PACKET]; - struct sk_buff *skb; - int pkt_len = 0; - unsigned int value; - long long key = 0; - - if ((pkt_len = uml_net_user_rx(lp->socket, buffer, MAX_PACKET)) > 0) { - /* - * look at the dev flags and the dest MAC to determin if this - * frame is for us - */ - - if (dev->flags & IFF_PROMISC) { - goto uml_net_rx_accept; - } - - memcpy(&key,buffer,ETH_ALEN); - if ((key & 0x010000000000) && (dev->flags & IFF_ALLMULTI)) { - goto uml_net_rx_accept; - } - - value = uml_net_get_mac_node(key); - if (value == dev->ifindex || value == 0) { - goto uml_net_rx_accept; - } - - goto uml_net_rx_drop; /* No match */ - -uml_net_rx_accept: - if ((skb = dev_alloc_skb(MAX_PACKET)) != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); - skb_put(skb, pkt_len); - eth_copy_and_sum(skb, buffer, pkt_len, 0); - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - lp->stats.rx_bytes += skb->len; - lp->stats.rx_packets++; - } - return 1; - } else if(pkt_len < 0) { - return -1; - } - return 0; - -uml_net_rx_drop: - lp->stats.rx_dropped++; - return 1; -} - -static int uml_net_close(struct net_device *dev) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - - netif_stop_queue(dev); - - spin_lock(&lp->lock); - - uml_net_user_close(lp->socket); - lp->socket = 0; - free_irq(dev->irq, dev); - - spin_unlock(&lp->lock); - return 0; -} - -static struct net_device_stats *uml_net_get_stats(struct net_device *dev) -{ - struct uml_net_private *lp = (struct uml_net_private *)dev->priv; - return &lp->stats; -} - -static void uml_net_set_multicast_list(struct net_device *dev) -{ - if (dev->flags & IFF_PROMISC) { - printk("%s: Promiscuous mode enabled.\n", dev->name); - } -} diff -Naur -X exclude-files ac_clean/arch/um/drivers/eth_net.h ac/arch/um/drivers/eth_net.h --- ac_clean/arch/um/drivers/eth_net.h Sun May 27 15:42:43 2001 +++ ac/arch/um/drivers/eth_net.h Wed Dec 31 19:00:00 1969 @@ -1,13 +0,0 @@ -#ifndef INCLUDE_NET_ETH_NET_H -#define INCLUDE_NET_ETH_NET_H - -#define MAX_PACKET 1544 -#define UML_NET_PORT 5299 -#define DEFAULT_NET_NUM 100 -#define UML_HDR_SIZE (sizeof(unsigned int)*2) - -enum packet_type { - PACKET_DATA = 1, - PACKET_MGMT -}; -#endif diff -Naur -X exclude-files ac_clean/arch/um/drivers/eth_user.c ac/arch/um/drivers/eth_user.c --- ac_clean/arch/um/drivers/eth_user.c Sun May 27 15:42:43 2001 +++ ac/arch/um/drivers/eth_user.c Wed Dec 31 19:00:00 1969 @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "user.h" -#include "user_util.h" -#include "eth_net.h" - -int uml_net_user_mac(void) -{ - static int first = 1; - - if(first) { - srand(time(NULL)); - first = 0; - } - return rand(); -} - -static int nb_write(int fd, void *buf, int tot) { - int len = 0; - int remain = tot; - int retval; - -write_try_again: - retval = write(fd, buf+len, remain); - if (retval < 0) { - if (errno == EAGAIN || errno == EINTR) { - goto write_try_again; - } - return -1; - } - if (retval < remain) { - remain -= retval; - len += retval; - goto write_try_again; - } - return 0; -} - -static int nb_read(int fd, void *buf, int tot, int flag) { - int len = 0; - int remain = tot; - int retval; - -read_try_again: - retval = read(fd, buf+len, remain); - if (retval < 0) { - if (errno == EINTR) { - goto read_try_again; - } - if (flag && (errno == EAGAIN)) { - goto read_try_again; - } else { - return 0; - } - return -1; - } - if(retval < remain) { - if(!retval) { - return -1; - } - len += retval; - remain -= retval; - flag = 1; - goto read_try_again; - } - return tot; -} - -int uml_net_user_join(int fd, int net_num) -{ - unsigned int header[3]; - - if (fd < 0) - return -ENOTCONN; - - header[0] = htonl(PACKET_MGMT); - header[1] = htonl(sizeof(unsigned int)); - header[2] = htonl(net_num); - - return nb_write(fd, header, UML_HDR_SIZE + sizeof(unsigned int)); -} - -int uml_net_user_open(struct sockaddr *addr, void *dev, int irq,int net_num) -{ - int new_fd; - - if ((new_fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) - return -ENOMEM; - - if (connect(new_fd,(struct sockaddr*)addr, - sizeof(struct sockaddr)) < 0) { - close(new_fd); - return -ENOTCONN; - } - - if(uml_net_user_join(new_fd,net_num) < 0) { - close(new_fd); - return -ENOTCONN; - } - - return new_fd; -} - -int uml_net_user_tx(int fd, char *buffer, int len) -{ - unsigned char hbuf[MAX_PACKET + UML_HDR_SIZE]; - unsigned char *buf = hbuf + UML_HDR_SIZE; - unsigned int *header = (unsigned int*)hbuf; - int retval = 0; - - if (fd < 0) - return -ENOTCONN; - - if(len > MAX_PACKET) panic("Too big packet"); - - memcpy(buf,buffer,len); - - header[0] = htonl(PACKET_DATA); - header[1] = htonl(len); - - retval = nb_write(fd, hbuf, UML_HDR_SIZE + len); - if (retval) { - return -1; - } - return len; -} - -int uml_net_user_rx(int fd, char *buf, int len) -{ - int retval = 0; - int header[2]; - - if (fd < 0) - return -1; - - retval = nb_read(fd, header, UML_HDR_SIZE,0); - if (retval < 0) { - return -1; - } - if(retval) { - retval = nb_read(fd, buf, ntohl(header[1]),1); - if (retval < 0) { - return -1; - } - } - - reactivate_fd(fd); - return retval; -} - -int __inline__ uml_net_user_close(int fd) -{ - shutdown(fd,SHUT_RDWR); - return 0; -} diff -Naur -X exclude-files ac_clean/arch/um/drivers/ethertap_kern.c ac/arch/um/drivers/ethertap_kern.c --- ac_clean/arch/um/drivers/ethertap_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/ethertap_kern.c Sun May 27 16:13:58 2001 @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/etherdevice.h" +#include "net_kern.h" +#include "net_user.h" +#include "etap.h" + +struct ethertap_setup { + char *dev_name; + unsigned char hw_addr[ETH_ALEN]; + int hw_setup; + char *gate_addr; +}; + +struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = { + { + dev_name: "tap0", + hw_addr: { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, + hw_setup: 0, + gate_addr: NULL, + }, + [ 1 ... MAX_UML_NETDEV - 1 ] = + { + dev_name: NULL, + hw_addr: { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, + hw_setup: 1, + gate_addr: NULL, + } +}; + +struct net_device *etap_init(int private_size, int index) +{ + struct net_device *dev; + struct uml_net_private *pri; + struct ethertap_data *epri; + + dev = init_etherdev(NULL, private_size); + if(dev == NULL) return(NULL); + pri = dev->priv; + epri = (struct ethertap_data *) pri->user; + epri->dev_name = ethertap_priv[index].dev_name; + epri->gate_addr = ethertap_priv[index].gate_addr; + memcpy(dev->dev_addr, ethertap_priv[index].hw_addr, ETH_ALEN); + memcpy(epri->hw_addr, ethertap_priv[index].hw_addr, + sizeof(epri->hw_addr)); + printk("TAP backend - %s", epri->dev_name); + if(epri->gate_addr != NULL) printk(", IP = %s", epri->gate_addr); + epri->hw_setup = ethertap_priv[index].hw_setup; + if(epri->hw_setup) + printk(", ether = %x:%x:%x:%x:%x:%x", + epri->hw_addr[0], epri->hw_addr[1], epri->hw_addr[2], + epri->hw_addr[3], epri->hw_addr[4], epri->hw_addr[5]); + printk("\n"); + return(dev); +} + +static unsigned short etap_protocol(struct sk_buff *skb) +{ + return(eth_type_trans(skb, skb->dev)); +} + +static int etap_set_mac(struct sockaddr *addr, void *data) +{ + struct ethertap_data *pri = data; + struct sockaddr *hwaddr = addr; + + memcpy(pri->hw_addr, hwaddr->sa_data, ETH_ALEN); + + return 0; +} + +static int etap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + int len; + + len = etap_user_read(fd, skb->mac.raw, skb->dev->mtu, + (struct ethertap_data *) &lp->user); + if(len <= 0) return(len); + skb_pull(skb, 2); + len -= 2; + return(len); +} + +static int etap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + if(skb_headroom(skb) < 2){ + struct sk_buff *skb2; + + skb2 = skb_realloc_headroom(skb, 2); + dev_kfree_skb(skb); + if (skb2 == NULL) return(-ENOMEM); + skb = skb2; + } + skb_push(skb, 2); + return(etap_user_write(fd, skb->data, skb->len, + (struct ethertap_data *) &lp->user)); +} + +struct net_kern_info ethertap_kern_info = { + init: etap_init, + protocol: etap_protocol, + set_mac: etap_set_mac, + read: etap_read, + write: etap_write, +}; + +static int ethertap_count = 0; + +void ethertap_setup(char *str, struct uml_net *dev) +{ + int err, n = ethertap_count; + + dev->user = ðertap_user_info; + dev->kern = ðertap_kern_info; + dev->private_size = sizeof(struct ethertap_data); + dev->transport_index = ethertap_count++; + if(*str != ','){ + printk("ethertap_setup: expected ',' after 'ethertap'\n"); + return; + } + str++; + if(*str != ',') ethertap_priv[n].dev_name = str; + str = strchr(str, ','); + if(str == NULL) return; + *str++ = '\0'; + if(*str != ','){ + err = setup_etheraddr(str, ethertap_priv[n].hw_addr); + if(!err) ethertap_priv[n].hw_setup = 1; + } + str = strchr(str, ','); + if(str == NULL) return; + *str++ = '\0'; + if(*str != '\0') ethertap_priv[n].gate_addr = str; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/ethertap_user.c ac/arch/um/drivers/ethertap_user.c --- ac_clean/arch/um/drivers/ethertap_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/ethertap_user.c Sun May 27 16:13:58 2001 @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "kern_util.h" +#include "net_user.h" +#include "etap.h" + +#define MAX_PACKET 1500 + +void etap_user_init(void *data, void *dev) +{ + struct ethertap_data *pri = data; + + pri->dev = dev; +} + +struct etap_open_data { + char *name; + char *gate; + char *addr; + int fd; + int me; + int err; +}; + +void etap_tramp(void *arg) +{ + struct etap_open_data *data = arg; + int pid, status, n; + char fd_buf[sizeof("nnnnnn\0")]; + char addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; + char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")], c; + char *setup_args[] = { "uml_net", "ethertap", data->name, fd_buf, + gate_buf, addr_buf, NULL }; + char *nosetup_args[] = { "uml_net", "ethertap", data->name, fd_buf, + NULL }; + char **args; + + sprintf(fd_buf, "%d", data->fd); + if(data->gate != NULL){ + strcpy(addr_buf, data->addr); + strcpy(gate_buf, data->gate); + args = setup_args; + } + else args = nosetup_args; + data->err = 0; + if((pid = fork()) == 0){ + close(data->me); + execvp(args[0], args); + exit(errno); + } + else if(pid < 0) data->err = errno; + n = read(data->me, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("etap_open - failed to read response from helper : " + "return = %d, errno = %d\n", n, errno); + if(waitpid(pid, &status, 0) < 0) data->err = errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){ + printk("'ethertap_helper' didn't exit with " + "status 1\n"); + data->err = EINVAL; + } + else data->err = EINVAL; + } + else if(c != 1) data->err = EINVAL; +} + +static int etap_open(void *data) +{ + struct ethertap_data *pri = data; + struct etap_open_data tap_data; + int fds[2]; + char addr[sizeof("255.255.255.255\0")], ether[6]; + + dev_ip_addr(pri->dev, addr, ðer[2]); + if(!pri->hw_setup){ + ether[0] = 0xfe; + ether[1] = 0xfd; + set_ether_mac(pri->dev, ether); + } + tap_data.name = pri->dev_name; + if(socketpair(PF_UNIX, SOCK_DGRAM, 0, fds) < 0){ + printk("socketpair failed - errno = %d\n", errno); + return(-errno); + } + tap_data.fd = fds[1]; + tap_data.me = fds[0]; + tap_data.gate = pri->gate_addr; + tap_data.addr = addr; + tracing_cb(etap_tramp, &tap_data); + if(tap_data.err != 0){ + printk("etap_tramp failed - errno = %d\n", tap_data.err); + return(-tap_data.err); + } + pri->helper_fd = fds[1]; + return(fds[0]); +} + +static void etap_close(int fd, void *data) +{ + struct ethertap_data *pri = data; + + printk("Closing down ethertap\n"); + close(fd); + shutdown(pri->helper_fd, SHUT_RDWR); +} + +int etap_user_read(int fd, void *buf, int len, struct ethertap_data *pri) +{ + int n; + + while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && + (errno == EINTR)) ; + if(n < 0){ + if(errno == EAGAIN) return(0); + return(-errno); + } + return(n); +} + +int etap_user_write(int fd, void *buf, int len, struct ethertap_data *pri) +{ + int n; + + while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; + if(errno == EAGAIN) n = 0; + if(n < 0) return(-errno); + return(n); +} + +static int etap_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +struct net_user_info ethertap_user_info = { + init: etap_user_init, + open: etap_open, + close: etap_close, + set_mtu: etap_set_mtu, + max_packet: MAX_PACKET +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/net_kern.c ac/arch/um/drivers/net_kern.c --- ac_clean/arch/um/drivers/net_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/net_kern.c Sun May 27 16:13:13 2001 @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include "linux/config.h" +#include "linux/netdevice.h" +#include "linux/skbuff.h" +#include "linux/socket.h" +#include "linux/spinlock.h" +#include "linux/module.h" +#include "linux/init.h" +#include "linux/autoconf.h" +#include "linux/etherdevice.h" +#include "linux/list.h" +#include "linux/inetdevice.h" +#include "user_util.h" +#include "net_kern.h" +#include "net_user.h" +#include "slip.h" +#include "etap.h" +#include "daemon.h" + +LIST_HEAD(opened); + +struct uml_net devices[MAX_UML_NETDEV] = { + [ 0 ... MAX_UML_NETDEV - 1 ] = + { + user: NULL, + kern: NULL, + private_size: 0, + } +}; + +static int eth_setup(char *str) +{ + char *end; + int n; + + n = simple_strtoul(str, &end, 0); + if(end == str){ + printk("eth_setup: Failed to parse '%s'\n", str); + return(1); + } + if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){ + printk("eth_setup: device %d out of range\n", n); + return(1); + } + str = end; + if(*str != '='){ + printk("eth_setup: expected '=' after device number\n"); + return(1); + } + str++; +#ifdef CONFIG_NET_ETHERTAP + if(!strncmp(str, "ethertap", strlen("ethertap"))) + ethertap_setup(&str[strlen("ethertap")], &devices[n]); +#endif +#ifdef CONFIG_NET_DAEMON + if(!strncmp(str, "daemon", strlen("daemon"))) + daemon_setup(&str[strlen("daemon")], &devices[n]); +#endif +#ifdef CONFIG_NET_SLIP + if(!strncmp(str, "slip", strlen("slip"))) + slip_setup(&str[strlen("slip")], &devices[n]); +#endif + return(1); +} + +__setup("eth", eth_setup); + +int ndev = 0; + +static int uml_net_rx(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + int pkt_len; + struct sk_buff *skb; + + /* If we can't allocate memory, try again next round. */ + if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { + lp->stats.rx_dropped++; + return 0; + } + + skb->dev = dev; + skb_put(skb, dev->mtu); + skb->mac.raw = skb->data; + pkt_len = (*lp->read)(lp->fd, skb, lp); + + reactivate_fd(lp->fd); + if (pkt_len > 0) { + skb_trim(skb, pkt_len); + skb->protocol = (*lp->protocol)(skb); + netif_rx(skb); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + return pkt_len; + } + + kfree_skb(skb); + return pkt_len; +} + +void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct uml_net_private *lp = dev->priv; + int err; + + if (netif_running(dev)) { + spin_lock(&lp->lock); + while((err = uml_net_rx(dev)) > 0) ; + if(err < 0) { + printk("Device '%s' read returned %d, shutting it " + "down\n", dev->name, err); + dev->flags &= ~IFF_UP; + dev_close(dev); + } + spin_unlock(&lp->lock); + } +} + +static int uml_net_open(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + int err; + + spin_lock(&lp->lock); + + if(lp->fd >= 0){ + err = -ENXIO; + goto out; + } + + lp->fd = (*lp->open)(&lp->user); + if(lp->fd < 0){ + err = lp->fd; + goto out; + } + + err = um_request_irq(dev->irq, lp->fd, uml_net_interrupt, + SA_INTERRUPT | SA_SHIRQ, dev->name, dev); + if(err != 0){ + printk("uml_net_open: failed to get irq(%d)\n", err); + (*lp->close)(lp->fd, &lp->user); + lp->fd = -1; + err = -ENETUNREACH; + } + + lp->tl.data = (unsigned long) &lp->user; + netif_start_queue(dev); + + list_add(&lp->list, &opened); + MOD_INC_USE_COUNT; + out: + spin_unlock(&lp->lock); + return(err); +} + +static int uml_net_close(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + + netif_stop_queue(dev); + spin_lock(&lp->lock); + + free_irq_fd(dev); + (*lp->close)(lp->fd, &lp->user); + lp->fd = -1; + list_del(&lp->list); + + MOD_DEC_USE_COUNT; + spin_unlock(&lp->lock); + return 0; +} + +static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + unsigned long flags; + int len; + + netif_stop_queue(dev); + + spin_lock_irqsave(&lp->lock, flags); + + len = (*lp->write)(lp->fd, skb, lp); + + if(len == skb->len) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* this is normally done in the interrupt when tx finishes */ + netif_wake_queue(dev); + } + else if(len == 0){ + netif_start_queue(dev); + lp->stats.tx_dropped++; + } + else { + netif_start_queue(dev); + printk("uml_net_start_xmit: failed(%d)\n", len); + } + + spin_unlock_irqrestore(&lp->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +static struct net_device_stats *uml_net_get_stats(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + return &lp->stats; +} + +static void uml_net_set_multicast_list(struct net_device *dev) +{ + if (dev->flags & IFF_PROMISC) return; + else if (dev->mc_count) dev->flags |= IFF_ALLMULTI; + else dev->flags &= ~IFF_ALLMULTI; +} + +static void uml_net_tx_timeout(struct net_device *dev) +{ + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int uml_net_set_mac(struct net_device *dev, void *addr) +{ + struct uml_net_private *lp = dev->priv; + struct sockaddr *hwaddr = addr; + int err; + + spin_lock(&lp->lock); + + err = (*lp->set_mac)(hwaddr, &lp->user); + + spin_unlock(&lp->lock); + + return err; +} + +static int uml_net_change_mtu(struct net_device *dev, int new_mtu) +{ + struct uml_net_private *lp = dev->priv; + int err = 0; + + spin_lock(&lp->lock); + + new_mtu = (*lp->set_mtu)(new_mtu, &lp->user); + if(new_mtu < 0){ + err = new_mtu; + goto out; + } + + dev->mtu = new_mtu; + + out: + spin_unlock(&lp->lock); + return err; +} + +static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return(-EINVAL); +} + +void uml_net_user_timer_expire(unsigned long _conn) +{ +#ifdef undef + struct connection *conn = (struct connection *)_conn; + + dprintk("uml_net_user_timer_expire [%p]\n", conn); + do_connect(conn); +#endif +} + +int __init uml_net_probe(void) +{ + struct net_device *dev; + struct uml_net_private *lp; + int i; + + for(i = 0; i < sizeof(devices)/sizeof(devices[0]); i++){ + if(devices[i].user == NULL) continue; + devices[i].private_size += sizeof(struct uml_net_private) + + sizeof(((struct uml_net_private *) 0)->user); + printk("Netdevice %d : ", i); + dev = (*devices[i].kern->init)(devices[i].private_size, + devices[i].transport_index); + + if (dev == NULL) + return -ENOMEM; + + dev->mtu = devices[i].user->max_packet; + dev->open = uml_net_open; + dev->hard_start_xmit = uml_net_start_xmit; + dev->stop = uml_net_close; + dev->get_stats = uml_net_get_stats; + dev->set_multicast_list = uml_net_set_multicast_list; + dev->tx_timeout = uml_net_tx_timeout; + dev->set_mac_address = uml_net_set_mac; + dev->change_mtu = uml_net_change_mtu; + dev->do_ioctl = uml_net_ioctl; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = UM_ETH_IRQ; + + lp = dev->priv; + spin_lock_init(&lp->lock); + init_timer(&lp->tl); + lp->tl.function = uml_net_user_timer_expire; + lp->list = ((struct list_head) LIST_HEAD_INIT(lp->list)); + memset(&lp->stats, 0, sizeof(lp->stats)); + lp->fd = -1; + lp->protocol = devices[i].kern->protocol; + lp->set_mac = devices[i].kern->set_mac; + lp->open = devices[i].user->open; + lp->close = devices[i].user->close; + lp->read = devices[i].kern->read; + lp->write = devices[i].kern->write; + lp->set_mtu = devices[i].user->set_mtu; + + if(devices[i].user->init) + (*devices[i].user->init)(&lp->user, dev); + } + return(0); +} + +static void close_devices(void) +{ + struct list_head *ele; + struct uml_net_private *lp; + + list_for_each(ele, &opened){ + lp = list_entry(ele, struct uml_net_private, list); + (*lp->close)(lp->fd, &lp->user); + } +} + +__exitcall(close_devices); + +int setup_etheraddr(char *str, unsigned char *addr) +{ + char *end; + int i; + + for(i=0;i<6;i++){ + addr[i] = simple_strtoul(str, &end, 16); + if((end == str) || + ((*end != ':') && (*end != ',') && (*end != '\0'))){ + printk("setup_etheraddr: failed to parse '%s' " + "as an ethernet address\n", str); + return(-1); + } + str = end + 1; + } + return(0); +} + +void dev_ip_addr(void *d, char *buf, char *bin_buf) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in = ip->ifa_list; + u32 addr = in->ifa_address; + + sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, + (addr >> 16) & 0xff, addr >> 24); + if(bin_buf){ + bin_buf[0] = addr & 0xff; + bin_buf[1] = (addr >> 8) & 0xff; + bin_buf[2] = (addr >> 16) & 0xff; + bin_buf[3] = addr >> 24; + } +} + +void set_ether_mac(void *d, unsigned char *addr) +{ + struct net_device *dev = d; + + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/net_kern.h ac/arch/um/drivers/net_kern.h --- ac_clean/arch/um/drivers/net_kern.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/net_kern.h Sun May 27 16:53:33 2001 @@ -0,0 +1,52 @@ +#ifndef __UM_NET_KERN_H +#define __UM_NET_KERN_H + +#include "linux/netdevice.h" +#include "linux/skbuff.h" +#include "linux/socket.h" +#include "linux/list.h" + +#define MAX_UML_NETDEV (16) + +struct uml_net_private { + spinlock_t lock; + + struct timer_list tl; + struct list_head list; + struct net_device_stats stats; + int fd; + unsigned short (*protocol)(struct sk_buff *); + int (*set_mac)(struct sockaddr *hwaddr, void *); + int (*open)(void *); + void (*close)(int, void *); + int (*read)(int, struct sk_buff *skb, struct uml_net_private *); + int (*write)(int, struct sk_buff *skb, struct uml_net_private *); + int (*set_mtu)(int mtu, void *); + int user[1]; +}; + +struct net_kern_info { + struct net_device *(*init)(int, int); + unsigned short (*protocol)(struct sk_buff *); + int (*set_mac)(struct sockaddr *hwaddr, void *); + int (*read)(int, struct sk_buff *skb, struct uml_net_private *); + int (*write)(int, struct sk_buff *skb, struct uml_net_private *); +}; + +extern struct net_device *ether_init(int); +extern unsigned short ether_protocol(struct sk_buff *); +extern int ether_set_mac(struct sockaddr *hwaddr, void *); +extern int setup_etheraddr(char *str, unsigned char *addr); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/net_user.h ac/arch/um/drivers/net_user.h --- ac_clean/arch/um/drivers/net_user.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/net_user.h Sun May 27 16:13:13 2001 @@ -0,0 +1,34 @@ +#ifndef __UM_NET_USER_H__ +#define __UM_NET_USER_H__ + +struct uml_net { + struct net_user_info *user; + struct net_kern_info *kern; + int private_size; + int transport_index; +}; + +struct net_user_info { + void (*init)(void *, void *); + int (*open)(void *); + void (*close)(int, void *); + int (*set_mtu)(int mtu, void *); + int max_packet; +}; + +extern void ether_user_init(void *data, void *dev); +extern void dev_ip_addr(void *d, char *buf, char *bin_buf); +extern void set_ether_mac(void *d, unsigned char *addr); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/slip.h ac/arch/um/drivers/slip.h --- ac_clean/arch/um/drivers/slip.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/slip.h Sun May 27 16:12:23 2001 @@ -0,0 +1,34 @@ +#ifndef __UM_SLIP_H +#define __UM_SLIP_H + +#define BUF_SIZE 1500 + +struct slip_data { + void *dev; + char *addr; + char *gate_addr; + int slave; + char buf[2 * BUF_SIZE]; + int pos; + int esc; +}; + +extern struct net_user_info slip_user_info; + +extern int set_umn_addr(int fd, char *addr, char *ptp_addr); +extern void slip_setup(char *arg, struct uml_net *dev); +extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri); +extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/slip_kern.c ac/arch/um/drivers/slip_kern.c --- ac_clean/arch/um/drivers/slip_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/slip_kern.c Sun May 27 16:12:23 2001 @@ -0,0 +1,104 @@ +#include "linux/stddef.h" +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/if_arp.h" +#include "net_kern.h" +#include "net_user.h" +#include "kern.h" +#include "slip.h" + +struct slip_data slip_priv[MAX_UML_NETDEV] = { + [ 0 ... MAX_UML_NETDEV - 1 ] = + { + addr: NULL, + gate_addr: NULL, + slave: -1, + buf: { 0 }, + pos: 0, + esc: 0, + } +}; + +struct net_device umn_dev; + +struct net_device *slip_init(int private_size, int index) +{ + struct uml_net_private *private; + struct slip_data *spri; + + private = kmalloc(private_size, GFP_KERNEL); + if(private == NULL) return(NULL); + umn_dev.priv = private; + spri = (struct slip_data *) private->user; + *spri = slip_priv[index]; + strncpy(umn_dev.name, "umn", IFNAMSIZ); + umn_dev.init = NULL; + umn_dev.hard_header_len = 0; + umn_dev.addr_len = 4; + umn_dev.type = ARPHRD_ETHER; + umn_dev.tx_queue_len = 256; + umn_dev.flags = IFF_NOARP; + if(register_netdev(&umn_dev)) + printk("Couldn't initialize umn\n"); + printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr); + + return(&umn_dev); +} + +static int slip_set_mac(struct sockaddr *hwaddr, void *data) +{ + return(0); +} + +static unsigned short slip_protocol(struct sk_buff *skbuff) +{ + return(htons(ETH_P_IP)); +} + +static int slip_read(int fd, struct sk_buff *skb, + struct uml_net_private *lp) +{ + return(slip_user_read(fd, skb->mac.raw, skb->dev->mtu, + (struct slip_data *) &lp->user)); +} + +static int slip_write(int fd, struct sk_buff *skb, + struct uml_net_private *lp) +{ + return(slip_user_write(fd, skb->data, skb->len, + (struct slip_data *) &lp->user)); +} + +struct net_kern_info slip_kern_info = { + init: slip_init, + protocol: slip_protocol, + set_mac: slip_set_mac, + read: slip_read, + write: slip_write, +}; + +static int slip_count = 0; + +void slip_setup(char *str, struct uml_net *dev) +{ + int n = slip_count; + + dev->user = &slip_user_info; + dev->kern = &slip_kern_info; + dev->private_size = sizeof(struct slip_data); + dev->transport_index = slip_count++; + if(*str != ',') return; + str++; + if(str[0] != '\0') slip_priv[n].gate_addr = str; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/arch/um/drivers/slip_user.c ac/arch/um/drivers/slip_user.c --- ac_clean/arch/um/drivers/slip_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/slip_user.c Sun May 27 16:12:24 2001 @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "net_user.h" +#include "slip.h" + +void slip_user_init(void *data, void *dev) +{ + struct slip_data *pri = data; + + pri->dev = dev; +} + +static int set_up_tty(int fd) +{ + int i; + struct termios tios; + + if (tcgetattr(fd, &tios) < 0) { + printk("could not get initial terminal attributes\n"); + return(-1); + } + + tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; + tios.c_iflag = IGNBRK | IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + for (i = 0; i < NCCS; i++) + tios.c_cc[i] = 0; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + + cfsetospeed(&tios, B38400); + cfsetispeed(&tios, B38400); + + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + printk("failed to set terminal attributes\n"); + return(-1); + } + return(0); +} + +struct slip_tramp_data { + char **args; + int err; +}; + +void slip_tramp(void *arg) +{ + struct slip_tramp_data *data = arg; + char **argv = data->args; + int status, pid; + + data->err = 0; + if((pid = fork()) == 0){ + execvp(argv[0], argv); + exit(errno); + } + else if(pid < 0) data->err = errno; + else { + if(waitpid(pid, &status, 0) < 0) data->err = errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ + printk("'%s' didn't exit with status 0\n", argv[0]); + data->err = EINVAL; + } + } +} + +static int slip_open(void *data) +{ + struct slip_data *pri = data; + struct slip_tramp_data slip_data; + char fd_buf[sizeof("nnnnnn\0")], addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; + char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; + char *argv[] = { "uml_net", "slip", "up", fd_buf, gate_buf, addr_buf, + NULL }; + int sfd, mfd, disc, sencap; + + if((mfd = get_pty()) < 0){ + printk("umn : Failed to open pty\n"); + return(-1); + } + if((sfd = open(ptsname(mfd), O_RDWR)) < 0){ + printk("Couldn't open tty for slip line\n"); + return(-1); + } + if(set_up_tty(sfd)) return(-1); + pri->slave = sfd; + pri->pos = 0; + pri->esc = 0; + if(pri->gate_addr != NULL){ + sprintf(fd_buf, "%d", sfd); + dev_ip_addr(pri->dev, addr_buf, NULL); + strcpy(gate_buf, pri->gate_addr); + slip_data.args = argv; + tracing_cb(slip_tramp, &slip_data); + if(slip_data.err != 0){ + printk("slip_tramp failed - errno = %d\n", + slip_data.err); + return(-slip_data.err); + } + } + else { + disc = N_SLIP; + if(ioctl(sfd, TIOCSETD, &disc) < 0){ + printk("Failed to set slip line discipline - " + "errno = %d\n", errno); + return(-errno); + } + sencap = 0; + if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ + printk("Failed to sett slip encapsulation - " + "errno = %d\n", errno); + return(-errno); + } + } + return(mfd); +} + +static void slip_close(int fd, void *data) +{ + struct slip_data *pri = data; + struct slip_tramp_data slip_data; + char fd_buf[sizeof("nnnnnn\0")], addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; + char *argv[] = { "uml_net", "slip", "down", fd_buf, addr_buf, NULL }; + + sprintf(fd_buf, "%d", pri->slave); + dev_ip_addr(pri->dev, addr_buf, NULL); + slip_data.args = argv; + tracing_cb(slip_tramp, &slip_data); + if(slip_data.err != 0) + printk("slip_tramp failed - errno = %d\n", slip_data.err); + close(fd); + close(pri->slave); +} + +/* SLIP protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +static int slip_unesc(struct slip_data *sl, unsigned char c) +{ + int ret; + + switch(c){ + case END: + sl->esc = 0; + ret = sl->pos; + sl->pos = 0; + return(ret); + case ESC: + sl->esc = 1; + return(0); + case ESC_ESC: + if(sl->esc){ + sl->esc = 0; + c = ESC; + } + break; + case ESC_END: + if(sl->esc){ + sl->esc = 0; + c = END; + } + break; + } + sl->buf[sl->pos++] = c; + return(0); +} + +int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) +{ + int i, n, size, start; + + n = read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos); + if(n < 0){ + if(errno == EAGAIN) return(0); + return(-errno); + } + else { + start = pri->pos; + for(i = 0; i < n; i++){ + size = slip_unesc(pri, pri->buf[start + i]); + if(size){ + memcpy(buf, pri->buf, size); + return(size); + } + } + } + return(0); +} + +static int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = END; + return (ptr - d); +} + +int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) +{ + int actual, n; + + actual = slip_esc(buf, pri->buf, len); + while(((n = write(fd, pri->buf, actual)) < 0) && (errno == EINTR)) ; + if(n < 0) return(-errno); + else if(n == actual) return(len); + else return(len - 1); +} + +static int slip_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +struct net_user_info slip_user_info = { + init: slip_user_init, + open: slip_open, + close: slip_close, + set_mtu: slip_set_mtu, + max_packet: BUF_SIZE +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_clean/drivers/net/setup.c ac/drivers/net/setup.c --- ac_clean/drivers/net/setup.c Sun May 27 15:42:43 2001 +++ ac/drivers/net/setup.c Sun May 27 16:47:10 2001 @@ -103,7 +103,7 @@ #ifdef CONFIG_MADGEMC {madgemc_probe, 0}, #endif -#ifdef CONFIG_NET_UM_ETH +#ifdef CONFIG_UML_NET {uml_net_probe, 0}, #endif