Nolan Leake | 4ff4d8d | 2011-05-24 17:13:02 -0700 | [diff] [blame] | 1 | /* |
| 2 | * user-mode-linux networking multicast transport |
| 3 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> |
| 4 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
| 5 | * |
| 6 | * based on the existing uml-networking code, which is |
| 7 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and |
| 8 | * James Leu (jleu@mindspring.net). |
| 9 | * Copyright (C) 2001 by various other people who didn't put their name here. |
| 10 | * |
| 11 | * Licensed under the GPL. |
| 12 | */ |
| 13 | |
Al Viro | 37185b3 | 2012-10-08 03:27:32 +0100 | [diff] [blame] | 14 | #include <linux/init.h> |
Nolan Leake | 4ff4d8d | 2011-05-24 17:13:02 -0700 | [diff] [blame] | 15 | #include <linux/netdevice.h> |
| 16 | #include "umcast.h" |
Al Viro | 37185b3 | 2012-10-08 03:27:32 +0100 | [diff] [blame] | 17 | #include <net_kern.h> |
Nolan Leake | 4ff4d8d | 2011-05-24 17:13:02 -0700 | [diff] [blame] | 18 | |
| 19 | struct umcast_init { |
| 20 | char *addr; |
| 21 | int lport; |
| 22 | int rport; |
| 23 | int ttl; |
| 24 | bool unicast; |
| 25 | }; |
| 26 | |
| 27 | static void umcast_init(struct net_device *dev, void *data) |
| 28 | { |
| 29 | struct uml_net_private *pri; |
| 30 | struct umcast_data *dpri; |
| 31 | struct umcast_init *init = data; |
| 32 | |
| 33 | pri = netdev_priv(dev); |
| 34 | dpri = (struct umcast_data *) pri->user; |
| 35 | dpri->addr = init->addr; |
| 36 | dpri->lport = init->lport; |
| 37 | dpri->rport = init->rport; |
| 38 | dpri->unicast = init->unicast; |
| 39 | dpri->ttl = init->ttl; |
| 40 | dpri->dev = dev; |
| 41 | |
| 42 | if (dpri->unicast) { |
| 43 | printk(KERN_INFO "ucast backend address: %s:%u listen port: " |
| 44 | "%u\n", dpri->addr, dpri->rport, dpri->lport); |
| 45 | } else { |
| 46 | printk(KERN_INFO "mcast backend multicast address: %s:%u, " |
| 47 | "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) |
| 52 | { |
| 53 | return net_recvfrom(fd, skb_mac_header(skb), |
| 54 | skb->dev->mtu + ETH_HEADER_OTHER); |
| 55 | } |
| 56 | |
| 57 | static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) |
| 58 | { |
| 59 | return umcast_user_write(fd, skb->data, skb->len, |
| 60 | (struct umcast_data *) &lp->user); |
| 61 | } |
| 62 | |
| 63 | static const struct net_kern_info umcast_kern_info = { |
| 64 | .init = umcast_init, |
| 65 | .protocol = eth_protocol, |
| 66 | .read = umcast_read, |
| 67 | .write = umcast_write, |
| 68 | }; |
| 69 | |
| 70 | static int mcast_setup(char *str, char **mac_out, void *data) |
| 71 | { |
| 72 | struct umcast_init *init = data; |
| 73 | char *port_str = NULL, *ttl_str = NULL, *remain; |
| 74 | char *last; |
| 75 | |
| 76 | *init = ((struct umcast_init) |
| 77 | { .addr = "239.192.168.1", |
| 78 | .lport = 1102, |
| 79 | .ttl = 1 }); |
| 80 | |
| 81 | remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, |
| 82 | NULL); |
| 83 | if (remain != NULL) { |
| 84 | printk(KERN_ERR "mcast_setup - Extra garbage on " |
| 85 | "specification : '%s'\n", remain); |
| 86 | return 0; |
| 87 | } |
| 88 | |
| 89 | if (port_str != NULL) { |
| 90 | init->lport = simple_strtoul(port_str, &last, 10); |
| 91 | if ((*last != '\0') || (last == port_str)) { |
| 92 | printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", |
| 93 | port_str); |
| 94 | return 0; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | if (ttl_str != NULL) { |
| 99 | init->ttl = simple_strtoul(ttl_str, &last, 10); |
| 100 | if ((*last != '\0') || (last == ttl_str)) { |
| 101 | printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", |
| 102 | ttl_str); |
| 103 | return 0; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | init->unicast = false; |
| 108 | init->rport = init->lport; |
| 109 | |
| 110 | printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, |
| 111 | init->lport, init->ttl); |
| 112 | |
| 113 | return 1; |
| 114 | } |
| 115 | |
| 116 | static int ucast_setup(char *str, char **mac_out, void *data) |
| 117 | { |
| 118 | struct umcast_init *init = data; |
| 119 | char *lport_str = NULL, *rport_str = NULL, *remain; |
| 120 | char *last; |
| 121 | |
| 122 | *init = ((struct umcast_init) |
| 123 | { .addr = "", |
| 124 | .lport = 1102, |
| 125 | .rport = 1102 }); |
| 126 | |
| 127 | remain = split_if_spec(str, mac_out, &init->addr, |
| 128 | &lport_str, &rport_str, NULL); |
| 129 | if (remain != NULL) { |
| 130 | printk(KERN_ERR "ucast_setup - Extra garbage on " |
| 131 | "specification : '%s'\n", remain); |
| 132 | return 0; |
| 133 | } |
| 134 | |
| 135 | if (lport_str != NULL) { |
| 136 | init->lport = simple_strtoul(lport_str, &last, 10); |
| 137 | if ((*last != '\0') || (last == lport_str)) { |
| 138 | printk(KERN_ERR "ucast_setup - Bad listen port : " |
| 139 | "'%s'\n", lport_str); |
| 140 | return 0; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | if (rport_str != NULL) { |
| 145 | init->rport = simple_strtoul(rport_str, &last, 10); |
| 146 | if ((*last != '\0') || (last == rport_str)) { |
| 147 | printk(KERN_ERR "ucast_setup - Bad remote port : " |
| 148 | "'%s'\n", rport_str); |
| 149 | return 0; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | init->unicast = true; |
| 154 | |
| 155 | printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n", |
| 156 | init->lport, init->addr, init->rport); |
| 157 | |
| 158 | return 1; |
| 159 | } |
| 160 | |
| 161 | static struct transport mcast_transport = { |
| 162 | .list = LIST_HEAD_INIT(mcast_transport.list), |
| 163 | .name = "mcast", |
| 164 | .setup = mcast_setup, |
| 165 | .user = &umcast_user_info, |
| 166 | .kern = &umcast_kern_info, |
| 167 | .private_size = sizeof(struct umcast_data), |
| 168 | .setup_size = sizeof(struct umcast_init), |
| 169 | }; |
| 170 | |
| 171 | static struct transport ucast_transport = { |
| 172 | .list = LIST_HEAD_INIT(ucast_transport.list), |
| 173 | .name = "ucast", |
| 174 | .setup = ucast_setup, |
| 175 | .user = &umcast_user_info, |
| 176 | .kern = &umcast_kern_info, |
| 177 | .private_size = sizeof(struct umcast_data), |
| 178 | .setup_size = sizeof(struct umcast_init), |
| 179 | }; |
| 180 | |
| 181 | static int register_umcast(void) |
| 182 | { |
| 183 | register_transport(&mcast_transport); |
| 184 | register_transport(&ucast_transport); |
| 185 | return 0; |
| 186 | } |
| 187 | |
| 188 | late_initcall(register_umcast); |