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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/daemon_user.c Mon Aug 6 16:24:59 2001 @@ -193,6 +193,8 @@ open: daemon_open, close: daemon_close, set_mtu: daemon_set_mtu, + add_address: NULL, + delete_address: NULL, 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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/etap.h Mon Aug 6 16:24:59 2001 @@ -8,7 +8,8 @@ struct ethertap_data { char *dev_name; char *gate_addr; - int helper_fd; + int data_fd; + int control_fd; void *dev; 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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/ethertap_kern.c Mon Aug 6 16:24:59 2001 @@ -59,6 +59,8 @@ epri->hw_addr[0], epri->hw_addr[1], epri->hw_addr[2], epri->hw_addr[3], epri->hw_addr[4], epri->hw_addr[5]); printk("\n"); + epri->data_fd = -1; + epri->control_fd = -1; return(dev); } 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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/ethertap_user.c Mon Aug 6 16:26:15 2001 @@ -32,8 +32,10 @@ char *name; char *gate; char *addr; - int fd; - int me; + int data_remote; + int data_me; + int control_remote; + int control_me; int err; }; @@ -41,16 +43,22 @@ { struct etap_open_data *data = arg; int pid, status, n; - char fd_buf[sizeof("nnnnnn\0")]; + char version_buf[sizeof("nnnnn\0")]; + char data_fd_buf[sizeof("nnnnnn\0")]; + char control_fd_buf[sizeof("nnnnnn\0")]; char addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")], c; - char *setup_args[] = { "uml_net", "ethertap", data->name, fd_buf, - gate_buf, addr_buf, NULL }; - char *nosetup_args[] = { "uml_net", "ethertap", data->name, fd_buf, + char *setup_args[] = { "uml_net", version_buf, "ethertap", data->name, + data_fd_buf, control_fd_buf, gate_buf, + addr_buf, NULL }; + char *nosetup_args[] = { "uml_net", version_buf, "ethertap", + data->name, data_fd_buf, control_fd_buf, NULL }; char **args; - sprintf(fd_buf, "%d", data->fd); + sprintf(data_fd_buf, "%d", data->data_remote); + sprintf(control_fd_buf, "%d", data->control_remote); + sprintf(version_buf, "%d", UML_NET_VERSION); if(data->gate != NULL){ strcpy(addr_buf, data->addr); strcpy(gate_buf, data->gate); @@ -61,21 +69,21 @@ if((pid = fork()) == 0){ char zero = 0; - close(data->me); + close(data->data_me); + close(data->control_me); execvp(args[0], args); printk("Exec of '%s' failed - errno = %d\n", args[0], errno); - write(data->fd, &zero, sizeof(zero)); + write(data->control_remote, &zero, sizeof(zero)); exit(errno); } else if(pid < 0) data->err = errno; - n = read(data->me, &c, sizeof(c)); + n = read(data->control_me, &c, sizeof(c)); if(n != sizeof(c)){ printk("etap_open - failed to read response from helper : " "return = %d, errno = %d\n", n, errno); if(waitpid(pid, &status, 0) < 0) data->err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){ - printk("'ethertap_helper' didn't exit with " - "status 1\n"); + printk("uml_net didn't exit with status 1\n"); data->err = EINVAL; } else data->err = EINVAL; @@ -83,11 +91,40 @@ else if(c != 1) data->err = EINVAL; } +struct addr_change { + enum { ADD_ADDR, DEL_ADDR } what; + unsigned char addr[4]; +}; + +static void etap_open_addr(unsigned char *addr, void *arg) +{ + int fd = *((int *) arg); + struct addr_change change; + + change.what = ADD_ADDR; + memcpy(change.addr, addr, sizeof(change.addr)); + if(write(fd, &change, sizeof(change)) != sizeof(change)) + printk("etap_add_addr - request failed, errno = %d\n", + errno); +} + +static void etap_close_addr(unsigned char *addr, void *arg) +{ + int fd = *((int *) arg); + struct addr_change change; + + change.what = DEL_ADDR; + memcpy(change.addr, addr, sizeof(change.addr)); + if(write(fd, &change, sizeof(change)) != sizeof(change)) + printk("etap_close_addr - request failed, errno = %d\n", + errno); +} + static int etap_open(void *data) { struct ethertap_data *pri = data; struct etap_open_data tap_data; - int fds[2]; + int data_fds[2], control_fds[2]; char addr[sizeof("255.255.255.255\0")], ether[6]; if((pri->gate_addr != NULL) || !pri->hw_setup){ @@ -127,12 +164,21 @@ set_ether_mac(pri->dev, ether); } tap_data.name = pri->dev_name; - if(socketpair(PF_UNIX, SOCK_DGRAM, 0, fds) < 0){ - printk("socketpair failed - errno = %d\n", errno); + + if(socketpair(PF_UNIX, SOCK_DGRAM, 0, data_fds) < 0){ + printk("data socketpair failed - errno = %d\n", errno); + return(-errno); + } + tap_data.data_remote = data_fds[1]; + tap_data.data_me = data_fds[0]; + + if(socketpair(PF_UNIX, SOCK_STREAM, 0, control_fds) < 0){ + printk("data socketpair failed - errno = %d\n", errno); return(-errno); } - tap_data.fd = fds[1]; - tap_data.me = fds[0]; + tap_data.control_remote = control_fds[1]; + tap_data.control_me = control_fds[0]; + tap_data.gate = pri->gate_addr; tap_data.addr = addr; tracing_cb(etap_tramp, &tap_data); @@ -140,16 +186,21 @@ printk("etap_tramp failed - errno = %d\n", tap_data.err); return(-tap_data.err); } - pri->helper_fd = fds[1]; - return(fds[0]); + pri->data_fd = data_fds[0]; + pri->control_fd = control_fds[0]; + iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); + return(data_fds[0]); } static void etap_close(int fd, void *data) { struct ethertap_data *pri = data; + iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); close(fd); - shutdown(pri->helper_fd, SHUT_RDWR); + shutdown(pri->data_fd, SHUT_RDWR); + close(pri->data_fd); + close(pri->control_fd); } int etap_user_read(int fd, void *buf, int len, struct ethertap_data *pri) @@ -180,11 +231,29 @@ return(mtu); } +static void etap_add_addr(unsigned char *addr, void *data) +{ + struct ethertap_data *pri = data; + + if(pri->control_fd == -1) return; + etap_open_addr(addr, &pri->control_fd); +} + +static void etap_del_addr(unsigned char *addr, void *data) +{ + struct ethertap_data *pri = data; + + if(pri->control_fd == -1) return; + etap_close_addr(addr, &pri->control_fd); +} + struct net_user_info ethertap_user_info = { init: etap_user_init, open: etap_open, close: etap_close, set_mtu: etap_set_mtu, + add_address: etap_add_addr, + delete_address: etap_del_addr, max_packet: MAX_PACKET - ETH_HEADER_ETHERTAP }; 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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/mcast_user.c Mon Aug 6 16:24:59 2001 @@ -197,6 +197,8 @@ open: mcast_open, close: mcast_close, set_mtu: mcast_set_mtu, + add_address: NULL, + delete_address: NULL, max_packet: MAX_PACKET - ETH_HEADER_OTHER }; 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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/net_kern.c Mon Aug 6 16:24:59 2001 @@ -361,6 +361,8 @@ lp->close = device->user->close; lp->read = device->kern->read; lp->write = device->kern->write; + lp->add_address = device->user->add_address; + lp->delete_address = device->user->delete_address; lp->set_mtu = device->user->set_mtu; if(device->user->init) @@ -420,13 +422,50 @@ remove: net_remove, }; -int net_mc_init(void) +static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa = ptr; + u32 addr = ifa->ifa_address; + struct net_device *dev = ifa->ifa_dev->dev; + struct uml_net_private *lp; + void (*proc)(unsigned char *addr, void *); + unsigned char addr_buf[4]; + + if(dev->open != uml_net_open) return NOTIFY_DONE; + + lp = dev->priv; + proc = NULL; + switch (event){ + case NETDEV_UP: + proc = lp->add_address; + break; + case NETDEV_DOWN: + proc = lp->delete_address; + break; + } + if(proc != NULL){ + addr_buf[0] = addr & 0xff; + addr_buf[1] = (addr >> 8) & 0xff; + addr_buf[2] = (addr >> 16) & 0xff; + addr_buf[3] = addr >> 24; + (*proc)(addr_buf, &lp->user); + } + return NOTIFY_DONE; +} + +struct notifier_block uml_inetaddr_notifier = { + notifier_call: uml_inetaddr_event, +}; + +static int uml_net_init(void) { mconsole_register_dev(&net_mc); + register_inetaddr_notifier(¨_inetaddr_notifier); return(0); } -__initcall(net_mc_init); +__initcall(uml_net_init); static void close_devices(void) { @@ -508,6 +547,26 @@ if(skb != NULL) skb_put(skb, extra); return(skb); } + +void iter_addresses(void *d, void (*cb)(unsigned char *, void *), void *arg) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + unsigned char address[4]; + + if(ip == NULL) return; + in = ip->ifa_list; + while(in != NULL){ + address[0] = in->ifa_address & 0xff; + address[1] = (in->ifa_address >> 8) & 0xff; + address[2] = (in->ifa_address >> 16) & 0xff; + address[3] = in->ifa_address >> 24; + (*cb)(address, arg); + in = in->ifa_next; + } +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -Naur -X exclude-files ac_cur/arch/um/drivers/net_kern.h ac/arch/um/drivers/net_kern.h --- ac_cur/arch/um/drivers/net_kern.h Sun Aug 5 16:15:32 2001 +++ ac/arch/um/drivers/net_kern.h Mon Aug 6 16:31:35 2001 @@ -29,6 +29,9 @@ void (*close)(int, void *); int (*read)(int, struct sk_buff **skb, struct uml_net_private *); int (*write)(int, struct sk_buff *skb, struct uml_net_private *); + + void (*add_address)(unsigned char *, void *); + void (*delete_address)(unsigned char *, void *); int (*set_mtu)(int mtu, void *); int user[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 Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/net_user.h Mon Aug 6 16:24:59 2001 @@ -6,17 +6,23 @@ #define ETH_HEADER_OTHER (14) #define ETH_MAX_PACKET (1500) +#define UML_NET_VERSION (1) + struct net_user_info { void (*init)(void *, void *); int (*open)(void *); void (*close)(int, void *); int (*set_mtu)(int mtu, void *); + void (*add_address)(unsigned char *, void *); + void (*delete_address)(unsigned char *, void *); int max_packet; }; extern void ether_user_init(void *data, void *dev); extern void dev_ip_addr(void *d, char *buf, char *bin_buf); extern void set_ether_mac(void *d, unsigned char *addr); +extern void iter_addresses(void *d, void (*cb)(unsigned char *, void *), + void *arg); #endif diff -Naur -X exclude-files ac_cur/arch/um/drivers/slip_user.c ac/arch/um/drivers/slip_user.c --- ac_cur/arch/um/drivers/slip_user.c Sun Aug 5 16:10:13 2001 +++ ac/arch/um/drivers/slip_user.c Mon Aug 6 16:24:59 2001 @@ -82,10 +82,11 @@ { struct slip_data *pri = data; struct slip_tramp_data slip_data; + char version_buf[sizeof("nnnnn\0")]; char fd_buf[sizeof("nnnnnn\0")], addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; - char *argv[] = { "uml_net", "slip", "up", fd_buf, gate_buf, addr_buf, - NULL }; + char *argv[] = { "uml_net", version_buf, "slip", "up", fd_buf, + gate_buf, addr_buf, NULL }; int sfd, mfd, disc, sencap; if((mfd = get_pty()) < 0){ @@ -101,6 +102,7 @@ pri->pos = 0; pri->esc = 0; if(pri->gate_addr != NULL){ + sprintf(version_buf, "%d", UML_NET_VERSION); sprintf(fd_buf, "%d", sfd); dev_ip_addr(pri->dev, addr_buf, NULL); strcpy(gate_buf, pri->gate_addr); @@ -134,8 +136,11 @@ struct slip_data *pri = data; struct slip_tramp_data slip_data; char fd_buf[sizeof("nnnnnn\0")], addr_buf[sizeof("nnn.nnn.nnn.nnn\0")]; - char *argv[] = { "uml_net", "slip", "down", fd_buf, addr_buf, NULL }; + char version_buf[sizeof("nnnnn\0")]; + char *argv[] = { "uml_net", "slip", version_buf, "down", fd_buf, + addr_buf, NULL }; + sprintf(version_buf, "%d", UML_NET_VERSION); sprintf(fd_buf, "%d", pri->slave); dev_ip_addr(pri->dev, addr_buf, NULL); slip_data.args = argv; @@ -262,6 +267,8 @@ open: slip_open, close: slip_close, set_mtu: slip_set_mtu, + add_address: NULL, + delete_address: NULL, max_packet: BUF_SIZE };