1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
/*
* File: mhi_raw.c
*
* Copyright (C) 2011 Renesas Mobile Corporation. All rights reserved.
*
* Author: Petri Mattila <petri.to.mattila@renesasmobile.com>
*
* RAW socket implementation for MHI protocol family.
*
* It uses the MHI socket framework in mhi_socket.c
*
* This implementation is the most basic frame passing interface.
* The user space can use the sendmsg() and recvmsg() system calls
* to access the frames. The socket is created with the socket()
* system call, e.g. socket(PF_MHI,SOCK_RAW,l2proto).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/mhi.h>
#include <linux/l2mux.h>
#include <asm/ioctls.h>
#include <net/af_mhi.h>
#include <net/mhi/sock.h>
#include <net/mhi/raw.h>
#ifdef CONFIG_MHI_DEBUG
# define DPRINTK(...) printk(KERN_DEBUG "MHI/RAW: " __VA_ARGS__)
#else
# define DPRINTK(...)
#endif
/*** Prototypes ***/
static struct proto mhi_raw_proto;
static void mhi_raw_destruct(struct sock *sk);
/*** Functions ***/
int mhi_raw_sock_create(
struct net *net,
struct socket *sock,
int proto,
int kern)
{
struct sock *sk;
struct mhi_sock *msk;
DPRINTK("mhi_raw_sock_create: proto:%d type:%d\n",
proto, sock->type);
if (sock->type != SOCK_RAW)
return -EPROTONOSUPPORT;
sk = sk_alloc(net, PF_MHI, GFP_KERNEL, &mhi_raw_proto);
if (!sk)
return -ENOMEM;
sock_init_data(sock, sk);
sock->ops = &mhi_socket_ops;
sock->state = SS_UNCONNECTED;
if (proto != MHI_L3_ANY)
sk->sk_protocol = proto;
else
sk->sk_protocol = 0;
sk->sk_destruct = mhi_raw_destruct;
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
sk->sk_prot->init(sk);
msk = mhi_sk(sk);
msk->sk_l3proto = proto;
msk->sk_ifindex = -1;
return 0;
}
static int mhi_raw_init(struct sock *sk)
{
return 0;
}
static void mhi_raw_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_receive_queue);
}
static void mhi_raw_close(struct sock *sk, long timeout)
{
sk_common_release(sk);
}
static int mhi_raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
int err;
DPRINTK("mhi_raw_ioctl: cmd:%d arg:%lu\n", cmd, arg);
switch (cmd) {
case SIOCOUTQ:
{
int len;
len = sk_wmem_alloc_get(sk);
err = put_user(len, (int __user *)arg);
}
break;
case SIOCINQ:
{
struct sk_buff *skb;
int len;
lock_sock(sk);
{
skb = skb_peek(&sk->sk_receive_queue);
len = skb ? skb->len : 0;
}
release_sock(sk);
err = put_user(len, (int __user *)arg);
}
break;
default:
err = -ENOIOCTLCMD;
}
return err;
}
static int mhi_raw_sendmsg(
struct kiocb *iocb,
struct sock *sk,
struct msghdr *msg,
size_t len)
{
struct mhi_sock *msk = mhi_sk(sk);
struct net_device *dev = NULL;
struct sk_buff *skb;
int err = -EFAULT;
if (msg->msg_flags &
~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_CMSG_COMPAT)) {
printk(KERN_WARNING
"mhi_raw_sendmsg: incompatible socket msg_flags: 0x%08X\n",
msg->msg_flags);
err = -EOPNOTSUPP;
goto out;
}
skb = sock_alloc_send_skb(sk,
len,
(msg->msg_flags & MSG_DONTWAIT),
&err);
if (!skb) {
printk(KERN_ERR
"mhi_raw_sendmsg: sock_alloc_send_skb failed: %d\n",
err);
goto out;
}
err = memcpy_fromiovec((void *)skb_put(skb, len), msg->msg_iov, len);
if (err < 0) {
printk(KERN_ERR
"mhi_raw_sendmsg: memcpy_fromiovec failed: %d\n",
err);
goto drop;
}
if (msk->sk_ifindex)
dev = dev_get_by_index(sock_net(sk), msk->sk_ifindex);
if (!dev) {
printk(KERN_ERR
"mhi_raw_sendmsg: no device for ifindex:%d\n",
msk->sk_ifindex);
goto drop;
}
if (!(dev->flags & IFF_UP)) {
printk(KERN_ERR
"mhi_raw_sendmsg: device %d not IFF_UP\n",
msk->sk_ifindex);
err = -ENETDOWN;
goto drop;
}
if (len > dev->mtu) {
err = -EMSGSIZE;
goto drop;
}
skb_reset_network_header(skb);
skb_reset_mac_header(skb);
err = mhi_skb_send(skb, dev, sk->sk_protocol);
goto put;
drop:
kfree(skb);
put:
if (dev)
dev_put(dev);
out:
return err;
}
static int mhi_raw_recvmsg(
struct kiocb *iocb,
struct sock *sk,
struct msghdr *msg,
size_t len,
int noblock,
int flags,
int *addr_len)
{
struct sk_buff *skb = NULL;
int cnt, err;
err = -EOPNOTSUPP;
if (flags &
~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|
MSG_NOSIGNAL|MSG_CMSG_COMPAT)) {
printk(KERN_WARNING
"mhi_raw_recvmsg: incompatible socket flags: 0x%08X",
flags);
goto out2;
}
if (addr_len)
addr_len[0] = 0;
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
goto out2;
cnt = skb->len;
if (len < cnt) {
msg->msg_flags |= MSG_TRUNC;
cnt = len;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, cnt);
if (err)
goto out;
if (flags & MSG_TRUNC)
err = skb->len;
else
err = cnt;
out:
skb_free_datagram(sk, skb);
out2:
return err;
}
static int mhi_raw_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
if (sock_queue_rcv_skb(sk, skb) < 0) {
kfree_skb(skb);
return NET_RX_DROP;
}
return NET_RX_SUCCESS;
}
static struct proto mhi_raw_proto = {
.name = "MHI-RAW",
.owner = THIS_MODULE,
.close = mhi_raw_close,
.ioctl = mhi_raw_ioctl,
.init = mhi_raw_init,
.sendmsg = mhi_raw_sendmsg,
.recvmsg = mhi_raw_recvmsg,
.backlog_rcv = mhi_raw_backlog_rcv,
.hash = mhi_sock_hash,
.unhash = mhi_sock_unhash,
.obj_size = sizeof(struct mhi_sock),
};
int mhi_raw_proto_init(void)
{
DPRINTK("mhi_raw_proto_init\n");
return proto_register(&mhi_raw_proto, 1);
}
void mhi_raw_proto_exit(void)
{
DPRINTK("mhi_raw_proto_exit\n");
proto_unregister(&mhi_raw_proto);
}
|