Commit 898b3bec authored by Jeff Dike's avatar Jeff Dike

Merge uml.karaya.com:/home/jdike/linux/2.5/linus-2.5

into uml.karaya.com:/home/jdike/linux/2.5/net
parents 2e714290 fa5c2b02
......@@ -9,6 +9,7 @@ dep_bool ' TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET
dep_bool ' SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
dep_bool ' Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
dep_bool ' Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET
# Below are hardware-independent drivers mirrored from
# drivers/net/Config.in. It would be nice if Linux
......
......@@ -86,6 +86,7 @@ CONFIG_UML_NET_TUNTAP=y
CONFIG_UML_NET_SLIP=y
CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_MCAST=y
# CONFIG_UML_NET_PCAP is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
......
......@@ -5,9 +5,23 @@
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,so}; do \
[ -f $$f ] && echo $$f ; done | head -1)
slip-objs := slip_kern.o slip_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)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o hostaudio_user.o
......@@ -22,6 +36,7 @@ obj-$(CONFIG_SSL) += ssl.o
obj-$(CONFIG_UML_NET_SLIP) += slip.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) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MMAPPER) += mmapper_kern.o
......@@ -35,6 +50,8 @@ obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.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))
......
......@@ -12,41 +12,36 @@
#include "net_kern.h"
#include "net_user.h"
#include "daemon.h"
#include "daemon_kern.h"
struct daemon_data daemon_priv[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
sock_type : "unix",
ctl_sock : "/tmp/uml.ctl",
ctl_addr : NULL,
data_addr : NULL,
local_addr : NULL,
fd : -1,
control : -1,
dev : NULL,
}
struct daemon_init {
char *sock_type;
char *ctl_sock;
};
void daemon_init(struct net_device *dev, int index)
void daemon_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct daemon_data *dpri;
struct daemon_init *init = data;
init_etherdev(dev, 0);
pri = dev->priv;
dpri = (struct daemon_data *) pri->user;
*dpri = daemon_priv[index];
*dpri = ((struct daemon_data)
{ sock_type : init->sock_type,
ctl_sock : init->ctl_sock,
ctl_addr : NULL,
data_addr : NULL,
local_addr : NULL,
fd : -1,
control : -1,
dev : dev });
printk("daemon backend (uml_switch version %d) - %s:%s",
SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
printk("\n");
}
static unsigned short daemon_protocol(struct sk_buff *skb)
{
return(eth_type_trans(skb, skb->dev));
}
static int daemon_read(int fd, struct sk_buff **skb,
struct uml_net_private *lp)
{
......@@ -65,47 +60,37 @@ static int daemon_write(int fd, struct sk_buff **skb,
static struct net_kern_info daemon_kern_info = {
init: daemon_init,
protocol: daemon_protocol,
protocol: eth_protocol,
read: daemon_read,
write: daemon_write,
};
static int daemon_count = 0;
int daemon_setup(char *str, struct uml_net *dev)
int daemon_setup(char *str, char **mac_out, void *data)
{
int err, n = daemon_count;
dev->user = &daemon_user_info;
dev->kern = &daemon_kern_info;
dev->private_size = sizeof(struct daemon_data);
dev->transport_index = daemon_count++;
if(*str != ',') return(0);
str++;
if(*str != ','){
err = setup_etheraddr(str, dev->mac);
if(!err) dev->have_mac = 1;
}
str = strchr(str, ',');
if(str == NULL) return(0);
*str++ = '\0';
if(*str != ',') daemon_priv[n].sock_type = str;
str = strchr(str, ',');
if(str == NULL) return(0);
*str++ = '\0';
if(*str != ',') daemon_priv[n].ctl_sock = str;
str = strchr(str, ',');
if(str == NULL) return(0);
*str = '\0';
struct daemon_init *init = data;
char *remain;
*init = ((struct daemon_init)
{ sock_type : "unix",
ctl_sock : "/tmp/uml.ctl" });
remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
NULL);
if(remain != NULL)
printk(KERN_WARNING "daemon_setup : Ignoring data socket "
"specification\n");
return(0);
return(1);
}
static struct transport daemon_transport = {
list : LIST_HEAD_INIT(daemon_transport.list),
name : "daemon",
setup : daemon_setup
setup : daemon_setup,
user : &daemon_user_info,
kern : &daemon_kern_info,
private_size : sizeof(struct daemon_data),
setup_size : sizeof(struct daemon_init),
};
static int register_daemon(void)
......@@ -115,6 +100,7 @@ static int register_daemon(void)
}
__initcall(register_daemon);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
#ifndef __UM_DAEMON_KERN_H
#define __UM_DAEMON_KERN_H
#include "net_kern.h"
extern int daemon_setup(char *arg, struct uml_net *dev);
#endif
......@@ -10,8 +10,6 @@ struct mcast_data {
unsigned short port;
void *mcast_addr;
int ttl;
unsigned char hwaddr[ETH_ADDR_LEN];
int hw_setup;
void *dev;
};
......
......@@ -19,26 +19,28 @@
#include "net_kern.h"
#include "net_user.h"
#include "mcast.h"
#include "mcast_kern.h"
struct mcast_data mcast_priv[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
addr: "239.192.168.1",
port: 1102,
ttl: 1,
}
struct mcast_init {
char *addr;
int port;
int ttl;
};
void mcast_init(struct net_device *dev, int index)
void mcast_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct mcast_data *dpri;
struct mcast_init *init = data;
init_etherdev(dev, 0);
pri = dev->priv;
dpri = (struct mcast_data *) pri->user;
*dpri = mcast_priv[index];
*dpri = ((struct mcast_data)
{ addr : init->addr,
port : init->port,
ttl : init->ttl,
mcast_addr : NULL,
dev : dev });
printk("mcast backend ");
printk("multicast adddress: %s:%u, TTL:%u ",
dpri->addr, dpri->port, dpri->ttl);
......@@ -46,11 +48,6 @@ void mcast_init(struct net_device *dev, int index)
printk("\n");
}
static unsigned short mcast_protocol(struct sk_buff *skb)
{
return eth_type_trans(skb, skb->dev);
}
static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
......@@ -68,71 +65,64 @@ static int mcast_write(int fd, struct sk_buff **skb,
static struct net_kern_info mcast_kern_info = {
init: mcast_init,
protocol: mcast_protocol,
protocol: eth_protocol,
read: mcast_read,
write: mcast_write,
};
static int mcast_count = 0;
int mcast_setup(char *str, struct uml_net *dev)
int mcast_setup(char *str, char **mac_out, void *data)
{
int err, n = mcast_count;
int num = 0;
char *p1, *p2;
dev->user = &mcast_user_info;
dev->kern = &mcast_kern_info;
dev->private_size = sizeof(struct mcast_data);
dev->transport_index = mcast_count++;
/* somewhat more sophisticated parser, needed for in_aton */
p1 = str;
if (*str == ',')
p1++;
while (p1 && *p1) {
if ((p2 = strchr(p1, ',')))
*p2++ = '\0';
if (strlen(p1) > 0) {
switch (num) {
case 0:
/* First argument: Ethernet address */
err = setup_etheraddr(p1, dev->mac);
if (!err)
dev->have_mac = 1;
break;
case 1:
/* Second argument: Multicast group */
mcast_priv[n].addr = p1;
break;
case 2:
/* Third argument: Port number */
mcast_priv[n].port =
htons(simple_strtoul(p1, NULL, 10));
break;
case 3:
/* Fourth argument: TTL */
mcast_priv[n].ttl =
simple_strtoul(p1, NULL, 10);
break;
struct mcast_init *init = data;
char *port_str = NULL, *ttl_str = NULL, *remain;
char *last;
int n;
*init = ((struct mcast_init)
{ addr : "239.192.168.1",
port : 1102,
ttl : 1 });
remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
NULL);
if(remain != NULL){
printk(KERN_ERR "mcast_setup - Extra garbage on "
"specification : '%s'\n", remain);
return(0);
}
if(port_str != NULL){
n = simple_strtoul(port_str, &last, 10);
if(*last != '\0'){
printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
port_str);
return(0);
}
init->port = htons(n);
}
if(ttl_str != NULL){
init->ttl = simple_strtoul(ttl_str, &last, 10);
if(*last != '\0'){
printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
ttl_str);
return(0);
}
p1 = p2;
num++;
}
printk(KERN_INFO "Configured mcast device: %s:%u-%u\n",
mcast_priv[n].addr, mcast_priv[n].port,
mcast_priv[n].ttl);
printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
init->port, init->ttl);
return(0);
return(1);
}
static struct transport mcast_transport = {
list : LIST_HEAD_INIT(mcast_transport.list),
name : "mcast",
setup : mcast_setup
setup : mcast_setup,
user : &mcast_user_info,
kern : &mcast_kern_info,
private_size : sizeof(struct mcast_data),
setup_size : sizeof(struct mcast_init),
};
static int register_mcast(void)
......@@ -142,6 +132,7 @@ static int register_mcast(void)
}
__initcall(register_mcast);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
#ifndef __UM_MCAST_KERN_H
#define __UM_MCAST_KERN_H
#include "net_kern.h"
extern int mcast_setup(char *arg, struct uml_net *dev);
#endif
......@@ -29,16 +29,6 @@
LIST_HEAD(opened);
struct uml_net devices[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
dev: NULL,
user: NULL,
kern: NULL,
private_size: 0,
}
};
static int uml_net_rx(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
......@@ -255,22 +245,38 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
static int eth_configure(struct uml_net *device, int n)
static struct list_head devices = LIST_HEAD_INIT(devices);
static int eth_configure(int n, void *init, char *mac,
struct transport *transport)
{
struct uml_net *device;
struct net_device *dev;
struct uml_net_private *lp;
int save, err;
int save, err, size;
device = kmalloc(sizeof(*device), GFP_KERNEL);
if(device == NULL){
printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
return(1);
}
list_add(&device->list, &devices);
device->index = n;
device->private_size += sizeof(struct uml_net_private) +
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;
printk(KERN_INFO "Netdevice %d ", n);
if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
device->mac[0], device->mac[1],
device->mac[2], device->mac[3],
device->mac[4], device->mac[5]);
printk(": ");
dev = kmalloc(sizeof(*dev) + device->private_size, GFP_KERNEL);
dev = kmalloc(sizeof(*dev) + size, GFP_KERNEL);
if(dev == NULL){
printk(KERN_ERR "eth_configure: failed to allocate device\n");
return(1);
......@@ -279,9 +285,9 @@ static int eth_configure(struct uml_net *device, int n)
dev->priv = (void *) &dev[1];
device->dev = dev;
(*device->kern->init)(dev, device->transport_index);
(*transport->kern->init)(dev, init);
dev->mtu = device->user->max_packet;
dev->mtu = transport->user->max_packet;
dev->open = uml_net_open;
dev->hard_start_xmit = uml_net_start_xmit;
dev->stop = uml_net_close;
......@@ -338,28 +344,41 @@ static int eth_configure(struct uml_net *device, int n)
fd : -1,
mac : { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
have_mac : device->have_mac,
protocol : device->kern->protocol,
open : device->user->open,
close : device->user->close,
remove : device->user->remove,
read : device->kern->read,
write : device->kern->write,
add_address : device->user->add_address,
delete_address : device->user->delete_address,
set_mtu : device->user->set_mtu,
protocol : transport->kern->protocol,
open : transport->user->open,
close : transport->user->close,
remove : transport->user->remove,
read : transport->kern->read,
write : transport->kern->write,
add_address : transport->user->add_address,
delete_address : transport->user->delete_address,
set_mtu : transport->user->set_mtu,
user : { save } });
init_timer(&lp->tl);
lp->tl.function = uml_net_user_timer_expire;
memset(&lp->stats, 0, sizeof(lp->stats));
if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac));
if(device->user->init)
(*device->user->init)(&lp->user, dev);
if(transport->user->init)
(*transport->user->init)(&lp->user, dev);
if(device->have_mac)
set_ether_mac(dev, device->mac);
return(0);
}
static struct uml_net *find_device(int n)
{
struct uml_net *device;
struct list_head *ele;
list_for_each(ele, &devices){
device = list_entry(ele, struct uml_net, list);
if(device->index == n)
return(device);
}
return(NULL);
}
static int eth_parse(char *str, int *index_out, char **str_out)
{
char *end;
......@@ -370,8 +389,8 @@ static int eth_parse(char *str, int *index_out, char **str_out)
printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
return(1);
}
if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){
printk(KERN_ERR "eth_setup: device %d out of range\n", n);
if(n < 0){
printk(KERN_ERR "eth_setup: device %d is negative\n", n);
return(1);
}
str = end;
......@@ -381,7 +400,7 @@ static int eth_parse(char *str, int *index_out, char **str_out)
return(1);
}
str++;
if(devices[n].dev != NULL){
if(find_device(n)){
printk(KERN_ERR "eth_setup: Device %d already configured\n",
n);
return(1);
......@@ -401,24 +420,54 @@ struct list_head transports = LIST_HEAD_INIT(transports);
struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
static int check_transport(struct transport *transport, char *eth, int n,
void **init_out, char **mac_out)
{
int len;
len = strlen(transport->name);
if(strncmp(eth, transport->name, len))
return(0);
eth += len;
if(*eth == ',')
eth++;
else if(*eth != '\0')
return(0);
*init_out = kmalloc(transport->setup_size, GFP_KERNEL);
if(*init_out == NULL)
return(1);
if(!transport->setup(eth, mac_out, *init_out)){
kfree(*init_out);
*init_out = NULL;
}
return(1);
}
void register_transport(struct transport *new)
{
struct list_head *ele, *next;
struct eth_init *eth;
char *str;
int err;
void *init;
char *mac = NULL;
int match;
list_add(&new->list, &transports);
list_for_each_safe(ele, next, &eth_cmd_line){
eth = list_entry(ele, struct eth_init, list);
if(!strncmp(eth->init, new->name, strlen(new->name))){
str = eth->init + strlen(new->name);
err = new->setup(str, &devices[eth->index]);
if(!err) eth_configure(&devices[eth->index],
eth->index);
list_del(&eth->list);
match = check_transport(new, eth->init, eth->index, &init,
&mac);
if(!match)
continue;
else if(init != NULL){
eth_configure(eth->index, init, mac, new);
kfree(init);
}
list_del(&eth->list);
return;
}
}
......@@ -426,16 +475,20 @@ static int eth_setup_common(char *str, int index)
{
struct list_head *ele;
struct transport *transport;
void *init;
char *mac = NULL;
list_for_each(ele, &transports){
transport = list_entry(ele, struct transport, list);
if(!strncmp(str, transport->name, strlen(transport->name))){
str += strlen(transport->name);
return(transport->setup(str, &devices[index]));
if(!check_transport(transport, str, index, &init, &mac))
continue;
if(init != NULL){
eth_configure(index, init, mac, transport);
kfree(init);
}
return(1);
}
return(-1);
return(0);
}
static int eth_setup(char *str)
......@@ -470,13 +523,12 @@ static int eth_init(void)
{
struct list_head *ele, *next;
struct eth_init *eth;
int err;
list_for_each_safe(ele, next, &eth_cmd_line){
eth = list_entry(ele, struct eth_init, list);
err = eth_setup_common(eth->init, eth->index);
if(!err) eth_configure(&devices[eth->index], eth->index);
if(err >= 0) list_del(&eth->list);
if(eth_setup_common(eth->init, eth->index))
list_del(&eth->list);
}
return(1);
......@@ -486,7 +538,7 @@ __initcall(eth_init);
static int net_config(char *str)
{
int err, n;
int n, err;
err = eth_parse(str, &n, &str);
if(err) return(err);
......@@ -494,32 +546,38 @@ static int net_config(char *str)
str = uml_strdup(str);
if(str == NULL){
printk(KERN_ERR "net_config failed to strdup string\n");
return(1);
return(-1);
}
err = eth_setup_common(str, n);
if(err){
err = !eth_setup_common(str, n);
if(err)
kfree(str);
return(err);
}
err = eth_configure(&devices[n], n);
return(err);
}
static int net_remove(char *str)
{
struct uml_net *device;
struct net_device *dev;
struct uml_net_private *lp;
char *end;
int n;
if(!isdigit(*str)) return(-1);
n = *str - '0';
if(devices[n].dev == NULL) return(0);
dev = devices[n].dev;
n = simple_strtoul(str, &end, 0);
if(*end != '\0')
return(-1);
device = find_device(n);
if(device == NULL)
return(0);
dev = device->dev;
lp = dev->priv;
if(lp->fd > 0) return(-1);
if(lp->remove != NULL) (*lp->remove)(&lp->user);
unregister_netdev(dev);
devices[n].dev = NULL;
list_del(&device->list);
kfree(device);
return(0);
}
......@@ -620,6 +678,8 @@ int setup_etheraddr(char *str, unsigned char *addr)
char *end;
int i;
if(str == NULL)
return(0);
for(i=0;i<6;i++){
addr[i] = simple_strtoul(str, &end, 16);
if((end == str) ||
......@@ -627,7 +687,7 @@ int setup_etheraddr(char *str, unsigned char *addr)
printk(KERN_ERR
"setup_etheraddr: failed to parse '%s' "
"as an ethernet address\n", str);
return(-1);
return(0);
}
str = end + 1;
}
......@@ -635,9 +695,9 @@ int setup_etheraddr(char *str, unsigned char *addr)
printk(KERN_ERR
"Attempt to assign a broadcast ethernet address to a "
"device disallowed\n");
return(-1);
}
return(0);
}
return(1);
}
void dev_ip_addr(void *d, char *buf, char *bin_buf)
......@@ -708,6 +768,24 @@ void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *,
}
}
int dev_netmask(void *d, void *m)
{
struct net_device *dev = d;
struct in_device *ip = dev->ip_ptr;
struct in_ifaddr *in;
__u32 *mask_out = m;
if(ip == NULL)
return(1);
in = ip->ifa_list;
if(in == NULL)
return(1);
*mask_out = in->ifa_mask;
return(0);
}
void *get_output_buffer(int *len_out)
{
void *ret;
......@@ -723,32 +801,26 @@ void free_output_buffer(void *buffer)
free_pages((unsigned long) buffer, 0);
}
int tap_setup_common(char *str, char *type, char **dev_name, char *mac,
int *have_mac, char **gate_addr)
int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out,
char **gate_addr)
{
int err;
char *remain;
if(*str != ','){
printk(KERN_ERR
"ethertap_setup: expected ',' after '%s'\n", type);
remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
if(remain != NULL){
printk("tap_setup_common - Extra garbage on specification : "
"'%s'\n", remain);
return(1);
}
str++;
if(*str != ',') *dev_name = str;
str = strchr(str, ',');
if(str == NULL) return(0);
*str++ = '\0';
if(*str != ','){
err = setup_etheraddr(str, mac);
if(!err) *have_mac = 1;
}
str = strchr(str, ',');
if(str == NULL) return(0);
*str++ = '\0';
if(*str != '\0') *gate_addr = str;
return(0);
}
unsigned short eth_protocol(struct sk_buff *skb)
{
return(eth_type_trans(skb, skb->dev));
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
......@@ -4,6 +4,7 @@
*/
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
......@@ -220,6 +221,27 @@ void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
change(arg, "del", addr, netmask);
}
char *split_if_spec(char *str, ...)
{
char **arg, *end;
va_list ap;
va_start(ap, str);
while((arg = va_arg(ap, char **)) != NULL){
if(*str == '\0')
return(NULL);
end = strchr(str, ',');
if(end != str)
*arg = str;
if(end == NULL)
return(NULL);
*end++ = '\0';
str = end;
}
va_end(ap);
return(str);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
/*
* Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
* Licensed under the GPL.
*/
#include "linux/init.h"
#include "linux/netdevice.h"
#include "linux/etherdevice.h"
#include "net_kern.h"
#include "net_user.h"
#include "pcap_user.h"
struct pcap_init {
char *host_if;
int promisc;
int optimize;
char *filter;
};
void pcap_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct pcap_data *ppri;
struct pcap_init *init = data;
init_etherdev(dev, 0);
pri = dev->priv;
ppri = (struct pcap_data *) pri->user;
*ppri = ((struct pcap_data)
{ host_if : init->host_if,
promisc : init->promisc,
optimize : init->optimize,
filter : init->filter,
compiled : NULL,
pcap : NULL });
}
static int pcap_read(int fd, struct sk_buff **skb,
struct uml_net_private *lp)
{
*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
if(*skb == NULL) return(-ENOMEM);
return(pcap_user_read(fd, (*skb)->mac.raw,
(*skb)->dev->mtu + ETH_HEADER_OTHER,
(struct pcap_data *) &lp->user));
}
static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
return(-EPERM);
}
static struct net_kern_info pcap_kern_info = {
init: pcap_init,
protocol: eth_protocol,
read: pcap_read,
write: pcap_write,
};
int pcap_setup(char *str, char **mac_out, void *data)
{
struct pcap_init *init = data;
char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
int i;
*init = ((struct pcap_init)
{ host_if : "eth0",
promisc : 1,
optimize : 0,
filter : NULL });
remain = split_if_spec(str, &host_if, &init->filter,
&options[0], &options[1], NULL);
if(remain != NULL){
printk(KERN_ERR "pcap_setup - Extra garbage on "
"specification : '%s'\n", remain);
return(0);
}
if(host_if != NULL)
init->host_if = host_if;
for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
if(options[i] == NULL)
continue;
if(!strcmp(options[i], "promisc"))
init->promisc = 1;
else if(!strcmp(options[i], "nopromisc"))
init->promisc = 0;
else if(!strcmp(options[i], "optimize"))
init->optimize = 1;
else if(!strcmp(options[i], "nooptimize"))
init->optimize = 0;
else printk("pcap_setup : bad option - '%s'\n", options[i]);
}
return(1);
}
static struct transport pcap_transport = {
list : LIST_HEAD_INIT(pcap_transport.list),
name : "pcap",
setup : pcap_setup,
user : &pcap_user_info,
kern : &pcap_kern_info,
private_size : sizeof(struct pcap_data),
setup_size : sizeof(struct pcap_init),
};
static int register_pcap(void)
{
register_transport(&pcap_transport);
return(1);
}
__initcall(register_pcap);
/*
* 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.
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pcap.h>
#include <asm/types.h>
#include "net_user.h"
#include "pcap_user.h"
#include "user.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
#define PCAP_FD(p) (*(int *)(p))
static void pcap_user_init(void *data, void *dev)
{
struct pcap_data *pri = data;
pcap_t *p;
char errors[PCAP_ERRBUF_SIZE];
p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
if(p == NULL){
printk("pcap_user_init : pcap_open_live failed - '%s'\n",
errors);
return;
}
pri->dev = dev;
pri->pcap = p;
}
static int pcap_open(void *data)
{
struct pcap_data *pri = data;
__u32 netmask;
int err;
if(pri->pcap == NULL)
return(-ENODEV);
if(pri->filter != NULL){
err = dev_netmask(pri->dev, &netmask);
if(err < 0){
printk("pcap_open : dev_netmask failed\n");
return(-EIO);
}
pri->compiled = um_kmalloc(sizeof(struct bpf_program));
if(pri->compiled == NULL){
printk("pcap_open : kmalloc failed\n");
return(-ENOMEM);
}
err = pcap_compile(pri->pcap,
(struct bpf_program *) pri->compiled,
pri->filter, pri->optimize, netmask);
if(err < 0){
printk("pcap_open : pcap_compile failed - '%s'\n",
pcap_geterr(pri->pcap));
return(-EIO);
}
err = pcap_setfilter(pri->pcap, pri->compiled);
if(err < 0){
printk("pcap_open : pcap_setfilter failed - '%s'\n",
pcap_geterr(pri->pcap));
return(-EIO);
}
}
return(PCAP_FD(pri->pcap));
}
static void pcap_remove(void *data)
{
struct pcap_data *pri = data;
if(pri->compiled != NULL)
pcap_freecode(pri->compiled);
pcap_close(pri->pcap);
}
struct pcap_handler_data {
char *buffer;
int len;
};
static void handler(u_char *data, const struct pcap_pkthdr *header,
const u_char *packet)
{
int len;
struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
len = hdata->len < header->caplen ? hdata->len : header->caplen;
memcpy(hdata->buffer, packet, len);
hdata->len = len;
}
int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
{
struct pcap_handler_data hdata = ((struct pcap_handler_data)
{ buffer : buffer,
len : len });
int n;
n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
if(n < 0){
printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
return(-EIO);
}
else if(n == 0)
return(0);
return(hdata.len);
}
struct net_user_info pcap_user_info = {
init: pcap_user_init,
open: pcap_open,
close: NULL,
remove: pcap_remove,
set_mtu: NULL,
add_address: NULL,
delete_address: NULL,
max_packet: MAX_PACKET - ETH_HEADER_OTHER
};
/*
* 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) 2001 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_TUNTAP_KERN_H
#define __UM_TUNTAP_KERN_H
#include "net_user.h"
#include "net_kern.h"
struct pcap_data {
char *host_if;
int promisc;
int optimize;
char *filter;
void *compiled;
void *pcap;
void *dev;
};
extern int tuntap_setup(char *arg, struct uml_net *dev);
extern struct net_user_info pcap_user_info;
#endif
extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
......
......@@ -7,28 +7,29 @@
#include "net_user.h"
#include "kern.h"
#include "slip.h"
#include "slip_kern.h"
struct slip_data slip_priv[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
addr: NULL,
gate_addr: NULL,
slave: -1,
buf: { 0 },
pos: 0,
esc: 0,
}
struct slip_init {
char *gate_addr;
};
void slip_init(struct net_device *dev, int index)
void slip_init(struct net_device *dev, void *data)
{
struct uml_net_private *private;
struct slip_data *spri;
struct slip_init *init = data;
private = dev->priv;
spri = (struct slip_data *) private->user;
*spri = slip_priv[index];
*spri = ((struct slip_data)
{ name : { '\0' },
addr: NULL,
gate_addr : init->gate_addr,
slave : 0,
buf : { '\0' },
pos : 0,
esc : 0,
dev : dev });
strncpy(dev->name, "umn", IFNAMSIZ);
dev->init = NULL;
dev->hard_header_len = 0;
......@@ -67,26 +68,26 @@ struct net_kern_info slip_kern_info = {
write: slip_write,
};
static int slip_count = 0;
int slip_setup(char *str, struct uml_net *dev)
static int slip_setup(char *str, char **mac_out, void *data)
{
int n = slip_count;
struct slip_init *init = data;
*init = ((struct slip_init)
{ gate_addr : NULL });
dev->user = &slip_user_info;
dev->kern = &slip_kern_info;
dev->private_size = sizeof(struct slip_data);
dev->transport_index = slip_count++;
if(*str != ',') return(0);
str++;
if(str[0] != '\0') slip_priv[n].gate_addr = str;
return(0);
if(str[0] != '\0')
init->gate_addr = str;
return(1);
}
static struct transport slip_transport = {
list : LIST_HEAD_INIT(slip_transport.list),
name : "slip",
setup : slip_setup
setup : slip_setup,
user : &slip_user_info,
kern : &slip_kern_info,
private_size : sizeof(struct slip_data),
setup_size : sizeof(struct slip_init),
};
static int register_slip(void)
......
#ifndef __UM_SLIP_KERN_H
#define __UM_SLIP_KERN_H
#include "net_kern.h"
extern int slip_setup(char *arg, struct uml_net *dev);
#endif
......@@ -6,14 +6,10 @@
#include "linux/socket.h"
#include "linux/list.h"
#define MAX_UML_NETDEV (16)
struct uml_net {
struct list_head list;
struct net_device *dev;
struct net_user_info *user;
struct net_kern_info *kern;
int private_size;
int transport_index;
int index;
unsigned char mac[ETH_ALEN];
int have_mac;
};
......@@ -41,7 +37,7 @@ struct uml_net_private {
};
struct net_kern_info {
void (*init)(struct net_device *, int);
void (*init)(struct net_device *, void *);
unsigned short (*protocol)(struct sk_buff *);
int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
......@@ -50,7 +46,11 @@ struct net_kern_info {
struct transport {
struct list_head list;
char *name;
int (*setup)(char *, struct uml_net *);
int (*setup)(char *, char **, void *);
struct net_user_info *user;
struct net_kern_info *kern;
int private_size;
int setup_size;
};
extern struct net_device *ether_init(int);
......@@ -58,8 +58,9 @@ extern unsigned short ether_protocol(struct sk_buff *);
extern int setup_etheraddr(char *str, unsigned char *addr);
extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
extern int tap_setup_common(char *str, char *type, char **dev_name,
char *hw_addr, int *hw_setup, char **gate_addr);
char **mac_out, char **gate_addr);
extern void register_transport(struct transport *new);
extern unsigned short eth_protocol(struct sk_buff *skb);
#endif
......
......@@ -43,6 +43,10 @@ extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
extern char *split_if_spec(char *str, ...);
extern int dev_netmask(void *d, void *m);
#endif
/*
......
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_ETHERTAP_KERN_H
#define __UM_ETHERTAP_KERN_H
#include "net_kern.h"
extern int ethertap_setup(char *arg, struct uml_net *dev);
#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:
*/
......@@ -12,42 +12,32 @@
#include "net_kern.h"
#include "net_user.h"
#include "etap.h"
#include "etap_kern.h"
struct ethertap_setup {
struct ethertap_init {
char *dev_name;
char *gate_addr;
};
struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
dev_name: NULL,
gate_addr: NULL,
}
};
static void etap_init(struct net_device *dev, int index)
static void etap_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct ethertap_data *epri;
struct ethertap_init *init = data;
init_etherdev(dev, 0);
pri = dev->priv;
epri = (struct ethertap_data *) pri->user;
epri->dev_name = ethertap_priv[index].dev_name;
epri->gate_addr = ethertap_priv[index].gate_addr;
*epri = ((struct ethertap_data)
{ dev_name : init->dev_name,
gate_addr : init->gate_addr,
data_fd : -1,
control_fd : -1,
dev : dev });
printk("ethertap backend - %s", epri->dev_name);
if(epri->gate_addr != NULL)
printk(", IP = %s", epri->gate_addr);
printk("\n");
epri->data_fd = -1;
epri->control_fd = -1;
}
static unsigned short etap_protocol(struct sk_buff *skb)
{
return(eth_type_trans(skb, skb->dev));
}
static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
......@@ -80,38 +70,36 @@ static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
struct net_kern_info ethertap_kern_info = {
init: etap_init,
protocol: etap_protocol,
protocol: eth_protocol,
read: etap_read,
write: etap_write,
};
static int ethertap_count = 0;
int ethertap_setup(char *str, struct uml_net *dev)
int ethertap_setup(char *str, char **mac_out, void *data)
{
struct ethertap_setup *pri;
int err;
pri = &ethertap_priv[ethertap_count];
err = tap_setup_common(str, "ethertap", &pri->dev_name, dev->mac,
&dev->have_mac, &pri->gate_addr);
if(err) return(err);
if(pri->dev_name == NULL){
struct ethertap_init *init = data;
*init = ((struct ethertap_init)
{ dev_name : NULL,
gate_addr : NULL });
if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
&init->gate_addr))
return(0);
if(init->dev_name == NULL){
printk("ethertap_setup : Missing tap device name\n");
return(1);
return(0);
}
dev->user = &ethertap_user_info;
dev->kern = &ethertap_kern_info;
dev->private_size = sizeof(struct ethertap_data);
dev->transport_index = ethertap_count++;
return(0);
return(1);
}
static struct transport ethertap_transport = {
list : LIST_HEAD_INIT(ethertap_transport.list),
name : "ethertap",
setup : ethertap_setup
setup : ethertap_setup,
user : &ethertap_user_info,
kern : &ethertap_kern_info,
private_size : sizeof(struct ethertap_data),
};
static int register_ethertap(void)
......
......@@ -14,8 +14,6 @@ struct tuntap_data {
char *gate_addr;
int fd;
void *dev;
unsigned char hw_addr[ETH_ADDR_LEN];
int hw_setup;
};
extern struct net_user_info tuntap_user_info;
......
......@@ -13,40 +13,30 @@
#include "net_user.h"
#include "tuntap.h"
struct tuntap_setup {
struct tuntap_init {
char *dev_name;
char *gate_addr;
};
struct tuntap_setup tuntap_priv[MAX_UML_NETDEV] = {
[ 0 ... MAX_UML_NETDEV - 1 ] =
{
dev_name: NULL,
gate_addr: NULL,
}
};
static void tuntap_init(struct net_device *dev, int index)
static void tuntap_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct tuntap_data *tpri;
struct tuntap_init *init = data;
init_etherdev(dev, 0);
pri = dev->priv;
tpri = (struct tuntap_data *) pri->user;
tpri->dev_name = tuntap_priv[index].dev_name;
tpri->fixed_config = (tpri->dev_name != NULL);
tpri->gate_addr = tuntap_priv[index].gate_addr;
*tpri = ((struct tuntap_data)
{ dev_name : init->dev_name,
fixed_config : (init->dev_name != NULL),
gate_addr : init->gate_addr,
fd : -1,
dev : dev });
printk("TUN/TAP backend - ");
if(tpri->gate_addr != NULL)
printk("IP = %s", tpri->gate_addr);
printk("\n");
tpri->fd = -1;
}
static unsigned short tuntap_protocol(struct sk_buff *skb)
{
return(eth_type_trans(skb, skb->dev));
}
static int tuntap_read(int fd, struct sk_buff **skb,
......@@ -66,34 +56,33 @@ static int tuntap_write(int fd, struct sk_buff **skb,
struct net_kern_info tuntap_kern_info = {
init: tuntap_init,
protocol: tuntap_protocol,
protocol: eth_protocol,
read: tuntap_read,
write: tuntap_write,
};
static int tuntap_count = 0;
int tuntap_setup(char *str, struct uml_net *dev)
int tuntap_setup(char *str, char **mac_out, void *data)
{
struct tuntap_setup *pri;
int err;
pri = &tuntap_priv[tuntap_count];
err = tap_setup_common(str, "tuntap", &pri->dev_name, dev->mac,
&dev->have_mac, &pri->gate_addr);
if(err) return(err);
struct tuntap_init *init = data;
dev->user = &tuntap_user_info;
dev->kern = &tuntap_kern_info;
dev->private_size = sizeof(struct tuntap_data);
dev->transport_index = tuntap_count++;
*init = ((struct tuntap_init)
{ dev_name : NULL,
gate_addr : NULL });
if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
&init->gate_addr))
return(0);
return(1);
}
static struct transport tuntap_transport = {
list : LIST_HEAD_INIT(tuntap_transport.list),
name : "tuntap",
setup : tuntap_setup
setup : tuntap_setup,
user : &tuntap_user_info,
kern : &tuntap_kern_info,
private_size : sizeof(struct tuntap_data),
setup_size : sizeof(struct tuntap_init),
};
static int register_tuntap(void)
......
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