1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * user-mode-linux networking multicast transport |
4 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> |
5 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
6 | * |
7 | * based on the existing uml-networking code, which is |
8 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and |
9 | * James Leu (jleu@mindspring.net). |
10 | * Copyright (C) 2001 by various other people who didn't put their name here. |
11 | * |
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, buf: skb->data, len: skb->len, |
60 | pri: (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); |
189 | |