162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * user-mode-linux networking multicast transport 462306a36Sopenharmony_ci * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> 562306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * based on the existing uml-networking code, which is 862306a36Sopenharmony_ci * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 962306a36Sopenharmony_ci * James Leu (jleu@mindspring.net). 1062306a36Sopenharmony_ci * Copyright (C) 2001 by various other people who didn't put their name here. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include "umcast.h" 1762306a36Sopenharmony_ci#include <net_kern.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct umcast_init { 2062306a36Sopenharmony_ci char *addr; 2162306a36Sopenharmony_ci int lport; 2262306a36Sopenharmony_ci int rport; 2362306a36Sopenharmony_ci int ttl; 2462306a36Sopenharmony_ci bool unicast; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void umcast_init(struct net_device *dev, void *data) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct uml_net_private *pri; 3062306a36Sopenharmony_ci struct umcast_data *dpri; 3162306a36Sopenharmony_ci struct umcast_init *init = data; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci pri = netdev_priv(dev); 3462306a36Sopenharmony_ci dpri = (struct umcast_data *) pri->user; 3562306a36Sopenharmony_ci dpri->addr = init->addr; 3662306a36Sopenharmony_ci dpri->lport = init->lport; 3762306a36Sopenharmony_ci dpri->rport = init->rport; 3862306a36Sopenharmony_ci dpri->unicast = init->unicast; 3962306a36Sopenharmony_ci dpri->ttl = init->ttl; 4062306a36Sopenharmony_ci dpri->dev = dev; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (dpri->unicast) { 4362306a36Sopenharmony_ci printk(KERN_INFO "ucast backend address: %s:%u listen port: " 4462306a36Sopenharmony_ci "%u\n", dpri->addr, dpri->rport, dpri->lport); 4562306a36Sopenharmony_ci } else { 4662306a36Sopenharmony_ci printk(KERN_INFO "mcast backend multicast address: %s:%u, " 4762306a36Sopenharmony_ci "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return net_recvfrom(fd, skb_mac_header(skb), 5462306a36Sopenharmony_ci skb->dev->mtu + ETH_HEADER_OTHER); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci return umcast_user_write(fd, skb->data, skb->len, 6062306a36Sopenharmony_ci (struct umcast_data *) &lp->user); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const struct net_kern_info umcast_kern_info = { 6462306a36Sopenharmony_ci .init = umcast_init, 6562306a36Sopenharmony_ci .protocol = eth_protocol, 6662306a36Sopenharmony_ci .read = umcast_read, 6762306a36Sopenharmony_ci .write = umcast_write, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int mcast_setup(char *str, char **mac_out, void *data) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct umcast_init *init = data; 7362306a36Sopenharmony_ci char *port_str = NULL, *ttl_str = NULL, *remain; 7462306a36Sopenharmony_ci char *last; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci *init = ((struct umcast_init) 7762306a36Sopenharmony_ci { .addr = "239.192.168.1", 7862306a36Sopenharmony_ci .lport = 1102, 7962306a36Sopenharmony_ci .ttl = 1 }); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, 8262306a36Sopenharmony_ci NULL); 8362306a36Sopenharmony_ci if (remain != NULL) { 8462306a36Sopenharmony_ci printk(KERN_ERR "mcast_setup - Extra garbage on " 8562306a36Sopenharmony_ci "specification : '%s'\n", remain); 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (port_str != NULL) { 9062306a36Sopenharmony_ci init->lport = simple_strtoul(port_str, &last, 10); 9162306a36Sopenharmony_ci if ((*last != '\0') || (last == port_str)) { 9262306a36Sopenharmony_ci printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", 9362306a36Sopenharmony_ci port_str); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (ttl_str != NULL) { 9962306a36Sopenharmony_ci init->ttl = simple_strtoul(ttl_str, &last, 10); 10062306a36Sopenharmony_ci if ((*last != '\0') || (last == ttl_str)) { 10162306a36Sopenharmony_ci printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", 10262306a36Sopenharmony_ci ttl_str); 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci init->unicast = false; 10862306a36Sopenharmony_ci init->rport = init->lport; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, 11162306a36Sopenharmony_ci init->lport, init->ttl); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 1; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int ucast_setup(char *str, char **mac_out, void *data) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct umcast_init *init = data; 11962306a36Sopenharmony_ci char *lport_str = NULL, *rport_str = NULL, *remain; 12062306a36Sopenharmony_ci char *last; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci *init = ((struct umcast_init) 12362306a36Sopenharmony_ci { .addr = "", 12462306a36Sopenharmony_ci .lport = 1102, 12562306a36Sopenharmony_ci .rport = 1102 }); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci remain = split_if_spec(str, mac_out, &init->addr, 12862306a36Sopenharmony_ci &lport_str, &rport_str, NULL); 12962306a36Sopenharmony_ci if (remain != NULL) { 13062306a36Sopenharmony_ci printk(KERN_ERR "ucast_setup - Extra garbage on " 13162306a36Sopenharmony_ci "specification : '%s'\n", remain); 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (lport_str != NULL) { 13662306a36Sopenharmony_ci init->lport = simple_strtoul(lport_str, &last, 10); 13762306a36Sopenharmony_ci if ((*last != '\0') || (last == lport_str)) { 13862306a36Sopenharmony_ci printk(KERN_ERR "ucast_setup - Bad listen port : " 13962306a36Sopenharmony_ci "'%s'\n", lport_str); 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (rport_str != NULL) { 14562306a36Sopenharmony_ci init->rport = simple_strtoul(rport_str, &last, 10); 14662306a36Sopenharmony_ci if ((*last != '\0') || (last == rport_str)) { 14762306a36Sopenharmony_ci printk(KERN_ERR "ucast_setup - Bad remote port : " 14862306a36Sopenharmony_ci "'%s'\n", rport_str); 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci init->unicast = true; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n", 15662306a36Sopenharmony_ci init->lport, init->addr, init->rport); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 1; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic struct transport mcast_transport = { 16262306a36Sopenharmony_ci .list = LIST_HEAD_INIT(mcast_transport.list), 16362306a36Sopenharmony_ci .name = "mcast", 16462306a36Sopenharmony_ci .setup = mcast_setup, 16562306a36Sopenharmony_ci .user = &umcast_user_info, 16662306a36Sopenharmony_ci .kern = &umcast_kern_info, 16762306a36Sopenharmony_ci .private_size = sizeof(struct umcast_data), 16862306a36Sopenharmony_ci .setup_size = sizeof(struct umcast_init), 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct transport ucast_transport = { 17262306a36Sopenharmony_ci .list = LIST_HEAD_INIT(ucast_transport.list), 17362306a36Sopenharmony_ci .name = "ucast", 17462306a36Sopenharmony_ci .setup = ucast_setup, 17562306a36Sopenharmony_ci .user = &umcast_user_info, 17662306a36Sopenharmony_ci .kern = &umcast_kern_info, 17762306a36Sopenharmony_ci .private_size = sizeof(struct umcast_data), 17862306a36Sopenharmony_ci .setup_size = sizeof(struct umcast_init), 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int register_umcast(void) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci register_transport(&mcast_transport); 18462306a36Sopenharmony_ci register_transport(&ucast_transport); 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cilate_initcall(register_umcast); 189