summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-12-27 19:35:19 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2002-12-27 19:35:19 -0800
commit9ec5ff60353fe6bc8714715a2dc5aadb95d4d660 (patch)
treeaab3c7cb5e67de9c14665ffc5956be9ee151a69a /arch
parent0ae26769a92e3bbb01a15f9d3cf2fa6d65c5a26c (diff)
parent67175256a48086bf8abc0f892a95a36b6af9405e (diff)
Merge http://uml.bkbits.net/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
Diffstat (limited to 'arch')
-rw-r--r--arch/um/Kconfig_net147
-rw-r--r--arch/um/drivers/Makefile24
-rw-r--r--arch/um/drivers/net_kern.c111
-rw-r--r--arch/um/drivers/slip.h10
-rw-r--r--arch/um/drivers/slip_kern.c9
-rw-r--r--arch/um/drivers/slip_proto.h93
-rw-r--r--arch/um/drivers/slip_user.c106
-rw-r--r--arch/um/drivers/slirp.h51
-rw-r--r--arch/um/drivers/slirp_kern.c132
-rw-r--r--arch/um/drivers/slirp_user.c202
-rw-r--r--arch/um/include/net_kern.h5
-rw-r--r--arch/um/include/net_user.h5
12 files changed, 743 insertions, 152 deletions
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net
index ba311513abc3..443a74bd622d 100644
--- a/arch/um/Kconfig_net
+++ b/arch/um/Kconfig_net
@@ -5,30 +5,177 @@ menu "Network Devices"
# UML virtual driver
config UML_NET
bool "Virtual network device"
+ help
+ While the User-Mode port cannot directly talk to any physical
+ hardware devices, this choice and the following transport options
+ provide one or more virtual network devices through which the UML
+ kernels can talk to each other, the host, and with the host's help,
+ machines on the outside world.
+
+ For more information, including explanations of the networking and
+ sample configurations, see
+ <http://user-mode-linux.sourceforge.net/networking.html>.
+
+ If you'd like to be able to enable networking in the User-Mode
+ linux environment, say Y; otherwise say N. Note that you must
+ enable at least one of the following transport options to actually
+ make use of UML networking.
config UML_NET_ETHERTAP
bool "Ethertap transport"
depends on UML_NET
+ help
+ The Ethertap User-Mode Linux network transport allows a single
+ running UML to exchange packets with its host over one of the
+ host's Ethertap devices, such as /dev/tap0. Additional running
+ UMLs can use additional Ethertap devices, one per running UML.
+ While the UML believes it's on a (multi-device, broadcast) virtual
+ Ethernet network, it's in fact communicating over a point-to-point
+ link with the host.
+
+ To use this, your host kernel must have support for Ethertap
+ devices. Also, if your host kernel is 2.4.x, it must have
+ CONFIG_NETLINK_DEV configured as Y or M.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Ethertap
+ networking.
+
+ If you'd like to set up an IP network with the host and/or the
+ outside world, say Y to this, the Daemon Transport and/or the
+ Slip Transport. You'll need at least one of them, but may choose
+ more than one without conflict. If you don't need UML networking,
+ say N.
config UML_NET_TUNTAP
bool "TUN/TAP transport"
depends on UML_NET
+ help
+ The UML TUN/TAP network transport allows a UML instance to exchange
+ packets with the host over a TUN/TAP device. This option will only
+ work with a 2.4 host, unless you've applied the TUN/TAP patch to
+ your 2.2 host kernel.
+
+ To use this transport, your host kernel must have support for TUN/TAP
+ devices, either built-in or as a module.
config UML_NET_SLIP
bool "SLIP transport"
depends on UML_NET
+ help
+ The slip User-Mode Linux network transport allows a running UML to
+ network with its host over a point-to-point link. Unlike Ethertap,
+ which can carry any Ethernet frame (and hence even non-IP packets),
+ the slip transport can only carry IP packets.
+
+ To use this, your host must support slip devices.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html>. That site
+ has examples of the UML command line to use to enable slip
+ networking, and details of a few quirks with it.
+
+ The Ethertap Transport is preferred over slip because of its
+ limitations. If you prefer slip, however, say Y here. Otherwise
+ choose the Multicast transport (to network multiple UMLs on
+ multiple hosts), Ethertap (to network with the host and the
+ outside world), and/or the Daemon transport (to network multiple
+ UMLs on a single host). You may choose more than one without
+ conflict. If you don't need UML networking, say N.
config UML_NET_DAEMON
bool "Daemon transport"
depends on UML_NET
+ help
+ This User-Mode Linux network transport allows one or more running
+ UMLs on a single host to communicate with each other, but not to
+ the host.
+
+ To use this form of networking, you'll need to run the UML
+ networking daemon on the host.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Daemon
+ networking.
+
+ If you'd like to set up a network with other UMLs on a single host,
+ say Y. If you need a network between UMLs on multiple physical
+ hosts, choose the Multicast Transport. To set up a network with
+ the host and/or other IP machines, say Y to the Ethertap or Slip
+ transports. You'll need at least one of them, but may choose
+ more than one without conflict. If you don't need UML networking,
+ say N.
config UML_NET_MCAST
bool "Multicast transport"
depends on UML_NET
+ help
+ This Multicast User-Mode Linux network transport allows multiple
+ UMLs (even ones running on different host machines!) to talk to
+ each other over a virtual ethernet network. However, it requires
+ at least one UML with one of the other transports to act as a
+ bridge if any of them need to be able to talk to their hosts or any
+ other IP machines.
+
+ To use this, your host kernel(s) must support IP Multicasting.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Multicast
+ networking, and notes about the security of this approach.
+
+ If you need UMLs on multiple physical hosts to communicate as if
+ they shared an Ethernet network, say Y. If you need to communicate
+ with other IP machines, make sure you select one of the other
+ transports (possibly in addition to Multicast; they're not
+ exclusive). If you don't need to network UMLs say N to each of
+ the transports.
config UML_NET_PCAP
bool "pcap transport"
depends on UML_NET
+ help
+ The pcap transport makes a pcap packet stream on the host look
+ like an ethernet device inside UML. This is useful for making
+ UML act as a network monitor for the host. You must have libcap
+ installed in order to build the pcap transport into UML.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable this option.
+
+ If you intend to use UML as a network monitor for the host, say
+ Y here. Otherwise, say N.
+
+config UML_NET_SLIRP
+ bool "SLiRP transport"
+ depends on UML_NET
+ help
+ The SLiRP User-Mode Linux network transport allows a running UML
+ to network by invoking a program that can handle SLIP encapsulated
+ packets. This is commonly (but not limited to) the application
+ known as SLiRP, a program that can re-socket IP packets back onto
+ the host on which it is run. Only IP packets are supported,
+ unlike other network transports that can handle all Ethernet
+ frames. In general, slirp allows the UML the same IP connectivity
+ to the outside world that the host user is permitted, and unlike
+ other transports, SLiRP works without the need of root level
+ privleges, setuid binaries, or SLIP devices on the host. This
+ also means not every type of connection is possible, but most
+ situations can be accomodated with carefully crafted slirp
+ commands that can be passed along as part of the network device's
+ setup string. The effect of this transport on the UML is similar
+ that of a host behind a firewall that masquerades all network
+ connections passing through it (but is less secure).
+
+ To use this you should first have slirp compiled somewhere
+ accessible on the host, and have read its documentation. If you
+ don't need UML networking, say N.
+
+ Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
+
# Below are hardware-independent drivers mirrored from
# drivers/net/Config.in. It would be nice if Linux
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index bd963ccdc7e8..8e72f9032ab6 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -5,23 +5,14 @@
CHAN_OBJS := chan_kern.o chan_user.o line.o
-# This nonsense is due to kbuild. In the 2.4 build, I stick -lpcap in
-# pcap-objs, and that is just included in the link command. The 2.5 kbuild
-# filters out everything from pcap-objs which are not in the built-in.o
-# dependencies, which are $(obj-y). So, -lpcap must be in $(obj-y), too.
-# However, make magically expands -lfoo prerequisites into /usr/lib/libfoo.a
-# file names. This causes the kbuild filtering to filter the -lpcap from
-# pcap-objs, causing the link to fail.
-# So, what this does is figure out by hand (crudely) what file -lpcap really
-# is and just use it.
-
-PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.a; do \
- [ -f $$f ] && echo $$f ; done | head -1)
+# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
+# in to pcap.o
slip-objs := slip_kern.o slip_user.o
+slirp-objs := slirp_kern.o slirp_user.o
daemon-objs := daemon_kern.o daemon_user.o
mcast-objs := mcast_kern.o mcast_user.o
-pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
+#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o hostaudio_user.o
@@ -34,9 +25,10 @@ export-objs := mconsole_kern.o
obj-y =
obj-$(CONFIG_SSL) += ssl.o
obj-$(CONFIG_UML_NET_SLIP) += slip.o
+obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
obj-$(CONFIG_UML_NET_MCAST) += mcast.o
-obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
+#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
obj-$(CONFIG_UML_NET) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MMAPPER) += mmapper_kern.o
@@ -50,8 +42,6 @@ obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o
-CFLAGS_pcap_user.o = -I/usr/include/pcap
-
obj-y += stdio_console.o $(CHAN_OBJS)
USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
@@ -61,7 +51,7 @@ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean:
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index deef1a0a75e3..f6bda1b3b1fe 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -39,7 +39,6 @@ static int uml_net_rx(struct net_device *dev)
/* If we can't allocate memory, try again next round. */
if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
lp->stats.rx_dropped++;
- reactivate_fd(lp->fd, UM_ETH_IRQ);
return 0;
}
@@ -48,7 +47,6 @@ static int uml_net_rx(struct net_device *dev)
skb->mac.raw = skb->data;
pkt_len = (*lp->read)(lp->fd, &skb, lp);
- reactivate_fd(lp->fd, UM_ETH_IRQ);
if (pkt_len > 0) {
skb_trim(skb, pkt_len);
skb->protocol = (*lp->protocol)(skb);
@@ -69,18 +67,22 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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(KERN_ERR
- "Device '%s' read returned %d, shutting it "
- "down\n", dev->name, err);
- dev->flags &= ~IFF_UP;
- dev_close(dev);
- }
- spin_unlock(&lp->lock);
+ if(!netif_running(dev))
+ return;
+
+ spin_lock(&lp->lock);
+ while((err = uml_net_rx(dev)) > 0) ;
+ if(err < 0) {
+ printk(KERN_ERR
+ "Device '%s' read returned %d, shutting it down\n",
+ dev->name, err);
+ dev_close(dev);
+ goto out;
}
+ reactivate_fd(lp->fd, UM_ETH_IRQ);
+
+ out:
+ spin_unlock(&lp->lock);
}
static int uml_net_open(struct net_device *dev)
@@ -250,6 +252,37 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
+/*
+ * default do nothing hard header packet routines for struct net_device init.
+ * real ethernet transports will overwrite with real routines.
+ */
+static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ return(0); /* no change */
+}
+
+static int uml_net_rebuild_header(struct sk_buff *skb)
+{
+ return(0); /* ignore */
+}
+
+static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+ return(-1); /* fail */
+}
+
+static void uml_net_header_cache_update(struct hh_cache *hh,
+ struct net_device *dev, unsigned char * haddr)
+{
+ /* ignore */
+}
+
+static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ return(0); /* nothing */
+}
+
static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
static struct list_head devices = LIST_HEAD_INIT(devices);
@@ -261,21 +294,25 @@ static int eth_configure(int n, void *init, char *mac,
struct uml_net_private *lp;
int save, err, size;
+ size = transport->private_size + sizeof(struct uml_net_private) +
+ sizeof(((struct uml_net_private *) 0)->user);
+
device = kmalloc(sizeof(*device), GFP_KERNEL);
if(device == NULL){
printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
return(1);
}
+ *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list),
+ .dev = NULL,
+ .index = n,
+ .mac = { [ 0 ... 5 ] = 0 },
+ .have_mac = 0 });
+
spin_lock(&devices_lock);
list_add(&device->list, &devices);
spin_unlock(&devices_lock);
- device->index = n;
-
- size = transport->private_size + sizeof(struct uml_net_private) +
- sizeof(((struct uml_net_private *) 0)->user);
-
if(setup_etheraddr(mac, device->mac))
device->have_mac = 1;
@@ -290,10 +327,18 @@ static int eth_configure(int n, void *init, char *mac,
printk(KERN_ERR "eth_configure: failed to allocate device\n");
return(1);
}
+ memset(dev, 0, sizeof(*dev) + size);
+
snprintf(dev->name, sizeof(dev->name), "eth%d", n);
dev->priv = (void *) &dev[1];
device->dev = dev;
+ dev->hard_header = uml_net_hard_header;
+ dev->rebuild_header = uml_net_rebuild_header;
+ dev->hard_header_cache = uml_net_header_cache;
+ dev->header_cache_update= uml_net_header_cache_update;
+ dev->hard_header_parse = uml_net_header_parse;
+
(*transport->kern->init)(dev, init);
dev->mtu = transport->user->max_packet;
@@ -308,32 +353,6 @@ static int eth_configure(int n, void *init, char *mac,
dev->do_ioctl = uml_net_ioctl;
dev->watchdog_timeo = (HZ >> 1);
dev->irq = UM_ETH_IRQ;
- dev->init = NULL;
- dev->master = NULL;
- dev->neigh_setup = NULL;
- dev->owner = NULL;
- dev->state = 0;
- dev->next_sched = 0;
- dev->get_wireless_stats = 0;
- dev->wireless_handlers = 0;
- dev->gflags = 0;
- dev->mc_list = NULL;
- dev->mc_count = 0;
- dev->promiscuity = 0;
- dev->atalk_ptr = NULL;
- dev->ip_ptr = NULL;
- dev->dn_ptr = NULL;
- dev->ip6_ptr = NULL;
- dev->ec_ptr = NULL;
- atomic_set(&dev->refcnt, 0);
- dev->features = 0;
- dev->uninit = NULL;
- dev->destructor = NULL;
- dev->set_config = NULL;
- dev->accept_fastpath = 0;
- dev->br_port = 0;
- dev->mem_start = 0;
- dev->mem_end = 0;
rtnl_lock();
err = register_netdevice(dev);
@@ -372,6 +391,7 @@ static int eth_configure(int n, void *init, char *mac,
if(transport->user->init)
(*transport->user->init)(&lp->user, dev);
+
if(device->have_mac)
set_ether_mac(dev, device->mac);
return(0);
@@ -486,7 +506,6 @@ void register_transport(struct transport *new)
kfree(init);
}
list_del(&eth->list);
- return;
}
}
@@ -580,7 +599,7 @@ static int net_remove(char *str)
int n;
n = simple_strtoul(str, &end, 0);
- if(*end != '\0')
+ if((*end != '\0') || (end == str))
return(-1);
device = find_device(n);
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
index 6fe5588e8a21..495f2f1b1420 100644
--- a/arch/um/drivers/slip.h
+++ b/arch/um/drivers/slip.h
@@ -2,6 +2,9 @@
#define __UM_SLIP_H
#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars + *
+ * terminating END char + initial END char */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
struct slip_data {
void *dev;
@@ -9,10 +12,9 @@ struct slip_data {
char *addr;
char *gate_addr;
int slave;
- /* two bytes each for a (pathological) max packet of escaped chars +
- * terminating END char + inital END char
- */
- char buf[2 * BUF_SIZE + 2];
+ char ibuf[ENC_BUF_SIZE];
+ char obuf[ENC_BUF_SIZE];
+ int more; /* more data: do not read fd until ibuf has been drained */
int pos;
int esc;
};
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 1ca56f563757..f498a83d9db5 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -1,3 +1,4 @@
+#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/stddef.h"
#include "linux/init.h"
@@ -24,21 +25,19 @@ void slip_init(struct net_device *dev, void *data)
{ name : { '\0' },
addr: NULL,
gate_addr : init->gate_addr,
- slave : 0,
- buf : { '\0' },
+ slave : -1,
+ ibuf : { '\0' },
+ obuf : { '\0' },
pos : 0,
esc : 0,
dev : dev });
- strncpy(dev->name, "umn", IFNAMSIZ);
dev->init = NULL;
dev->hard_header_len = 0;
dev->addr_len = 4;
dev->type = ARPHRD_ETHER;
dev->tx_queue_len = 256;
dev->flags = IFF_NOARP;
- if(register_netdev(dev))
- printk(KERN_ERR "Couldn't initialize umn\n");
printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
}
diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h
new file mode 100644
index 000000000000..7206361ace45
--- /dev/null
+++ b/arch/um/drivers/slip_proto.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_SLIP_PROTO_H__
+#define __UM_SLIP_PROTO_H__
+
+/* SLIP protocol characters. */
+#define SLIP_END 0300 /* indicates end of frame */
+#define SLIP_ESC 0333 /* indicates byte stuffing */
+#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
+#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
+
+static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
+{
+ int ret;
+
+ switch(c){
+ case SLIP_END:
+ *esc = 0;
+ ret=*pos;
+ *pos=0;
+ return(ret);
+ case SLIP_ESC:
+ *esc = 1;
+ return(0);
+ case SLIP_ESC_ESC:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_ESC;
+ }
+ break;
+ case SLIP_ESC_END:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_END;
+ }
+ break;
+ }
+ buf[(*pos)++] = c;
+ return(0);
+}
+
+static inline 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++ = SLIP_END;
+
+ /*
+ * For each byte in the packet, send the appropriate
+ * character sequence, according to the SLIP protocol.
+ */
+
+ while (len-- > 0) {
+ switch(c = *s++) {
+ case SLIP_END:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_END;
+ break;
+ case SLIP_ESC:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_ESC;
+ break;
+ default:
+ *ptr++ = c;
+ break;
+ }
+ }
+ *ptr++ = SLIP_END;
+ return (ptr - d);
+}
+
+#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 --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index d8cd43c2f555..e36e8213671b 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -15,6 +15,7 @@
#include "user.h"
#include "net_user.h"
#include "slip.h"
+#include "slip_proto.h"
#include "helper.h"
#include "os.h"
@@ -66,7 +67,7 @@ static void slip_pre_exec(void *arg)
if(data->stdin != -1) dup2(data->stdin, 0);
dup2(data->stdout, 1);
- close(data->close_me);
+ if(data->close_me != -1) close(data->close_me);
}
static int slip_tramp(char **argv, int fd)
@@ -156,7 +157,7 @@ static int slip_open(void *data)
}
sencap = 0;
if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
- printk("Failed to sett slip encapsulation - "
+ printk("Failed to set slip encapsulation - "
"errno = %d\n", errno);
return(-errno);
}
@@ -186,103 +187,48 @@ static void slip_close(int fd, void *data)
pri->slave = -1;
}
-/* 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 = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos);
+ if(pri->more>0) {
+ i = 0;
+ while(i < pri->more) {
+ size = slip_unesc(pri->ibuf[i++],
+ pri->ibuf, &pri->pos, &pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
+ pri->more=pri->more-i;
+ return(size);
+ }
+ }
+ pri->more=0;
+ }
+
+ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
if(n <= 0) return(n);
start = pri->pos;
for(i = 0; i < n; i++){
- size = slip_unesc(pri, pri->buf[start + i]);
+ size = slip_unesc(pri->ibuf[start + i],
+ pri->ibuf, &pri->pos, &pri->esc);
if(size){
- memcpy(buf, pri->buf, size);
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
+ pri->more=n-(i+1);
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);
- n = net_write(fd, pri->buf, actual);
+ actual = slip_esc(buf, pri->obuf, len);
+ n = net_write(fd, pri->obuf, actual);
if(n < 0) return(n);
else return(len);
}
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
new file mode 100644
index 000000000000..04e407d1e44a
--- /dev/null
+++ b/arch/um/drivers/slirp.h
@@ -0,0 +1,51 @@
+#ifndef __UM_SLIRP_H
+#define __UM_SLIRP_H
+
+#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars + *
+ * terminating END char + initial END char */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+
+#define SLIRP_MAX_ARGS 100
+/*
+ * XXX this next definition is here because I don't understand why this
+ * initializer doesn't work in slirp_kern.c:
+ *
+ * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
+ *
+ * or why I can't typecast like this:
+ *
+ * argv : (char* [SLIRP_MAX_ARGS])(init->argv),
+ */
+struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
+
+struct slirp_data {
+ void *dev;
+ struct arg_list_dummy_wrapper argw;
+ int pid;
+ int slave;
+ char ibuf[ENC_BUF_SIZE];
+ char obuf[ENC_BUF_SIZE];
+ int more; /* more data: do not read fd until ibuf has been drained */
+ int pos;
+ int esc;
+};
+
+extern struct net_user_info slirp_user_info;
+
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
+extern int slirp_user_write(int fd, void *buf, int len, struct slirp_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 --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
new file mode 100644
index 000000000000..1a459dd94d76
--- /dev/null
+++ b/arch/um/drivers/slirp_kern.c
@@ -0,0 +1,132 @@
+#include "linux/kernel.h"
+#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 "slirp.h"
+
+struct slirp_init {
+ struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
+};
+
+void slirp_init(struct net_device *dev, void *data)
+{
+ struct uml_net_private *private;
+ struct slirp_data *spri;
+ struct slirp_init *init = data;
+ int i;
+
+ private = dev->priv;
+ spri = (struct slirp_data *) private->user;
+ *spri = ((struct slirp_data)
+ { argw : init->argw,
+ pid : -1,
+ slave : -1,
+ ibuf : { '\0' },
+ obuf : { '\0' },
+ pos : 0,
+ esc : 0,
+ dev : dev });
+
+ dev->init = NULL;
+ dev->hard_header_len = 0;
+ dev->addr_len = 4;
+ dev->type = ARPHRD_ETHER;
+ dev->tx_queue_len = 256;
+ dev->flags = IFF_NOARP;
+ printk("SLIRP backend - command line:");
+ for(i=0;spri->argw.argv[i]!=NULL;i++) {
+ printk(" '%s'",spri->argw.argv[i]);
+ }
+ printk("\n");
+}
+
+static unsigned short slirp_protocol(struct sk_buff *skbuff)
+{
+ return(htons(ETH_P_IP));
+}
+
+static int slirp_read(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
+ (struct slirp_data *) &lp->user));
+}
+
+static int slirp_write(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ return(slirp_user_write(fd, (*skb)->data, (*skb)->len,
+ (struct slirp_data *) &lp->user));
+}
+
+struct net_kern_info slirp_kern_info = {
+ init: slirp_init,
+ protocol: slirp_protocol,
+ read: slirp_read,
+ write: slirp_write,
+};
+
+static int slirp_setup(char *str, char **mac_out, void *data)
+{
+ struct slirp_init *init = data;
+ int i=0;
+
+ *init = ((struct slirp_init)
+ { argw : { { "slirp", NULL } } });
+
+ str = split_if_spec(str, mac_out, NULL);
+
+ if(str == NULL) { /* no command line given after MAC addr */
+ return(1);
+ }
+
+ do {
+ if(i>=SLIRP_MAX_ARGS-1) {
+ printk("slirp_setup: truncating slirp arguments\n");
+ break;
+ }
+ init->argw.argv[i++] = str;
+ while(*str && *str!=',') {
+ if(*str=='_') *str=' ';
+ str++;
+ }
+ if(*str!=',')
+ break;
+ *str++='\0';
+ } while(1);
+ init->argw.argv[i]=NULL;
+ return(1);
+}
+
+static struct transport slirp_transport = {
+ list : LIST_HEAD_INIT(slirp_transport.list),
+ name : "slirp",
+ setup : slirp_setup,
+ user : &slirp_user_info,
+ kern : &slirp_kern_info,
+ private_size : sizeof(struct slirp_data),
+ setup_size : sizeof(struct slirp_init),
+};
+
+static int register_slirp(void)
+{
+ register_transport(&slirp_transport);
+ return(1);
+}
+
+__initcall(register_slirp);
+
+/*
+ * 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 --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
new file mode 100644
index 000000000000..bba76df0f33d
--- /dev/null
+++ b/arch/um/drivers/slirp_user.c
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "net_user.h"
+#include "slirp.h"
+#include "slip_proto.h"
+#include "helper.h"
+#include "os.h"
+
+void slirp_user_init(void *data, void *dev)
+{
+ struct slirp_data *pri = data;
+
+ pri->dev = dev;
+}
+
+struct slirp_pre_exec_data {
+ int stdin;
+ int stdout;
+};
+
+static void slirp_pre_exec(void *arg)
+{
+ struct slirp_pre_exec_data *data = arg;
+
+ if(data->stdin != -1) dup2(data->stdin, 0);
+ if(data->stdout != -1) dup2(data->stdout, 1);
+}
+
+static int slirp_tramp(char **argv, int fd)
+{
+ struct slirp_pre_exec_data pe_data;
+ int pid;
+
+ pe_data.stdin = fd;
+ pe_data.stdout = fd;
+ pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
+
+ return(pid);
+}
+
+static int slirp_datachan(int *mfd, int *sfd)
+{
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err){
+ printk("slirp_datachan: Failed to open pipe, errno = %d\n",
+ -err);
+ return(err);
+ }
+
+ *mfd = fds[0];
+ *sfd = fds[1];
+ return(0);
+}
+
+static int slirp_open(void *data)
+{
+ struct slirp_data *pri = data;
+ int sfd, mfd, pid, err;
+
+ err = slirp_datachan(&mfd, &sfd);
+ if(err)
+ return(err);
+
+ pid = slirp_tramp(pri->argw.argv, sfd);
+
+ if(pid < 0){
+ printk("slirp_tramp failed - errno = %d\n", pid);
+ os_close_file(sfd);
+ os_close_file(mfd);
+ return(pid);
+ }
+
+ pri->slave = sfd;
+ pri->pos = 0;
+ pri->esc = 0;
+
+ pri->pid = pid;
+
+ return(mfd);
+}
+
+static void slirp_close(int fd, void *data)
+{
+ struct slirp_data *pri = data;
+ int status,err;
+
+ close(fd);
+ close(pri->slave);
+
+ pri->slave = -1;
+
+ if(pri->pid<1) {
+ printk("slirp_close: no child process to shut down\n");
+ return;
+ }
+
+#if 0
+ if(kill(pri->pid, SIGHUP)<0) {
+ printk("slirp_close: sending hangup to %d failed (%d)\n",
+ pri->pid, errno);
+ }
+#endif
+
+ err = waitpid(pri->pid, &status, WNOHANG);
+ if(err<0) {
+ printk("slirp_close: waitpid returned %d\n", errno);
+ return;
+ }
+
+ if(err==0) {
+ printk("slirp_close: process %d has not exited\n");
+ return;
+ }
+
+ pri->pid = -1;
+}
+
+int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
+{
+ int i, n, size, start;
+
+ if(pri->more>0) {
+ i = 0;
+ while(i < pri->more) {
+ size = slip_unesc(pri->ibuf[i++],
+ pri->ibuf,&pri->pos,&pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
+ pri->more=pri->more-i;
+ return(size);
+ }
+ }
+ pri->more=0;
+ }
+
+ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
+ if(n <= 0) return(n);
+
+ start = pri->pos;
+ for(i = 0; i < n; i++){
+ size = slip_unesc(pri->ibuf[start + i],
+ pri->ibuf,&pri->pos,&pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
+ pri->more=n-(i+1);
+ return(size);
+ }
+ }
+ return(0);
+}
+
+int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
+{
+ int actual, n;
+
+ actual = slip_esc(buf, pri->obuf, len);
+ n = net_write(fd, pri->obuf, actual);
+ if(n < 0) return(n);
+ else return(len);
+}
+
+static int slirp_set_mtu(int mtu, void *data)
+{
+ return(mtu);
+}
+
+struct net_user_info slirp_user_info = {
+ init: slirp_user_init,
+ open: slirp_open,
+ close: slirp_close,
+ remove: NULL,
+ set_mtu: slirp_set_mtu,
+ add_address: NULL,
+ delete_address: NULL,
+ 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 --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index 22d43acb78f1..de793e9bf438 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_NET_KERN_H
#define __UM_NET_KERN_H
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
index 01867cae92e2..36807b796e9f 100644
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_NET_USER_H__
#define __UM_NET_USER_H__