Commit 7b6f42d0 authored by Jeff Dike's avatar Jeff Dike

Merge http://jdike.stearns.org:5000/net-2.5

into uml.karaya.com:/home/jdike/linux/2.5/uml-2.5
parents d78b462d 48277fd0
......@@ -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
......
......@@ -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:
......
......@@ -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)) {
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->flags &= ~IFF_UP;
"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);
......
......@@ -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;
};
......
#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);
}
......
/*
* 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:
*/
......@@ -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 slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
{
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;
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);
}
break;
case ESC_END:
if(sl->esc){
sl->esc = 0;
c = END;
}
break;
pri->more=0;
}
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);
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);
}
......
#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:
*/
#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:
*/
#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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_NET_KERN_H
#define __UM_NET_KERN_H
......
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_NET_USER_H__
#define __UM_NET_USER_H__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment