diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-27 19:35:19 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-27 19:35:19 -0800 |
| commit | 9ec5ff60353fe6bc8714715a2dc5aadb95d4d660 (patch) | |
| tree | aab3c7cb5e67de9c14665ffc5956be9ee151a69a /arch | |
| parent | 0ae26769a92e3bbb01a15f9d3cf2fa6d65c5a26c (diff) | |
| parent | 67175256a48086bf8abc0f892a95a36b6af9405e (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_net | 147 | ||||
| -rw-r--r-- | arch/um/drivers/Makefile | 24 | ||||
| -rw-r--r-- | arch/um/drivers/net_kern.c | 111 | ||||
| -rw-r--r-- | arch/um/drivers/slip.h | 10 | ||||
| -rw-r--r-- | arch/um/drivers/slip_kern.c | 9 | ||||
| -rw-r--r-- | arch/um/drivers/slip_proto.h | 93 | ||||
| -rw-r--r-- | arch/um/drivers/slip_user.c | 106 | ||||
| -rw-r--r-- | arch/um/drivers/slirp.h | 51 | ||||
| -rw-r--r-- | arch/um/drivers/slirp_kern.c | 132 | ||||
| -rw-r--r-- | arch/um/drivers/slirp_user.c | 202 | ||||
| -rw-r--r-- | arch/um/include/net_kern.h | 5 | ||||
| -rw-r--r-- | arch/um/include/net_user.h | 5 |
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(ð->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__ |
