| 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 |  | 
|  | 14 | #include "linux/init.h" | 
|  | 15 | #include <linux/netdevice.h> | 
|  | 16 | #include "umcast.h" | 
|  | 17 | #include "net_kern.h" | 
|  | 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); |