Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/phonet/datagram.c
15111 views
1
/*
2
* File: datagram.c
3
*
4
* Datagram (ISI) Phonet sockets
5
*
6
* Copyright (C) 2008 Nokia Corporation.
7
*
8
* Contact: Remi Denis-Courmont <[email protected]>
9
* Original author: Sakari Ailus <[email protected]>
10
*
11
* This program is free software; you can redistribute it and/or
12
* modify it under the terms of the GNU General Public License
13
* version 2 as published by the Free Software Foundation.
14
*
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23
* 02110-1301 USA
24
*/
25
26
#include <linux/kernel.h>
27
#include <linux/slab.h>
28
#include <linux/socket.h>
29
#include <asm/ioctls.h>
30
#include <net/sock.h>
31
32
#include <linux/phonet.h>
33
#include <net/phonet/phonet.h>
34
35
static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
36
37
/* associated socket ceases to exist */
38
static void pn_sock_close(struct sock *sk, long timeout)
39
{
40
sk_common_release(sk);
41
}
42
43
static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
44
{
45
struct sk_buff *skb;
46
int answ;
47
48
switch (cmd) {
49
case SIOCINQ:
50
lock_sock(sk);
51
skb = skb_peek(&sk->sk_receive_queue);
52
answ = skb ? skb->len : 0;
53
release_sock(sk);
54
return put_user(answ, (int __user *)arg);
55
56
case SIOCPNADDRESOURCE:
57
case SIOCPNDELRESOURCE: {
58
u32 res;
59
if (get_user(res, (u32 __user *)arg))
60
return -EFAULT;
61
if (res >= 256)
62
return -EINVAL;
63
if (cmd == SIOCPNADDRESOURCE)
64
return pn_sock_bind_res(sk, res);
65
else
66
return pn_sock_unbind_res(sk, res);
67
}
68
}
69
70
return -ENOIOCTLCMD;
71
}
72
73
/* Destroy socket. All references are gone. */
74
static void pn_destruct(struct sock *sk)
75
{
76
skb_queue_purge(&sk->sk_receive_queue);
77
}
78
79
static int pn_init(struct sock *sk)
80
{
81
sk->sk_destruct = pn_destruct;
82
return 0;
83
}
84
85
static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
86
struct msghdr *msg, size_t len)
87
{
88
struct sockaddr_pn *target;
89
struct sk_buff *skb;
90
int err;
91
92
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
93
MSG_CMSG_COMPAT))
94
return -EOPNOTSUPP;
95
96
if (msg->msg_name == NULL)
97
return -EDESTADDRREQ;
98
99
if (msg->msg_namelen < sizeof(struct sockaddr_pn))
100
return -EINVAL;
101
102
target = (struct sockaddr_pn *)msg->msg_name;
103
if (target->spn_family != AF_PHONET)
104
return -EAFNOSUPPORT;
105
106
skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
107
msg->msg_flags & MSG_DONTWAIT, &err);
108
if (skb == NULL)
109
return err;
110
skb_reserve(skb, MAX_PHONET_HEADER);
111
112
err = memcpy_fromiovec((void *)skb_put(skb, len), msg->msg_iov, len);
113
if (err < 0) {
114
kfree_skb(skb);
115
return err;
116
}
117
118
/*
119
* Fill in the Phonet header and
120
* finally pass the packet forwards.
121
*/
122
err = pn_skb_send(sk, skb, target);
123
124
/* If ok, return len. */
125
return (err >= 0) ? len : err;
126
}
127
128
static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
129
struct msghdr *msg, size_t len, int noblock,
130
int flags, int *addr_len)
131
{
132
struct sk_buff *skb = NULL;
133
struct sockaddr_pn sa;
134
int rval = -EOPNOTSUPP;
135
int copylen;
136
137
if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
138
MSG_CMSG_COMPAT))
139
goto out_nofree;
140
141
if (addr_len)
142
*addr_len = sizeof(sa);
143
144
skb = skb_recv_datagram(sk, flags, noblock, &rval);
145
if (skb == NULL)
146
goto out_nofree;
147
148
pn_skb_get_src_sockaddr(skb, &sa);
149
150
copylen = skb->len;
151
if (len < copylen) {
152
msg->msg_flags |= MSG_TRUNC;
153
copylen = len;
154
}
155
156
rval = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copylen);
157
if (rval) {
158
rval = -EFAULT;
159
goto out;
160
}
161
162
rval = (flags & MSG_TRUNC) ? skb->len : copylen;
163
164
if (msg->msg_name != NULL)
165
memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn));
166
167
out:
168
skb_free_datagram(sk, skb);
169
170
out_nofree:
171
return rval;
172
}
173
174
/* Queue an skb for a sock. */
175
static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
176
{
177
int err = sock_queue_rcv_skb(sk, skb);
178
179
if (err < 0)
180
kfree_skb(skb);
181
return err ? NET_RX_DROP : NET_RX_SUCCESS;
182
}
183
184
/* Module registration */
185
static struct proto pn_proto = {
186
.close = pn_sock_close,
187
.ioctl = pn_ioctl,
188
.init = pn_init,
189
.sendmsg = pn_sendmsg,
190
.recvmsg = pn_recvmsg,
191
.backlog_rcv = pn_backlog_rcv,
192
.hash = pn_sock_hash,
193
.unhash = pn_sock_unhash,
194
.get_port = pn_sock_get_port,
195
.obj_size = sizeof(struct pn_sock),
196
.owner = THIS_MODULE,
197
.name = "PHONET",
198
};
199
200
static struct phonet_protocol pn_dgram_proto = {
201
.ops = &phonet_dgram_ops,
202
.prot = &pn_proto,
203
.sock_type = SOCK_DGRAM,
204
};
205
206
int __init isi_register(void)
207
{
208
return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
209
}
210
211
void __exit isi_unregister(void)
212
{
213
phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
214
}
215
216