Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/drivers/umcast_user.c
10817 views
1
/*
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 <[email protected]>
5
*
6
* based on the existing uml-networking code, which is
7
* Copyright (C) 2001 Lennert Buytenhek ([email protected]) and
8
* James Leu ([email protected]).
9
* Copyright (C) 2001 by various other people who didn't put their name here.
10
*
11
* Licensed under the GPL.
12
*
13
*/
14
15
#include <unistd.h>
16
#include <errno.h>
17
#include <netinet/in.h>
18
#include "kern_constants.h"
19
#include "umcast.h"
20
#include "net_user.h"
21
#include "um_malloc.h"
22
#include "user.h"
23
24
static struct sockaddr_in *new_addr(char *addr, unsigned short port)
25
{
26
struct sockaddr_in *sin;
27
28
sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
29
if (sin == NULL) {
30
printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
31
"failed\n");
32
return NULL;
33
}
34
sin->sin_family = AF_INET;
35
if (addr)
36
sin->sin_addr.s_addr = in_aton(addr);
37
else
38
sin->sin_addr.s_addr = INADDR_ANY;
39
sin->sin_port = htons(port);
40
return sin;
41
}
42
43
static int umcast_user_init(void *data, void *dev)
44
{
45
struct umcast_data *pri = data;
46
47
pri->remote_addr = new_addr(pri->addr, pri->rport);
48
if (pri->unicast)
49
pri->listen_addr = new_addr(NULL, pri->lport);
50
else
51
pri->listen_addr = pri->remote_addr;
52
pri->dev = dev;
53
return 0;
54
}
55
56
static void umcast_remove(void *data)
57
{
58
struct umcast_data *pri = data;
59
60
kfree(pri->listen_addr);
61
if (pri->unicast)
62
kfree(pri->remote_addr);
63
pri->listen_addr = pri->remote_addr = NULL;
64
}
65
66
static int umcast_open(void *data)
67
{
68
struct umcast_data *pri = data;
69
struct sockaddr_in *lsin = pri->listen_addr;
70
struct sockaddr_in *rsin = pri->remote_addr;
71
struct ip_mreq mreq;
72
int fd, yes = 1, err = -EINVAL;
73
74
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))
78
goto out;
79
80
fd = socket(AF_INET, SOCK_DGRAM, 0);
81
82
if (fd < 0) {
83
err = -errno;
84
printk(UM_KERN_ERR "umcast_open : data socket failed, "
85
"errno = %d\n", errno);
86
goto out;
87
}
88
89
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
90
err = -errno;
91
printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
92
"errno = %d\n", errno);
93
goto out_close;
94
}
95
96
if (!pri->unicast) {
97
/* set ttl according to config */
98
if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
99
sizeof(pri->ttl)) < 0) {
100
err = -errno;
101
printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
102
"failed, error = %d\n", errno);
103
goto out_close;
104
}
105
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) {
109
err = -errno;
110
printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
111
"failed, error = %d\n", errno);
112
goto out_close;
113
}
114
}
115
116
/* bind socket to the address */
117
if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
118
err = -errno;
119
printk(UM_KERN_ERR "umcast_open : data bind failed, "
120
"errno = %d\n", errno);
121
goto out_close;
122
}
123
124
if (!pri->unicast) {
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) {
130
err = -errno;
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 "
135
"host.\n");
136
printk(UM_KERN_ERR "eth0 should be configured in order "
137
"to use the multicast transport.\n");
138
goto out_close;
139
}
140
}
141
142
return fd;
143
144
out_close:
145
close(fd);
146
out:
147
return err;
148
}
149
150
static void umcast_close(int fd, void *data)
151
{
152
struct umcast_data *pri = data;
153
154
if (!pri->unicast) {
155
struct ip_mreq mreq;
156
struct sockaddr_in *lsin = pri->listen_addr;
157
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);
164
}
165
}
166
167
close(fd);
168
}
169
170
int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
171
{
172
struct sockaddr_in *data_addr = pri->remote_addr;
173
174
return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
175
}
176
177
const struct net_user_info umcast_user_info = {
178
.init = umcast_user_init,
179
.open = umcast_open,
180
.close = umcast_close,
181
.remove = umcast_remove,
182
.add_address = NULL,
183
.delete_address = NULL,
184
.mtu = ETH_MAX_PACKET,
185
.max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER,
186
};
187
188