1
linux/arch/um/drivers/umcast_kern.c
Nolan Leake 4ff4d8d342 um: add ucast ethernet transport
The ucast transport is similar to the mcast transport (and, in fact,
shares most of its code), only it uses UDP unicast to move packets.

Obviously this is only useful for point-to-point connections between
virtual ethernet devices.

Signed-off-by: Nolan Leake <nolan@cumulusnetworks.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-05-25 08:39:41 -07:00

189 lines
4.6 KiB
C

/*
* user-mode-linux networking multicast transport
* Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*
* based on the existing uml-networking code, which is
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
* James Leu (jleu@mindspring.net).
* Copyright (C) 2001 by various other people who didn't put their name here.
*
* Licensed under the GPL.
*/
#include "linux/init.h"
#include <linux/netdevice.h>
#include "umcast.h"
#include "net_kern.h"
struct umcast_init {
char *addr;
int lport;
int rport;
int ttl;
bool unicast;
};
static void umcast_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct umcast_data *dpri;
struct umcast_init *init = data;
pri = netdev_priv(dev);
dpri = (struct umcast_data *) pri->user;
dpri->addr = init->addr;
dpri->lport = init->lport;
dpri->rport = init->rport;
dpri->unicast = init->unicast;
dpri->ttl = init->ttl;
dpri->dev = dev;
if (dpri->unicast) {
printk(KERN_INFO "ucast backend address: %s:%u listen port: "
"%u\n", dpri->addr, dpri->rport, dpri->lport);
} else {
printk(KERN_INFO "mcast backend multicast address: %s:%u, "
"TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
}
}
static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
{
return net_recvfrom(fd, skb_mac_header(skb),
skb->dev->mtu + ETH_HEADER_OTHER);
}
static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
{
return umcast_user_write(fd, skb->data, skb->len,
(struct umcast_data *) &lp->user);
}
static const struct net_kern_info umcast_kern_info = {
.init = umcast_init,
.protocol = eth_protocol,
.read = umcast_read,
.write = umcast_write,
};
static int mcast_setup(char *str, char **mac_out, void *data)
{
struct umcast_init *init = data;
char *port_str = NULL, *ttl_str = NULL, *remain;
char *last;
*init = ((struct umcast_init)
{ .addr = "239.192.168.1",
.lport = 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) {
init->lport = simple_strtoul(port_str, &last, 10);
if ((*last != '\0') || (last == port_str)) {
printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
port_str);
return 0;
}
}
if (ttl_str != NULL) {
init->ttl = simple_strtoul(ttl_str, &last, 10);
if ((*last != '\0') || (last == ttl_str)) {
printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
ttl_str);
return 0;
}
}
init->unicast = false;
init->rport = init->lport;
printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
init->lport, init->ttl);
return 1;
}
static int ucast_setup(char *str, char **mac_out, void *data)
{
struct umcast_init *init = data;
char *lport_str = NULL, *rport_str = NULL, *remain;
char *last;
*init = ((struct umcast_init)
{ .addr = "",
.lport = 1102,
.rport = 1102 });
remain = split_if_spec(str, mac_out, &init->addr,
&lport_str, &rport_str, NULL);
if (remain != NULL) {
printk(KERN_ERR "ucast_setup - Extra garbage on "
"specification : '%s'\n", remain);
return 0;
}
if (lport_str != NULL) {
init->lport = simple_strtoul(lport_str, &last, 10);
if ((*last != '\0') || (last == lport_str)) {
printk(KERN_ERR "ucast_setup - Bad listen port : "
"'%s'\n", lport_str);
return 0;
}
}
if (rport_str != NULL) {
init->rport = simple_strtoul(rport_str, &last, 10);
if ((*last != '\0') || (last == rport_str)) {
printk(KERN_ERR "ucast_setup - Bad remote port : "
"'%s'\n", rport_str);
return 0;
}
}
init->unicast = true;
printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
init->lport, init->addr, init->rport);
return 1;
}
static struct transport mcast_transport = {
.list = LIST_HEAD_INIT(mcast_transport.list),
.name = "mcast",
.setup = mcast_setup,
.user = &umcast_user_info,
.kern = &umcast_kern_info,
.private_size = sizeof(struct umcast_data),
.setup_size = sizeof(struct umcast_init),
};
static struct transport ucast_transport = {
.list = LIST_HEAD_INIT(ucast_transport.list),
.name = "ucast",
.setup = ucast_setup,
.user = &umcast_user_info,
.kern = &umcast_kern_info,
.private_size = sizeof(struct umcast_data),
.setup_size = sizeof(struct umcast_init),
};
static int register_umcast(void)
{
register_transport(&mcast_transport);
register_transport(&ucast_transport);
return 0;
}
late_initcall(register_umcast);