Blame view

net/phonet/datagram.c 4.08 KB
2b27bdcc2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
2
3
4
5
6
7
8
  /*
   * File: datagram.c
   *
   * Datagram (ISI) Phonet sockets
   *
   * Copyright (C) 2008 Nokia Corporation.
   *
31fdc5553   Rémi Denis-Courmont   net: remove my fu...
9
10
   * Authors: Sakari Ailus <sakari.ailus@nokia.com>
   *          Rémi Denis-Courmont
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
11
12
13
   */
  
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
15
16
17
18
19
  #include <linux/socket.h>
  #include <asm/ioctls.h>
  #include <net/sock.h>
  
  #include <linux/phonet.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
20
  #include <linux/export.h>
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  #include <net/phonet/phonet.h>
  
  static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
  
  /* associated socket ceases to exist */
  static void pn_sock_close(struct sock *sk, long timeout)
  {
  	sk_common_release(sk);
  }
  
  static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
  	struct sk_buff *skb;
  	int answ;
  
  	switch (cmd) {
  	case SIOCINQ:
  		lock_sock(sk);
  		skb = skb_peek(&sk->sk_receive_queue);
  		answ = skb ? skb->len : 0;
  		release_sock(sk);
  		return put_user(answ, (int __user *)arg);
7417fa83c   Rémi Denis-Courmont   Phonet: hook reso...
43
44
45
46
47
48
49
50
51
52
53
54
55
  
  	case SIOCPNADDRESOURCE:
  	case SIOCPNDELRESOURCE: {
  			u32 res;
  			if (get_user(res, (u32 __user *)arg))
  				return -EFAULT;
  			if (res >= 256)
  				return -EINVAL;
  			if (cmd == SIOCPNADDRESOURCE)
  				return pn_sock_bind_res(sk, res);
  			else
  				return pn_sock_unbind_res(sk, res);
  		}
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  	}
  
  	return -ENOIOCTLCMD;
  }
  
  /* Destroy socket. All references are gone. */
  static void pn_destruct(struct sock *sk)
  {
  	skb_queue_purge(&sk->sk_receive_queue);
  }
  
  static int pn_init(struct sock *sk)
  {
  	sk->sk_destruct = pn_destruct;
  	return 0;
  }
1b7841404   Ying Xue   net: Remove iocb ...
72
  static int pn_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
73
  {
342dfc306   Steffen Hurrle   net: add build-ti...
74
  	DECLARE_SOCKADDR(struct sockaddr_pn *, target, msg->msg_name);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
75
76
  	struct sk_buff *skb;
  	int err;
82ecbcb9c   Rémi Denis-Courmont   Phonet: reject un...
77
78
  	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
  				MSG_CMSG_COMPAT))
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
79
  		return -EOPNOTSUPP;
342dfc306   Steffen Hurrle   net: add build-ti...
80
  	if (target == NULL)
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
81
82
83
84
  		return -EDESTADDRREQ;
  
  	if (msg->msg_namelen < sizeof(struct sockaddr_pn))
  		return -EINVAL;
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
85
86
87
88
89
90
91
92
  	if (target->spn_family != AF_PHONET)
  		return -EAFNOSUPPORT;
  
  	skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
  					msg->msg_flags & MSG_DONTWAIT, &err);
  	if (skb == NULL)
  		return err;
  	skb_reserve(skb, MAX_PHONET_HEADER);
6ce8e9ce5   Al Viro   new helper: memcp...
93
  	err = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	if (err < 0) {
  		kfree_skb(skb);
  		return err;
  	}
  
  	/*
  	 * Fill in the Phonet header and
  	 * finally pass the packet forwards.
  	 */
  	err = pn_skb_send(sk, skb, target);
  
  	/* If ok, return len. */
  	return (err >= 0) ? len : err;
  }
1b7841404   Ying Xue   net: Remove iocb ...
108
109
  static int pn_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
  		      int noblock, int flags, int *addr_len)
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
110
111
112
113
114
  {
  	struct sk_buff *skb = NULL;
  	struct sockaddr_pn sa;
  	int rval = -EOPNOTSUPP;
  	int copylen;
82ecbcb9c   Rémi Denis-Courmont   Phonet: reject un...
115
116
  	if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
  			MSG_CMSG_COMPAT))
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
117
  		goto out_nofree;
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
118
119
120
121
122
123
124
125
126
127
128
  	skb = skb_recv_datagram(sk, flags, noblock, &rval);
  	if (skb == NULL)
  		goto out_nofree;
  
  	pn_skb_get_src_sockaddr(skb, &sa);
  
  	copylen = skb->len;
  	if (len < copylen) {
  		msg->msg_flags |= MSG_TRUNC;
  		copylen = len;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
129
  	rval = skb_copy_datagram_msg(skb, 0, msg, copylen);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
130
131
132
133
134
135
  	if (rval) {
  		rval = -EFAULT;
  		goto out;
  	}
  
  	rval = (flags & MSG_TRUNC) ? skb->len : copylen;
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
136
  	if (msg->msg_name != NULL) {
342dfc306   Steffen Hurrle   net: add build-ti...
137
  		__sockaddr_check_size(sizeof(sa));
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
138
139
140
  		memcpy(msg->msg_name, &sa, sizeof(sa));
  		*addr_len = sizeof(sa);
  	}
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
141
142
143
144
145
146
147
148
149
150
151
152
  
  out:
  	skb_free_datagram(sk, skb);
  
  out_nofree:
  	return rval;
  }
  
  /* Queue an skb for a sock. */
  static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
  {
  	int err = sock_queue_rcv_skb(sk, skb);
766e9037c   Eric Dumazet   net: sk_drops con...
153
154
  
  	if (err < 0)
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  		kfree_skb(skb);
  	return err ? NET_RX_DROP : NET_RX_SUCCESS;
  }
  
  /* Module registration */
  static struct proto pn_proto = {
  	.close		= pn_sock_close,
  	.ioctl		= pn_ioctl,
  	.init		= pn_init,
  	.sendmsg	= pn_sendmsg,
  	.recvmsg	= pn_recvmsg,
  	.backlog_rcv	= pn_backlog_rcv,
  	.hash		= pn_sock_hash,
  	.unhash		= pn_sock_unhash,
  	.get_port	= pn_sock_get_port,
  	.obj_size	= sizeof(struct pn_sock),
  	.owner		= THIS_MODULE,
  	.name		= "PHONET",
  };
548ec1147   Lin Zhang   net: phonet: mark...
174
  static const struct phonet_protocol pn_dgram_proto = {
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  	.ops		= &phonet_dgram_ops,
  	.prot		= &pn_proto,
  	.sock_type	= SOCK_DGRAM,
  };
  
  int __init isi_register(void)
  {
  	return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
  }
  
  void __exit isi_unregister(void)
  {
  	phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
  }