diff -Naur -X exclude-files ac_cur/arch/um/config.in ac/arch/um/config.in --- ac_cur/arch/um/config.in Thu Jun 14 12:33:46 2001 +++ ac/arch/um/config.in Thu Jun 14 12:57:41 2001 @@ -61,6 +61,7 @@ bool 'Ethertap transport' CONFIG_NET_ETHERTAP bool 'Daemon transport' CONFIG_NET_DAEMON bool 'Slip transport' CONFIG_NET_SLIP + bool 'Multicast transport' CONFIG_NET_MCAST fi endmenu fi diff -Naur -X exclude-files ac_cur/arch/um/defconfig ac/arch/um/defconfig --- ac_cur/arch/um/defconfig Thu Jun 14 12:33:46 2001 +++ ac/arch/um/defconfig Thu Jun 14 13:29:10 2001 @@ -93,6 +93,7 @@ CONFIG_NET_ETHERTAP=y CONFIG_NET_DAEMON=y CONFIG_NET_SLIP=y +CONFIG_NET_MCAST=y # # File systems diff -Naur -X exclude-files ac_cur/arch/um/drivers/Makefile ac/arch/um/drivers/Makefile --- ac_cur/arch/um/drivers/Makefile Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/Makefile Thu Jun 14 12:58:01 2001 @@ -27,6 +27,8 @@ CFLAGS_daemon_kern.o := $(CFLAGS) CFLAGS_daemon_user.o := $(USER_CFLAGS) CFLAGS_net_kern.o := $(CFLAGS) +CFLAGS_mcast_user.o := $(USER_CFLAGS) +CFLAGS_mcast_kern.o := $(CFLAGS) obj-$(CONFIG_STDIO_CONSOLE) += stdio_console.o stdio_console_user.o obj-$(CONFIG_SSL) += ssl.o @@ -37,6 +39,7 @@ obj-$(CONFIG_NET_SLIP) += slip_user.o slip_kern.o obj-$(CONFIG_NET_ETHERTAP) += ethertap_user.o ethertap_kern.o obj-$(CONFIG_NET_DAEMON) += daemon_kern.o daemon_user.o +obj-$(CONFIG_NET_MCAST) += mcast_user.o mcast_kern.o override CFLAGS = diff -Naur -X exclude-files ac_cur/arch/um/drivers/daemon.h ac/arch/um/drivers/daemon.h --- ac_cur/arch/um/drivers/daemon.h Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/daemon.h Thu Jun 14 12:58:29 2001 @@ -3,8 +3,7 @@ * Licensed under the GPL */ -#define ETH_ADDR_LEN 6 -#define DAEMON_HEADER (14) +#include "net_user.h" struct daemon_data { char *sock_type; diff -Naur -X exclude-files ac_cur/arch/um/drivers/daemon_kern.c ac/arch/um/drivers/daemon_kern.c --- ac_cur/arch/um/drivers/daemon_kern.c Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/daemon_kern.c Thu Jun 14 13:10:27 2001 @@ -63,10 +63,10 @@ static int daemon_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) { - *skb = ether_adjust_skb(*skb, DAEMON_HEADER); + *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if(*skb == NULL) return(-ENOMEM); return(daemon_user_read(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + DAEMON_HEADER, + (*skb)->dev->mtu + ETH_HEADER_OTHER, (struct daemon_data *) &lp->user)); } diff -Naur -X exclude-files ac_cur/arch/um/drivers/daemon_user.c ac/arch/um/drivers/daemon_user.c --- ac_cur/arch/um/drivers/daemon_user.c Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/daemon_user.c Thu Jun 14 13:06:35 2001 @@ -16,7 +16,7 @@ #include "user_util.h" #include "user.h" -#define MAX_PACKET 1514 +#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) enum request_type { REQ_NEW_CONTROL }; @@ -163,7 +163,10 @@ struct sockaddr_un *data_addr = pri->data_addr; n = sendto(fd, buf, len, 0, data_addr, sizeof(*data_addr)); - if(n < 0) return(-errno); + if(n < 0){ + if(errno == EAGAIN) return(0); + return(-errno); + } return(n); } @@ -184,7 +187,7 @@ open: daemon_open, close: daemon_close, set_mtu: daemon_set_mtu, - max_packet: MAX_PACKET - DAEMON_HEADER + max_packet: MAX_PACKET - ETH_HEADER_OTHER }; /* diff -Naur -X exclude-files ac_cur/arch/um/drivers/etap.h ac/arch/um/drivers/etap.h --- ac_cur/arch/um/drivers/etap.h Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/etap.h Thu Jun 14 13:01:16 2001 @@ -3,14 +3,14 @@ * Licensed under the GPL */ -#define ETHERTAP_HEADER (16) +#include "net_user.h" struct ethertap_data { char *dev_name; char *gate_addr; int helper_fd; void *dev; - unsigned char hw_addr[6]; + unsigned char hw_addr[ETH_ADDR_LEN]; int hw_setup; }; diff -Naur -X exclude-files ac_cur/arch/um/drivers/ethertap_kern.c ac/arch/um/drivers/ethertap_kern.c --- ac_cur/arch/um/drivers/ethertap_kern.c Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/ethertap_kern.c Thu Jun 14 13:01:45 2001 @@ -80,10 +80,10 @@ { int len; - *skb = ether_adjust_skb(*skb, ETHERTAP_HEADER); + *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP); if(*skb == NULL) return(-ENOMEM); len = etap_user_read(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + 2 * ETHERTAP_HEADER, + (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP, (struct ethertap_data *) &lp->user); if(len <= 0) return(len); skb_pull(*skb, 2); diff -Naur -X exclude-files ac_cur/arch/um/drivers/ethertap_user.c ac/arch/um/drivers/ethertap_user.c --- ac_cur/arch/um/drivers/ethertap_user.c Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/ethertap_user.c Thu Jun 14 13:09:04 2001 @@ -18,7 +18,7 @@ #include "net_user.h" #include "etap.h" -#define MAX_PACKET 1500 +#define MAX_PACKET ETH_MAX_PACKET void etap_user_init(void *data, void *dev) { @@ -155,7 +155,7 @@ open: etap_open, close: etap_close, set_mtu: etap_set_mtu, - max_packet: MAX_PACKET - ETHERTAP_HEADER + max_packet: MAX_PACKET - ETH_HEADER_ETHERTAP }; /* diff -Naur -X exclude-files ac_cur/arch/um/drivers/mcast.h ac/arch/um/drivers/mcast.h --- ac_cur/arch/um/drivers/mcast.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/mcast.h Thu Jun 14 13:02:56 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "net_user.h" + +struct mcast_data { + char *addr; + unsigned short port; + void *mcast_addr; + int ttl; + unsigned char hwaddr[ETH_ADDR_LEN]; + int hw_setup; + void *dev; +}; + +extern struct net_user_info mcast_user_info; + +extern int mcast_user_set_mac(struct mcast_data *pri, unsigned char *hwaddr, + int len); +extern void mcast_setup(char *str, struct uml_net *dev); +extern int mcast_user_read(int fd, void *buf, int len, + struct mcast_data *data); +extern int mcast_user_write(int fd, void *buf, int len, + struct mcast_data *pri); + +/* + * 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 -Naur -X exclude-files ac_cur/arch/um/drivers/mcast_kern.c ac/arch/um/drivers/mcast_kern.c --- ac_cur/arch/um/drivers/mcast_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/mcast_kern.c Thu Jun 14 13:02:56 2001 @@ -0,0 +1,167 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte + * + * 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/kernel.h" +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/etherdevice.h" +#include "linux/in.h" +#include "linux/inet.h" +#include "net_kern.h" +#include "net_user.h" +#include "mcast.h" + +struct mcast_data mcast_priv[MAX_UML_NETDEV] = { + [ 0 ... MAX_UML_NETDEV - 1 ] = + { + addr: "239.192.168.1", + port: 1102, + ttl: 1, + hwaddr: { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, + hw_setup: 0, + } +}; + +struct net_device *mcast_init(int private_size, int index) +{ + struct net_device *dev; + struct uml_net_private *pri; + struct mcast_data *dpri; + + dev = init_etherdev(NULL, private_size); + if (!dev) + return NULL; + + pri = dev->priv; + dpri = (struct mcast_data *) pri->user; + *dpri = mcast_priv[index]; + memcpy(dev->dev_addr, dpri->hwaddr, ETH_ALEN); + printk("mcast backend "); + if(dpri->hw_setup) + printk("ethernet address=%x:%x:%x:%x:%x:%x ", + dpri->hwaddr[0], dpri->hwaddr[1], dpri->hwaddr[2], + dpri->hwaddr[3], dpri->hwaddr[4], dpri->hwaddr[5]); + + printk("multicast adddress: %s:%u, TTL:%u ", + dpri->addr, dpri->port, dpri->ttl); + + printk("\n"); + return(dev); +} + +static unsigned short mcast_protocol(struct sk_buff *skb) +{ + return eth_type_trans(skb, skb->dev); +} + +static int mcast_set_mac(struct sockaddr *addr, void *data) +{ + struct mcast_data *pri = data; + struct net_device *dev = pri->dev; + struct sockaddr *hwaddr = addr; + + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + return mcast_user_set_mac(pri, hwaddr->sa_data, ETH_ALEN); +} + +static int mcast_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 mcast_user_read(fd, (*skb)->mac.raw, + (*skb)->dev->mtu + ETH_HEADER_OTHER, + (struct mcast_data *) &lp->user); +} + +static int mcast_write(int fd, struct sk_buff *skb, + struct uml_net_private *lp) +{ + return mcast_user_write(fd, skb->data, skb->len, + (struct mcast_data *) &lp->user); +} + +static struct net_kern_info mcast_kern_info = { + init: mcast_init, + protocol: mcast_protocol, + set_mac: mcast_set_mac, + read: mcast_read, + write: mcast_write, +}; + +static int mcast_count = 0; + +void mcast_setup(char *str, struct uml_net *dev) +{ + 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, + mcast_priv[n].hwaddr); + if (!err) + mcast_priv[n].hw_setup = 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; + } + } + 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); + + return; +} + +/* + * 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 -Naur -X exclude-files ac_cur/arch/um/drivers/mcast_user.c ac/arch/um/drivers/mcast_user.c --- ac_cur/arch/um/drivers/mcast_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/mcast_user.c Thu Jun 14 13:02:56 2001 @@ -0,0 +1,207 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte + * + * 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 +#include +#include +#include +#include +#include +#include "net_user.h" +#include "mcast.h" +#include "kern_util.h" +#include "user_util.h" +#include "user.h" + +#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) + +static struct sockaddr_in *new_addr(char *addr, unsigned short port) +{ + struct sockaddr_in *sin; + + sin = um_kmalloc(sizeof(struct sockaddr_in)); + if(sin == NULL){ + printk("new_addr: allocation of sockaddr_in failed\n"); + return(NULL); + } + sin->sin_addr.s_addr = in_aton(addr); + sin->sin_port = port; + return(sin); +} + +static void mcast_user_init(void *data, void *dev) +{ + struct mcast_data *pri = data; + + pri->mcast_addr = new_addr(pri->addr, pri->port); + pri->dev = dev; +} + +static int mcast_open(void *data) +{ + struct mcast_data *pri = data; + struct sockaddr_in *sin = pri->mcast_addr; + struct ip_mreq mreq; + char addr[sizeof("255.255.255.255\0")]; + int fd, err, yes = 1; + + + if(!pri->hw_setup){ + pri->hwaddr[0] = 0xfe; + pri->hwaddr[1] = 0xfd; + dev_ip_addr(pri->dev, addr, &pri->hwaddr[2]); + set_ether_mac(pri->dev, pri->hwaddr); + } + + if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) { + err = -EINVAL; + goto out; + } + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ + printk("mcast_open : data socket failed, errno = %d\n", + errno); + err = -ENOMEM; + goto out; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { + printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", + errno); + close(fd); + err = -EINVAL; + goto out; + } + + /* set ttl according to config */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, + sizeof(pri->ttl)) < 0) { + printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", + errno); + close(fd); + err = -EINVAL; + goto out; + } + + /* set LOOP, so data does get fed back to local sockets */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { + printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", + errno); + close(fd); + err = -EINVAL; + goto out; + } + + /* bind socket to mcast address */ + if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { + printk("mcast_open : data bind failed, errno = %d\n", errno); + close(fd); + err = -EINVAL; + goto out; + } + + /* subscribe to the multicast group */ + mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n", + errno); + close(fd); + err = -EINVAL; + goto out; + } + + return(fd); + out: + return(err); +} + +static void mcast_close(int fd, void *data) +{ + struct ip_mreq mreq; + struct mcast_data *pri = data; + struct sockaddr_in *sin = pri->mcast_addr; + + mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n", + errno); + } + + close(fd); +} + +int mcast_user_read(int fd, void *buf, int len, struct mcast_data *data) +{ + int n; + + while (((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && + (errno == EINTR)) ; + + if (n < 0) { + if (errno == EAGAIN) + return 0; + return -errno; + } else if (n == 0) + return -ENOTCONN; + + return n; +} + +int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) +{ + int n; + struct sockaddr_in *data_addr = pri->mcast_addr; + + n = sendto(fd, buf, len, 0, (struct sockaddr *) data_addr, + sizeof(*data_addr)); + + if (n < 0) + return(-errno); + + return(n); +} + +static int mcast_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +int mcast_user_set_mac(struct mcast_data *pri, unsigned char *hwaddr, + int len) +{ + memcpy(pri->hwaddr, hwaddr, len); + return 0; +} + +struct net_user_info mcast_user_info = { + init: mcast_user_init, + open: mcast_open, + close: mcast_close, + set_mtu: mcast_set_mtu, + 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: + */ diff -Naur -X exclude-files ac_cur/arch/um/drivers/net_kern.c ac/arch/um/drivers/net_kern.c --- ac_cur/arch/um/drivers/net_kern.c Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/net_kern.c Thu Jun 14 13:31:02 2001 @@ -22,6 +22,7 @@ #include "slip.h" #include "etap.h" #include "daemon.h" +#include "mcast.h" LIST_HEAD(opened); @@ -55,17 +56,30 @@ } str++; #ifdef CONFIG_NET_ETHERTAP - if(!strncmp(str, "ethertap", strlen("ethertap"))) + if(!strncmp(str, "ethertap", strlen("ethertap"))){ ethertap_setup(&str[strlen("ethertap")], &devices[n]); + return(1); + } #endif #ifdef CONFIG_NET_DAEMON - if(!strncmp(str, "daemon", strlen("daemon"))) + if(!strncmp(str, "daemon", strlen("daemon"))){ daemon_setup(&str[strlen("daemon")], &devices[n]); + return(1); + } #endif #ifdef CONFIG_NET_SLIP - if(!strncmp(str, "slip", strlen("slip"))) + if(!strncmp(str, "slip", strlen("slip"))){ slip_setup(&str[strlen("slip")], &devices[n]); + return(1); + } +#endif +#ifdef CONFIG_NET_MCAST + if(!strncmp(str, "mcast", strlen("mcast"))){ + mcast_setup(&str[strlen("mcast")], &devices[n]); + return(1); + } #endif + printk(KERN_ERR "Unknown transport in eth_setup : %s\n", str); return(1); } diff -Naur -X exclude-files ac_cur/arch/um/drivers/net_user.h ac/arch/um/drivers/net_user.h --- ac_cur/arch/um/drivers/net_user.h Thu Jun 14 12:33:46 2001 +++ ac/arch/um/drivers/net_user.h Thu Jun 14 13:06:32 2001 @@ -1,6 +1,11 @@ #ifndef __UM_NET_USER_H__ #define __UM_NET_USER_H__ +#define ETH_ADDR_LEN (6) +#define ETH_HEADER_ETHERTAP (16) +#define ETH_HEADER_OTHER (14) +#define ETH_MAX_PACKET (1500) + struct uml_net { struct net_user_info *user; struct net_kern_info *kern;