1*dbddf429SAlex Dewar // SPDX-License-Identifier: GPL-2.0
24ff4d8d3SNolan Leake /*
34ff4d8d3SNolan Leake * user-mode-linux networking multicast transport
44ff4d8d3SNolan Leake * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
54ff4d8d3SNolan Leake * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
64ff4d8d3SNolan Leake *
74ff4d8d3SNolan Leake * based on the existing uml-networking code, which is
84ff4d8d3SNolan Leake * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
94ff4d8d3SNolan Leake * James Leu (jleu@mindspring.net).
104ff4d8d3SNolan Leake * Copyright (C) 2001 by various other people who didn't put their name here.
114ff4d8d3SNolan Leake *
124ff4d8d3SNolan Leake */
134ff4d8d3SNolan Leake
1437185b33SAl Viro #include <linux/init.h>
154ff4d8d3SNolan Leake #include <linux/netdevice.h>
164ff4d8d3SNolan Leake #include "umcast.h"
1737185b33SAl Viro #include <net_kern.h>
184ff4d8d3SNolan Leake
194ff4d8d3SNolan Leake struct umcast_init {
204ff4d8d3SNolan Leake char *addr;
214ff4d8d3SNolan Leake int lport;
224ff4d8d3SNolan Leake int rport;
234ff4d8d3SNolan Leake int ttl;
244ff4d8d3SNolan Leake bool unicast;
254ff4d8d3SNolan Leake };
264ff4d8d3SNolan Leake
umcast_init(struct net_device * dev,void * data)274ff4d8d3SNolan Leake static void umcast_init(struct net_device *dev, void *data)
284ff4d8d3SNolan Leake {
294ff4d8d3SNolan Leake struct uml_net_private *pri;
304ff4d8d3SNolan Leake struct umcast_data *dpri;
314ff4d8d3SNolan Leake struct umcast_init *init = data;
324ff4d8d3SNolan Leake
334ff4d8d3SNolan Leake pri = netdev_priv(dev);
344ff4d8d3SNolan Leake dpri = (struct umcast_data *) pri->user;
354ff4d8d3SNolan Leake dpri->addr = init->addr;
364ff4d8d3SNolan Leake dpri->lport = init->lport;
374ff4d8d3SNolan Leake dpri->rport = init->rport;
384ff4d8d3SNolan Leake dpri->unicast = init->unicast;
394ff4d8d3SNolan Leake dpri->ttl = init->ttl;
404ff4d8d3SNolan Leake dpri->dev = dev;
414ff4d8d3SNolan Leake
424ff4d8d3SNolan Leake if (dpri->unicast) {
434ff4d8d3SNolan Leake printk(KERN_INFO "ucast backend address: %s:%u listen port: "
444ff4d8d3SNolan Leake "%u\n", dpri->addr, dpri->rport, dpri->lport);
454ff4d8d3SNolan Leake } else {
464ff4d8d3SNolan Leake printk(KERN_INFO "mcast backend multicast address: %s:%u, "
474ff4d8d3SNolan Leake "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
484ff4d8d3SNolan Leake }
494ff4d8d3SNolan Leake }
504ff4d8d3SNolan Leake
umcast_read(int fd,struct sk_buff * skb,struct uml_net_private * lp)514ff4d8d3SNolan Leake static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
524ff4d8d3SNolan Leake {
534ff4d8d3SNolan Leake return net_recvfrom(fd, skb_mac_header(skb),
544ff4d8d3SNolan Leake skb->dev->mtu + ETH_HEADER_OTHER);
554ff4d8d3SNolan Leake }
564ff4d8d3SNolan Leake
umcast_write(int fd,struct sk_buff * skb,struct uml_net_private * lp)574ff4d8d3SNolan Leake static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
584ff4d8d3SNolan Leake {
594ff4d8d3SNolan Leake return umcast_user_write(fd, skb->data, skb->len,
604ff4d8d3SNolan Leake (struct umcast_data *) &lp->user);
614ff4d8d3SNolan Leake }
624ff4d8d3SNolan Leake
634ff4d8d3SNolan Leake static const struct net_kern_info umcast_kern_info = {
644ff4d8d3SNolan Leake .init = umcast_init,
654ff4d8d3SNolan Leake .protocol = eth_protocol,
664ff4d8d3SNolan Leake .read = umcast_read,
674ff4d8d3SNolan Leake .write = umcast_write,
684ff4d8d3SNolan Leake };
694ff4d8d3SNolan Leake
mcast_setup(char * str,char ** mac_out,void * data)704ff4d8d3SNolan Leake static int mcast_setup(char *str, char **mac_out, void *data)
714ff4d8d3SNolan Leake {
724ff4d8d3SNolan Leake struct umcast_init *init = data;
734ff4d8d3SNolan Leake char *port_str = NULL, *ttl_str = NULL, *remain;
744ff4d8d3SNolan Leake char *last;
754ff4d8d3SNolan Leake
764ff4d8d3SNolan Leake *init = ((struct umcast_init)
774ff4d8d3SNolan Leake { .addr = "239.192.168.1",
784ff4d8d3SNolan Leake .lport = 1102,
794ff4d8d3SNolan Leake .ttl = 1 });
804ff4d8d3SNolan Leake
814ff4d8d3SNolan Leake remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
824ff4d8d3SNolan Leake NULL);
834ff4d8d3SNolan Leake if (remain != NULL) {
844ff4d8d3SNolan Leake printk(KERN_ERR "mcast_setup - Extra garbage on "
854ff4d8d3SNolan Leake "specification : '%s'\n", remain);
864ff4d8d3SNolan Leake return 0;
874ff4d8d3SNolan Leake }
884ff4d8d3SNolan Leake
894ff4d8d3SNolan Leake if (port_str != NULL) {
904ff4d8d3SNolan Leake init->lport = simple_strtoul(port_str, &last, 10);
914ff4d8d3SNolan Leake if ((*last != '\0') || (last == port_str)) {
924ff4d8d3SNolan Leake printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
934ff4d8d3SNolan Leake port_str);
944ff4d8d3SNolan Leake return 0;
954ff4d8d3SNolan Leake }
964ff4d8d3SNolan Leake }
974ff4d8d3SNolan Leake
984ff4d8d3SNolan Leake if (ttl_str != NULL) {
994ff4d8d3SNolan Leake init->ttl = simple_strtoul(ttl_str, &last, 10);
1004ff4d8d3SNolan Leake if ((*last != '\0') || (last == ttl_str)) {
1014ff4d8d3SNolan Leake printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
1024ff4d8d3SNolan Leake ttl_str);
1034ff4d8d3SNolan Leake return 0;
1044ff4d8d3SNolan Leake }
1054ff4d8d3SNolan Leake }
1064ff4d8d3SNolan Leake
1074ff4d8d3SNolan Leake init->unicast = false;
1084ff4d8d3SNolan Leake init->rport = init->lport;
1094ff4d8d3SNolan Leake
1104ff4d8d3SNolan Leake printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
1114ff4d8d3SNolan Leake init->lport, init->ttl);
1124ff4d8d3SNolan Leake
1134ff4d8d3SNolan Leake return 1;
1144ff4d8d3SNolan Leake }
1154ff4d8d3SNolan Leake
ucast_setup(char * str,char ** mac_out,void * data)1164ff4d8d3SNolan Leake static int ucast_setup(char *str, char **mac_out, void *data)
1174ff4d8d3SNolan Leake {
1184ff4d8d3SNolan Leake struct umcast_init *init = data;
1194ff4d8d3SNolan Leake char *lport_str = NULL, *rport_str = NULL, *remain;
1204ff4d8d3SNolan Leake char *last;
1214ff4d8d3SNolan Leake
1224ff4d8d3SNolan Leake *init = ((struct umcast_init)
1234ff4d8d3SNolan Leake { .addr = "",
1244ff4d8d3SNolan Leake .lport = 1102,
1254ff4d8d3SNolan Leake .rport = 1102 });
1264ff4d8d3SNolan Leake
1274ff4d8d3SNolan Leake remain = split_if_spec(str, mac_out, &init->addr,
1284ff4d8d3SNolan Leake &lport_str, &rport_str, NULL);
1294ff4d8d3SNolan Leake if (remain != NULL) {
1304ff4d8d3SNolan Leake printk(KERN_ERR "ucast_setup - Extra garbage on "
1314ff4d8d3SNolan Leake "specification : '%s'\n", remain);
1324ff4d8d3SNolan Leake return 0;
1334ff4d8d3SNolan Leake }
1344ff4d8d3SNolan Leake
1354ff4d8d3SNolan Leake if (lport_str != NULL) {
1364ff4d8d3SNolan Leake init->lport = simple_strtoul(lport_str, &last, 10);
1374ff4d8d3SNolan Leake if ((*last != '\0') || (last == lport_str)) {
1384ff4d8d3SNolan Leake printk(KERN_ERR "ucast_setup - Bad listen port : "
1394ff4d8d3SNolan Leake "'%s'\n", lport_str);
1404ff4d8d3SNolan Leake return 0;
1414ff4d8d3SNolan Leake }
1424ff4d8d3SNolan Leake }
1434ff4d8d3SNolan Leake
1444ff4d8d3SNolan Leake if (rport_str != NULL) {
1454ff4d8d3SNolan Leake init->rport = simple_strtoul(rport_str, &last, 10);
1464ff4d8d3SNolan Leake if ((*last != '\0') || (last == rport_str)) {
1474ff4d8d3SNolan Leake printk(KERN_ERR "ucast_setup - Bad remote port : "
1484ff4d8d3SNolan Leake "'%s'\n", rport_str);
1494ff4d8d3SNolan Leake return 0;
1504ff4d8d3SNolan Leake }
1514ff4d8d3SNolan Leake }
1524ff4d8d3SNolan Leake
1534ff4d8d3SNolan Leake init->unicast = true;
1544ff4d8d3SNolan Leake
1554ff4d8d3SNolan Leake printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
1564ff4d8d3SNolan Leake init->lport, init->addr, init->rport);
1574ff4d8d3SNolan Leake
1584ff4d8d3SNolan Leake return 1;
1594ff4d8d3SNolan Leake }
1604ff4d8d3SNolan Leake
1614ff4d8d3SNolan Leake static struct transport mcast_transport = {
1624ff4d8d3SNolan Leake .list = LIST_HEAD_INIT(mcast_transport.list),
1634ff4d8d3SNolan Leake .name = "mcast",
1644ff4d8d3SNolan Leake .setup = mcast_setup,
1654ff4d8d3SNolan Leake .user = &umcast_user_info,
1664ff4d8d3SNolan Leake .kern = &umcast_kern_info,
1674ff4d8d3SNolan Leake .private_size = sizeof(struct umcast_data),
1684ff4d8d3SNolan Leake .setup_size = sizeof(struct umcast_init),
1694ff4d8d3SNolan Leake };
1704ff4d8d3SNolan Leake
1714ff4d8d3SNolan Leake static struct transport ucast_transport = {
1724ff4d8d3SNolan Leake .list = LIST_HEAD_INIT(ucast_transport.list),
1734ff4d8d3SNolan Leake .name = "ucast",
1744ff4d8d3SNolan Leake .setup = ucast_setup,
1754ff4d8d3SNolan Leake .user = &umcast_user_info,
1764ff4d8d3SNolan Leake .kern = &umcast_kern_info,
1774ff4d8d3SNolan Leake .private_size = sizeof(struct umcast_data),
1784ff4d8d3SNolan Leake .setup_size = sizeof(struct umcast_init),
1794ff4d8d3SNolan Leake };
1804ff4d8d3SNolan Leake
register_umcast(void)1814ff4d8d3SNolan Leake static int register_umcast(void)
1824ff4d8d3SNolan Leake {
1834ff4d8d3SNolan Leake register_transport(&mcast_transport);
1844ff4d8d3SNolan Leake register_transport(&ucast_transport);
1854ff4d8d3SNolan Leake return 0;
1864ff4d8d3SNolan Leake }
1874ff4d8d3SNolan Leake
1884ff4d8d3SNolan Leake late_initcall(register_umcast);
189