2 * user-mode-linux networking multicast transport
3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
6 * based on the existing uml-networking code, which is
7 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
8 * James Leu (jleu@mindspring.net).
9 * Copyright (C) 2001 by various other people who didn't put their name here.
11 * Licensed under the GPL.
17 #include <netinet/in.h>
18 #include "kern_constants.h"
21 #include "um_malloc.h"
24 static struct sockaddr_in
*new_addr(char *addr
, unsigned short port
)
26 struct sockaddr_in
*sin
;
28 sin
= uml_kmalloc(sizeof(struct sockaddr_in
), UM_GFP_KERNEL
);
30 printk(UM_KERN_ERR
"new_addr: allocation of sockaddr_in "
34 sin
->sin_family
= AF_INET
;
36 sin
->sin_addr
.s_addr
= in_aton(addr
);
38 sin
->sin_addr
.s_addr
= INADDR_ANY
;
39 sin
->sin_port
= htons(port
);
43 static int umcast_user_init(void *data
, void *dev
)
45 struct umcast_data
*pri
= data
;
47 pri
->remote_addr
= new_addr(pri
->addr
, pri
->rport
);
49 pri
->listen_addr
= new_addr(NULL
, pri
->lport
);
51 pri
->listen_addr
= pri
->remote_addr
;
56 static void umcast_remove(void *data
)
58 struct umcast_data
*pri
= data
;
60 kfree(pri
->listen_addr
);
62 kfree(pri
->remote_addr
);
63 pri
->listen_addr
= pri
->remote_addr
= NULL
;
66 static int umcast_open(void *data
)
68 struct umcast_data
*pri
= data
;
69 struct sockaddr_in
*lsin
= pri
->listen_addr
;
70 struct sockaddr_in
*rsin
= pri
->remote_addr
;
72 int fd
, yes
= 1, err
= -EINVAL
;
75 if ((!pri
->unicast
&& lsin
->sin_addr
.s_addr
== 0) ||
76 (rsin
->sin_addr
.s_addr
== 0) ||
77 (lsin
->sin_port
== 0) || (rsin
->sin_port
== 0))
80 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
84 printk(UM_KERN_ERR
"umcast_open : data socket failed, "
85 "errno = %d\n", errno
);
89 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) < 0) {
91 printk(UM_KERN_ERR
"umcast_open: SO_REUSEADDR failed, "
92 "errno = %d\n", errno
);
97 /* set ttl according to config */
98 if (setsockopt(fd
, SOL_IP
, IP_MULTICAST_TTL
, &pri
->ttl
,
99 sizeof(pri
->ttl
)) < 0) {
101 printk(UM_KERN_ERR
"umcast_open: IP_MULTICAST_TTL "
102 "failed, error = %d\n", errno
);
106 /* set LOOP, so data does get fed back to local sockets */
107 if (setsockopt(fd
, SOL_IP
, IP_MULTICAST_LOOP
,
108 &yes
, sizeof(yes
)) < 0) {
110 printk(UM_KERN_ERR
"umcast_open: IP_MULTICAST_LOOP "
111 "failed, error = %d\n", errno
);
116 /* bind socket to the address */
117 if (bind(fd
, (struct sockaddr
*) lsin
, sizeof(*lsin
)) < 0) {
119 printk(UM_KERN_ERR
"umcast_open : data bind failed, "
120 "errno = %d\n", errno
);
125 /* subscribe to the multicast group */
126 mreq
.imr_multiaddr
.s_addr
= lsin
->sin_addr
.s_addr
;
127 mreq
.imr_interface
.s_addr
= 0;
128 if (setsockopt(fd
, SOL_IP
, IP_ADD_MEMBERSHIP
,
129 &mreq
, sizeof(mreq
)) < 0) {
131 printk(UM_KERN_ERR
"umcast_open: IP_ADD_MEMBERSHIP "
132 "failed, error = %d\n", errno
);
133 printk(UM_KERN_ERR
"There appears not to be a "
134 "multicast-capable network interface on the "
136 printk(UM_KERN_ERR
"eth0 should be configured in order "
137 "to use the multicast transport.\n");
150 static void umcast_close(int fd
, void *data
)
152 struct umcast_data
*pri
= data
;
156 struct sockaddr_in
*lsin
= pri
->listen_addr
;
158 mreq
.imr_multiaddr
.s_addr
= lsin
->sin_addr
.s_addr
;
159 mreq
.imr_interface
.s_addr
= 0;
160 if (setsockopt(fd
, SOL_IP
, IP_DROP_MEMBERSHIP
,
161 &mreq
, sizeof(mreq
)) < 0) {
162 printk(UM_KERN_ERR
"umcast_close: IP_DROP_MEMBERSHIP "
163 "failed, error = %d\n", errno
);
170 int umcast_user_write(int fd
, void *buf
, int len
, struct umcast_data
*pri
)
172 struct sockaddr_in
*data_addr
= pri
->remote_addr
;
174 return net_sendto(fd
, buf
, len
, data_addr
, sizeof(*data_addr
));
177 const struct net_user_info umcast_user_info
= {
178 .init
= umcast_user_init
,
180 .close
= umcast_close
,
181 .remove
= umcast_remove
,
183 .delete_address
= NULL
,
184 .mtu
= ETH_MAX_PACKET
,
185 .max_packet
= ETH_MAX_PACKET
+ ETH_HEADER_OTHER
,