11541Srgrimes// SPDX-License-Identifier: GPL-2.0 21541Srgrimes/* 31541Srgrimes * user-mode-linux networking multicast transport 41541Srgrimes * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> 51541Srgrimes * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 61541Srgrimes * 71541Srgrimes * based on the existing uml-networking code, which is 81541Srgrimes * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 91541Srgrimes * James Leu (jleu@mindspring.net). 101541Srgrimes * Copyright (C) 2001 by various other people who didn't put their name here. 111541Srgrimes * 121541Srgrimes */ 131541Srgrimes 141541Srgrimes#include <linux/init.h> 151541Srgrimes#include <linux/netdevice.h> 161541Srgrimes#include "umcast.h" 171541Srgrimes#include <net_kern.h> 181541Srgrimes 191541Srgrimesstruct umcast_init { 201541Srgrimes char *addr; 211541Srgrimes int lport; 221541Srgrimes int rport; 231541Srgrimes int ttl; 241541Srgrimes bool unicast; 251541Srgrimes}; 261541Srgrimes 271541Srgrimesstatic void umcast_init(struct net_device *dev, void *data) 281541Srgrimes{ 291541Srgrimes struct uml_net_private *pri; 301541Srgrimes struct umcast_data *dpri; 311541Srgrimes struct umcast_init *init = data; 321541Srgrimes 3350477Speter pri = netdev_priv(dev); 341541Srgrimes dpri = (struct umcast_data *) pri->user; 351541Srgrimes dpri->addr = init->addr; 361541Srgrimes dpri->lport = init->lport; 371541Srgrimes dpri->rport = init->rport; 381541Srgrimes dpri->unicast = init->unicast; 3998272Swollman dpri->ttl = init->ttl; 4098272Swollman dpri->dev = dev; 4198272Swollman 4298302Swollman if (dpri->unicast) { 43108478Smike printk(KERN_INFO "ucast backend address: %s:%u listen port: " 4498272Swollman "%u\n", dpri->addr, dpri->rport, dpri->lport); 4598272Swollman } else { 46103867Smike printk(KERN_INFO "mcast backend multicast address: %s:%u, " 47103867Smike "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); 48103867Smike } 49103867Smike} 50103867Smike 51104504Smikestatic int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) 52104504Smike{ 53104504Smike return net_recvfrom(fd, skb_mac_header(skb), 54104504Smike skb->dev->mtu + ETH_HEADER_OTHER); 55104504Smike} 56103867Smike 57103867Smikestatic int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) 58103867Smike{ 59103867Smike return umcast_user_write(fd, skb->data, skb->len, 60103867Smike (struct umcast_data *) &lp->user); 61103867Smike} 62103867Smike 63103867Smikestatic const struct net_kern_info umcast_kern_info = { 64103867Smike .init = umcast_init, 65103867Smike .protocol = eth_protocol, 66103867Smike .read = umcast_read, 67103867Smike .write = umcast_write, 68103867Smike}; 69103867Smike 70103867Smikestatic int mcast_setup(char *str, char **mac_out, void *data) 71103867Smike{ 72103867Smike struct umcast_init *init = data; 73103867Smike char *port_str = NULL, *ttl_str = NULL, *remain; 74103867Smike char *last; 75103867Smike 76107019Smike *init = ((struct umcast_init) 77103867Smike { .addr = "239.192.168.1", 78107019Smike .lport = 1102, 79107019Smike .ttl = 1 }); 80107019Smike 81103867Smike remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, 82107019Smike NULL); 83107377Smike if (remain != NULL) { 84103867Smike printk(KERN_ERR "mcast_setup - Extra garbage on " 85107019Smike "specification : '%s'\n", remain); 86103867Smike return 0; 87107377Smike } 88107377Smike 89107019Smike if (port_str != NULL) { 90107019Smike init->lport = simple_strtoul(port_str, &last, 10); 91107019Smike if ((*last != '\0') || (last == port_str)) { 92107019Smike printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", 93107019Smike port_str); 94107019Smike return 0; 95107019Smike } 96107019Smike } 97107019Smike 98103867Smike if (ttl_str != NULL) { 9998272Swollman init->ttl = simple_strtoul(ttl_str, &last, 10); 100103867Smike if ((*last != '\0') || (last == ttl_str)) { 10198272Swollman printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", 10298272Swollman ttl_str); 10398302Swollman return 0; 104103867Smike } 105103867Smike } 106103867Smike 107103867Smike init->unicast = false; 108103867Smike init->rport = init->lport; 10998272Swollman 11098272Swollman printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, 11198272Swollman init->lport, init->ttl); 11270650Swollman 113 return 1; 114} 115 116static 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 161static 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 171static 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 181static int register_umcast(void) 182{ 183 register_transport(&mcast_transport); 184 register_transport(&ucast_transport); 185 return 0; 186} 187 188late_initcall(register_umcast); 189