1 // SPDX-License-Identifier: GPL-2.0
3 * user-mode-linux networking multicast transport
4 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
5 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
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.
17 #include <netinet/in.h>
20 #include <um_malloc.h>
22 static struct sockaddr_in
*new_addr(char *addr
, unsigned short port
)
24 struct sockaddr_in
*sin
;
26 sin
= uml_kmalloc(sizeof(struct sockaddr_in
), UM_GFP_KERNEL
);
28 printk(UM_KERN_ERR
"new_addr: allocation of sockaddr_in "
32 sin
->sin_family
= AF_INET
;
34 sin
->sin_addr
.s_addr
= in_aton(addr
);
36 sin
->sin_addr
.s_addr
= INADDR_ANY
;
37 sin
->sin_port
= htons(port
);
41 static int umcast_user_init(void *data
, void *dev
)
43 struct umcast_data
*pri
= data
;
45 pri
->remote_addr
= new_addr(pri
->addr
, pri
->rport
);
47 pri
->listen_addr
= new_addr(NULL
, pri
->lport
);
49 pri
->listen_addr
= pri
->remote_addr
;
54 static void umcast_remove(void *data
)
56 struct umcast_data
*pri
= data
;
58 kfree(pri
->listen_addr
);
60 kfree(pri
->remote_addr
);
61 pri
->listen_addr
= pri
->remote_addr
= NULL
;
64 static int umcast_open(void *data
)
66 struct umcast_data
*pri
= data
;
67 struct sockaddr_in
*lsin
= pri
->listen_addr
;
68 struct sockaddr_in
*rsin
= pri
->remote_addr
;
70 int fd
, yes
= 1, err
= -EINVAL
;
73 if ((!pri
->unicast
&& lsin
->sin_addr
.s_addr
== 0) ||
74 (rsin
->sin_addr
.s_addr
== 0) ||
75 (lsin
->sin_port
== 0) || (rsin
->sin_port
== 0))
78 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
82 printk(UM_KERN_ERR
"umcast_open : data socket failed, "
83 "errno = %d\n", errno
);
87 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) < 0) {
89 printk(UM_KERN_ERR
"umcast_open: SO_REUSEADDR failed, "
90 "errno = %d\n", errno
);
95 /* set ttl according to config */
96 if (setsockopt(fd
, SOL_IP
, IP_MULTICAST_TTL
, &pri
->ttl
,
97 sizeof(pri
->ttl
)) < 0) {
99 printk(UM_KERN_ERR
"umcast_open: IP_MULTICAST_TTL "
100 "failed, error = %d\n", errno
);
104 /* set LOOP, so data does get fed back to local sockets */
105 if (setsockopt(fd
, SOL_IP
, IP_MULTICAST_LOOP
,
106 &yes
, sizeof(yes
)) < 0) {
108 printk(UM_KERN_ERR
"umcast_open: IP_MULTICAST_LOOP "
109 "failed, error = %d\n", errno
);
114 /* bind socket to the address */
115 if (bind(fd
, (struct sockaddr
*) lsin
, sizeof(*lsin
)) < 0) {
117 printk(UM_KERN_ERR
"umcast_open : data bind failed, "
118 "errno = %d\n", errno
);
123 /* subscribe to the multicast group */
124 mreq
.imr_multiaddr
.s_addr
= lsin
->sin_addr
.s_addr
;
125 mreq
.imr_interface
.s_addr
= 0;
126 if (setsockopt(fd
, SOL_IP
, IP_ADD_MEMBERSHIP
,
127 &mreq
, sizeof(mreq
)) < 0) {
129 printk(UM_KERN_ERR
"umcast_open: IP_ADD_MEMBERSHIP "
130 "failed, error = %d\n", errno
);
131 printk(UM_KERN_ERR
"There appears not to be a "
132 "multicast-capable network interface on the "
134 printk(UM_KERN_ERR
"eth0 should be configured in order "
135 "to use the multicast transport.\n");
148 static void umcast_close(int fd
, void *data
)
150 struct umcast_data
*pri
= data
;
154 struct sockaddr_in
*lsin
= pri
->listen_addr
;
156 mreq
.imr_multiaddr
.s_addr
= lsin
->sin_addr
.s_addr
;
157 mreq
.imr_interface
.s_addr
= 0;
158 if (setsockopt(fd
, SOL_IP
, IP_DROP_MEMBERSHIP
,
159 &mreq
, sizeof(mreq
)) < 0) {
160 printk(UM_KERN_ERR
"umcast_close: IP_DROP_MEMBERSHIP "
161 "failed, error = %d\n", errno
);
168 int umcast_user_write(int fd
, void *buf
, int len
, struct umcast_data
*pri
)
170 struct sockaddr_in
*data_addr
= pri
->remote_addr
;
172 return net_sendto(fd
, buf
, len
, data_addr
, sizeof(*data_addr
));
175 const struct net_user_info umcast_user_info
= {
176 .init
= umcast_user_init
,
178 .close
= umcast_close
,
179 .remove
= umcast_remove
,
181 .delete_address
= NULL
,
182 .mtu
= ETH_MAX_PACKET
,
183 .max_packet
= ETH_MAX_PACKET
+ ETH_HEADER_OTHER
,