1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e6f95ec8SSjur Braendeland /*
3e6f95ec8SSjur Braendeland * Copyright (C) ST-Ericsson AB 2010
426ee65e6Ssjur.brandeland@stericsson.com * Author: Sjur Brendeland
5e6f95ec8SSjur Braendeland */
6e6f95ec8SSjur Braendeland
7b31fa5baSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
8b31fa5baSJoe Perches
9b6459415SJakub Kicinski #include <linux/filter.h>
10e6f95ec8SSjur Braendeland #include <linux/fs.h>
11e6f95ec8SSjur Braendeland #include <linux/init.h>
12e6f95ec8SSjur Braendeland #include <linux/module.h>
133f07c014SIngo Molnar #include <linux/sched/signal.h>
14e6f95ec8SSjur Braendeland #include <linux/spinlock.h>
15e6f95ec8SSjur Braendeland #include <linux/mutex.h>
16e6f95ec8SSjur Braendeland #include <linux/list.h>
17e6f95ec8SSjur Braendeland #include <linux/wait.h>
18e6f95ec8SSjur Braendeland #include <linux/poll.h>
19e6f95ec8SSjur Braendeland #include <linux/tcp.h>
20e6f95ec8SSjur Braendeland #include <linux/uaccess.h>
21bece7b23SSjur Braendeland #include <linux/debugfs.h>
22e6f95ec8SSjur Braendeland #include <linux/caif/caif_socket.h>
2344764812SDmitry Tarnyagin #include <linux/pkt_sched.h>
24bece7b23SSjur Braendeland #include <net/sock.h>
25bece7b23SSjur Braendeland #include <net/tcp_states.h>
26e6f95ec8SSjur Braendeland #include <net/caif/caif_layer.h>
27e6f95ec8SSjur Braendeland #include <net/caif/caif_dev.h>
28e6f95ec8SSjur Braendeland #include <net/caif/cfpkt.h>
29e6f95ec8SSjur Braendeland
30e6f95ec8SSjur Braendeland MODULE_LICENSE("GPL");
31bece7b23SSjur Braendeland MODULE_ALIAS_NETPROTO(AF_CAIF);
32e6f95ec8SSjur Braendeland
33bece7b23SSjur Braendeland /*
34bece7b23SSjur Braendeland * CAIF state is re-using the TCP socket states.
35bece7b23SSjur Braendeland * caif_states stored in sk_state reflect the state as reported by
36bece7b23SSjur Braendeland * the CAIF stack, while sk_socket->state is the state of the socket.
37bece7b23SSjur Braendeland */
38bece7b23SSjur Braendeland enum caif_states {
39bece7b23SSjur Braendeland CAIF_CONNECTED = TCP_ESTABLISHED,
40bece7b23SSjur Braendeland CAIF_CONNECTING = TCP_SYN_SENT,
41bece7b23SSjur Braendeland CAIF_DISCONNECTED = TCP_CLOSE
42bece7b23SSjur Braendeland };
43e6f95ec8SSjur Braendeland
44e6f95ec8SSjur Braendeland #define TX_FLOW_ON_BIT 1
45e6f95ec8SSjur Braendeland #define RX_FLOW_ON_BIT 2
46e6f95ec8SSjur Braendeland
47e6f95ec8SSjur Braendeland struct caifsock {
48bece7b23SSjur Braendeland struct sock sk; /* must be first member */
49e6f95ec8SSjur Braendeland struct cflayer layer;
508ee18e2aSChristophe JAILLET unsigned long flow_state;
51e6f95ec8SSjur Braendeland struct caif_connect_request conn_req;
52bece7b23SSjur Braendeland struct mutex readlock;
53e6f95ec8SSjur Braendeland struct dentry *debugfs_socket_dir;
542aa40aefSSjur Braendeland int headroom, tailroom, maxframe;
55e6f95ec8SSjur Braendeland };
56e6f95ec8SSjur Braendeland
rx_flow_is_on(struct caifsock * cf_sk)57bece7b23SSjur Braendeland static int rx_flow_is_on(struct caifsock *cf_sk)
58bece7b23SSjur Braendeland {
598ee18e2aSChristophe JAILLET return test_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
60bece7b23SSjur Braendeland }
61bece7b23SSjur Braendeland
tx_flow_is_on(struct caifsock * cf_sk)62bece7b23SSjur Braendeland static int tx_flow_is_on(struct caifsock *cf_sk)
63bece7b23SSjur Braendeland {
648ee18e2aSChristophe JAILLET return test_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
65bece7b23SSjur Braendeland }
66bece7b23SSjur Braendeland
set_rx_flow_off(struct caifsock * cf_sk)67bece7b23SSjur Braendeland static void set_rx_flow_off(struct caifsock *cf_sk)
68bece7b23SSjur Braendeland {
698ee18e2aSChristophe JAILLET clear_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
70bece7b23SSjur Braendeland }
71bece7b23SSjur Braendeland
set_rx_flow_on(struct caifsock * cf_sk)72bece7b23SSjur Braendeland static void set_rx_flow_on(struct caifsock *cf_sk)
73bece7b23SSjur Braendeland {
748ee18e2aSChristophe JAILLET set_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
75bece7b23SSjur Braendeland }
76bece7b23SSjur Braendeland
set_tx_flow_off(struct caifsock * cf_sk)77bece7b23SSjur Braendeland static void set_tx_flow_off(struct caifsock *cf_sk)
78bece7b23SSjur Braendeland {
798ee18e2aSChristophe JAILLET clear_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
80bece7b23SSjur Braendeland }
81bece7b23SSjur Braendeland
set_tx_flow_on(struct caifsock * cf_sk)82bece7b23SSjur Braendeland static void set_tx_flow_on(struct caifsock *cf_sk)
83bece7b23SSjur Braendeland {
848ee18e2aSChristophe JAILLET set_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
85bece7b23SSjur Braendeland }
86bece7b23SSjur Braendeland
caif_read_lock(struct sock * sk)87bece7b23SSjur Braendeland static void caif_read_lock(struct sock *sk)
88bece7b23SSjur Braendeland {
89bece7b23SSjur Braendeland struct caifsock *cf_sk;
90bece7b23SSjur Braendeland cf_sk = container_of(sk, struct caifsock, sk);
91bece7b23SSjur Braendeland mutex_lock(&cf_sk->readlock);
92bece7b23SSjur Braendeland }
93bece7b23SSjur Braendeland
caif_read_unlock(struct sock * sk)94bece7b23SSjur Braendeland static void caif_read_unlock(struct sock *sk)
95bece7b23SSjur Braendeland {
96bece7b23SSjur Braendeland struct caifsock *cf_sk;
97bece7b23SSjur Braendeland cf_sk = container_of(sk, struct caifsock, sk);
98bece7b23SSjur Braendeland mutex_unlock(&cf_sk->readlock);
99bece7b23SSjur Braendeland }
100bece7b23SSjur Braendeland
sk_rcvbuf_lowwater(struct caifsock * cf_sk)101a9a8f107SSjur Braendeland static int sk_rcvbuf_lowwater(struct caifsock *cf_sk)
102bece7b23SSjur Braendeland {
103bece7b23SSjur Braendeland /* A quarter of full buffer is used a low water mark */
104bece7b23SSjur Braendeland return cf_sk->sk.sk_rcvbuf / 4;
105bece7b23SSjur Braendeland }
106bece7b23SSjur Braendeland
caif_flow_ctrl(struct sock * sk,int mode)107a9a8f107SSjur Braendeland static void caif_flow_ctrl(struct sock *sk, int mode)
108bece7b23SSjur Braendeland {
109bece7b23SSjur Braendeland struct caifsock *cf_sk;
110bece7b23SSjur Braendeland cf_sk = container_of(sk, struct caifsock, sk);
111ca6a09f2SSjur Braendeland if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd)
112bece7b23SSjur Braendeland cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode);
113bece7b23SSjur Braendeland }
114bece7b23SSjur Braendeland
115bece7b23SSjur Braendeland /*
116bece7b23SSjur Braendeland * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
117bece7b23SSjur Braendeland * not dropped, but CAIF is sending flow off instead.
118bece7b23SSjur Braendeland */
caif_queue_rcv_skb(struct sock * sk,struct sk_buff * skb)119b8a23e8dSEric Dumazet static void caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
120bece7b23SSjur Braendeland {
121bece7b23SSjur Braendeland int err;
122bece7b23SSjur Braendeland unsigned long flags;
123bece7b23SSjur Braendeland struct sk_buff_head *list = &sk->sk_receive_queue;
124bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
125b8a23e8dSEric Dumazet bool queued = false;
126bece7b23SSjur Braendeland
127bece7b23SSjur Braendeland if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
12895c96174SEric Dumazet (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
129e87cc472SJoe Perches net_dbg_ratelimited("sending flow OFF (queue len = %d %d)\n",
130bece7b23SSjur Braendeland atomic_read(&cf_sk->sk.sk_rmem_alloc),
131bece7b23SSjur Braendeland sk_rcvbuf_lowwater(cf_sk));
132bece7b23SSjur Braendeland set_rx_flow_off(cf_sk);
133ca6a09f2SSjur Braendeland caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
134bece7b23SSjur Braendeland }
135bece7b23SSjur Braendeland
136bece7b23SSjur Braendeland err = sk_filter(sk, skb);
137bece7b23SSjur Braendeland if (err)
138b8a23e8dSEric Dumazet goto out;
139b8a23e8dSEric Dumazet
140c76562b6SMel Gorman if (!sk_rmem_schedule(sk, skb, skb->truesize) && rx_flow_is_on(cf_sk)) {
141bece7b23SSjur Braendeland set_rx_flow_off(cf_sk);
142e87cc472SJoe Perches net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n");
143ca6a09f2SSjur Braendeland caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
144bece7b23SSjur Braendeland }
145bece7b23SSjur Braendeland skb->dev = NULL;
146bece7b23SSjur Braendeland skb_set_owner_r(skb, sk);
147bece7b23SSjur Braendeland spin_lock_irqsave(&list->lock, flags);
148b8a23e8dSEric Dumazet queued = !sock_flag(sk, SOCK_DEAD);
149b8a23e8dSEric Dumazet if (queued)
150bece7b23SSjur Braendeland __skb_queue_tail(list, skb);
151bece7b23SSjur Braendeland spin_unlock_irqrestore(&list->lock, flags);
152b8a23e8dSEric Dumazet out:
153b8a23e8dSEric Dumazet if (queued)
154676d2369SDavid S. Miller sk->sk_data_ready(sk);
155bece7b23SSjur Braendeland else
156bece7b23SSjur Braendeland kfree_skb(skb);
157bece7b23SSjur Braendeland }
158e6f95ec8SSjur Braendeland
159e6f95ec8SSjur Braendeland /* Packet Receive Callback function called from CAIF Stack */
caif_sktrecv_cb(struct cflayer * layr,struct cfpkt * pkt)160e6f95ec8SSjur Braendeland static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt)
161e6f95ec8SSjur Braendeland {
162e6f95ec8SSjur Braendeland struct caifsock *cf_sk;
163bece7b23SSjur Braendeland struct sk_buff *skb;
164e6f95ec8SSjur Braendeland
165bece7b23SSjur Braendeland cf_sk = container_of(layr, struct caifsock, layer);
166bece7b23SSjur Braendeland skb = cfpkt_tonative(pkt);
167bece7b23SSjur Braendeland
168bece7b23SSjur Braendeland if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) {
1693f874adcSsjur.brandeland@stericsson.com kfree_skb(skb);
170e6f95ec8SSjur Braendeland return 0;
171e6f95ec8SSjur Braendeland }
172bece7b23SSjur Braendeland caif_queue_rcv_skb(&cf_sk->sk, skb);
173e6f95ec8SSjur Braendeland return 0;
174e6f95ec8SSjur Braendeland }
175e6f95ec8SSjur Braendeland
cfsk_hold(struct cflayer * layr)176b3ccfbe4Ssjur.brandeland@stericsson.com static void cfsk_hold(struct cflayer *layr)
177b3ccfbe4Ssjur.brandeland@stericsson.com {
178b3ccfbe4Ssjur.brandeland@stericsson.com struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
179b3ccfbe4Ssjur.brandeland@stericsson.com sock_hold(&cf_sk->sk);
180b3ccfbe4Ssjur.brandeland@stericsson.com }
181b3ccfbe4Ssjur.brandeland@stericsson.com
cfsk_put(struct cflayer * layr)182b3ccfbe4Ssjur.brandeland@stericsson.com static void cfsk_put(struct cflayer *layr)
183b3ccfbe4Ssjur.brandeland@stericsson.com {
184b3ccfbe4Ssjur.brandeland@stericsson.com struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
185b3ccfbe4Ssjur.brandeland@stericsson.com sock_put(&cf_sk->sk);
186b3ccfbe4Ssjur.brandeland@stericsson.com }
187b3ccfbe4Ssjur.brandeland@stericsson.com
188bece7b23SSjur Braendeland /* Packet Control Callback function called from CAIF */
caif_ctrl_cb(struct cflayer * layr,enum caif_ctrlcmd flow,int phyid)189bece7b23SSjur Braendeland static void caif_ctrl_cb(struct cflayer *layr,
190e6f95ec8SSjur Braendeland enum caif_ctrlcmd flow,
191e6f95ec8SSjur Braendeland int phyid)
192e6f95ec8SSjur Braendeland {
193bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
194e6f95ec8SSjur Braendeland switch (flow) {
195e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_FLOW_ON_IND:
196bece7b23SSjur Braendeland /* OK from modem to start sending again */
197bece7b23SSjur Braendeland set_tx_flow_on(cf_sk);
198bece7b23SSjur Braendeland cf_sk->sk.sk_state_change(&cf_sk->sk);
199e6f95ec8SSjur Braendeland break;
200e6f95ec8SSjur Braendeland
201e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_FLOW_OFF_IND:
202bece7b23SSjur Braendeland /* Modem asks us to shut up */
203bece7b23SSjur Braendeland set_tx_flow_off(cf_sk);
204bece7b23SSjur Braendeland cf_sk->sk.sk_state_change(&cf_sk->sk);
205e6f95ec8SSjur Braendeland break;
206e6f95ec8SSjur Braendeland
207e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_INIT_RSP:
208bece7b23SSjur Braendeland /* We're now connected */
209b3ccfbe4Ssjur.brandeland@stericsson.com caif_client_register_refcnt(&cf_sk->layer,
210b3ccfbe4Ssjur.brandeland@stericsson.com cfsk_hold, cfsk_put);
211bece7b23SSjur Braendeland cf_sk->sk.sk_state = CAIF_CONNECTED;
212bece7b23SSjur Braendeland set_tx_flow_on(cf_sk);
213eaa8c5f3SSjur Brændeland cf_sk->sk.sk_shutdown = 0;
214bece7b23SSjur Braendeland cf_sk->sk.sk_state_change(&cf_sk->sk);
215e6f95ec8SSjur Braendeland break;
216e6f95ec8SSjur Braendeland
217e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_DEINIT_RSP:
218bece7b23SSjur Braendeland /* We're now disconnected */
219bece7b23SSjur Braendeland cf_sk->sk.sk_state = CAIF_DISCONNECTED;
220bece7b23SSjur Braendeland cf_sk->sk.sk_state_change(&cf_sk->sk);
221e6f95ec8SSjur Braendeland break;
222e6f95ec8SSjur Braendeland
223e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_INIT_FAIL_RSP:
224bece7b23SSjur Braendeland /* Connect request failed */
225bece7b23SSjur Braendeland cf_sk->sk.sk_err = ECONNREFUSED;
226bece7b23SSjur Braendeland cf_sk->sk.sk_state = CAIF_DISCONNECTED;
227bece7b23SSjur Braendeland cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;
228bece7b23SSjur Braendeland /*
229bece7b23SSjur Braendeland * Socket "standards" seems to require POLLOUT to
230bece7b23SSjur Braendeland * be set at connect failure.
231bece7b23SSjur Braendeland */
232bece7b23SSjur Braendeland set_tx_flow_on(cf_sk);
233bece7b23SSjur Braendeland cf_sk->sk.sk_state_change(&cf_sk->sk);
234e6f95ec8SSjur Braendeland break;
235e6f95ec8SSjur Braendeland
236e6f95ec8SSjur Braendeland case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
237bece7b23SSjur Braendeland /* Modem has closed this connection, or device is down. */
238bece7b23SSjur Braendeland cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;
239bece7b23SSjur Braendeland cf_sk->sk.sk_err = ECONNRESET;
240bece7b23SSjur Braendeland set_rx_flow_on(cf_sk);
241e3ae2365SAlexander Aring sk_error_report(&cf_sk->sk);
242e6f95ec8SSjur Braendeland break;
243e6f95ec8SSjur Braendeland
244e6f95ec8SSjur Braendeland default:
245b31fa5baSJoe Perches pr_debug("Unexpected flow command %d\n", flow);
246e6f95ec8SSjur Braendeland }
247e6f95ec8SSjur Braendeland }
248e6f95ec8SSjur Braendeland
caif_check_flow_release(struct sock * sk)249bece7b23SSjur Braendeland static void caif_check_flow_release(struct sock *sk)
250e6f95ec8SSjur Braendeland {
251bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
252bece7b23SSjur Braendeland
253bece7b23SSjur Braendeland if (rx_flow_is_on(cf_sk))
254bece7b23SSjur Braendeland return;
255bece7b23SSjur Braendeland
256bece7b23SSjur Braendeland if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) {
257bece7b23SSjur Braendeland set_rx_flow_on(cf_sk);
258ca6a09f2SSjur Braendeland caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ);
259e6f95ec8SSjur Braendeland }
260bece7b23SSjur Braendeland }
261e6f95ec8SSjur Braendeland
262dcda138dSSjur Braendeland /*
263dcda138dSSjur Braendeland * Copied from unix_dgram_recvmsg, but removed credit checks,
264dcda138dSSjur Braendeland * changed locking, address handling and added MSG_TRUNC.
265dcda138dSSjur Braendeland */
caif_seqpkt_recvmsg(struct socket * sock,struct msghdr * m,size_t len,int flags)2661b784140SYing Xue static int caif_seqpkt_recvmsg(struct socket *sock, struct msghdr *m,
2671b784140SYing Xue size_t len, int flags)
268e6f95ec8SSjur Braendeland
269e6f95ec8SSjur Braendeland {
270e6f95ec8SSjur Braendeland struct sock *sk = sock->sk;
271e6f95ec8SSjur Braendeland struct sk_buff *skb;
272dcda138dSSjur Braendeland int ret;
273dcda138dSSjur Braendeland int copylen;
274e6f95ec8SSjur Braendeland
275dcda138dSSjur Braendeland ret = -EOPNOTSUPP;
2763eeff778SAl Viro if (flags & MSG_OOB)
277dcda138dSSjur Braendeland goto read_error;
278e6f95ec8SSjur Braendeland
279f4b41f06SOliver Hartkopp skb = skb_recv_datagram(sk, flags, &ret);
280bece7b23SSjur Braendeland if (!skb)
281e6f95ec8SSjur Braendeland goto read_error;
282dcda138dSSjur Braendeland copylen = skb->len;
283dcda138dSSjur Braendeland if (len < copylen) {
284dcda138dSSjur Braendeland m->msg_flags |= MSG_TRUNC;
285dcda138dSSjur Braendeland copylen = len;
286e6f95ec8SSjur Braendeland }
287e6f95ec8SSjur Braendeland
28851f3d02bSDavid S. Miller ret = skb_copy_datagram_msg(skb, 0, m, copylen);
289bece7b23SSjur Braendeland if (ret)
290dcda138dSSjur Braendeland goto out_free;
291e6f95ec8SSjur Braendeland
292dcda138dSSjur Braendeland ret = (flags & MSG_TRUNC) ? skb->len : copylen;
293dcda138dSSjur Braendeland out_free:
294e6f95ec8SSjur Braendeland skb_free_datagram(sk, skb);
295bece7b23SSjur Braendeland caif_check_flow_release(sk);
296dcda138dSSjur Braendeland return ret;
297e6f95ec8SSjur Braendeland
298e6f95ec8SSjur Braendeland read_error:
299e6f95ec8SSjur Braendeland return ret;
300e6f95ec8SSjur Braendeland }
301e6f95ec8SSjur Braendeland
302bece7b23SSjur Braendeland
303bece7b23SSjur Braendeland /* Copied from unix_stream_wait_data, identical except for lock call. */
caif_stream_data_wait(struct sock * sk,long timeo)304bece7b23SSjur Braendeland static long caif_stream_data_wait(struct sock *sk, long timeo)
305e6f95ec8SSjur Braendeland {
306bece7b23SSjur Braendeland DEFINE_WAIT(wait);
307bece7b23SSjur Braendeland lock_sock(sk);
308e6f95ec8SSjur Braendeland
309bece7b23SSjur Braendeland for (;;) {
310bece7b23SSjur Braendeland prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
311e6f95ec8SSjur Braendeland
312bece7b23SSjur Braendeland if (!skb_queue_empty(&sk->sk_receive_queue) ||
313bece7b23SSjur Braendeland sk->sk_err ||
314bece7b23SSjur Braendeland sk->sk_state != CAIF_CONNECTED ||
315bece7b23SSjur Braendeland sock_flag(sk, SOCK_DEAD) ||
316bece7b23SSjur Braendeland (sk->sk_shutdown & RCV_SHUTDOWN) ||
317bece7b23SSjur Braendeland signal_pending(current) ||
318bece7b23SSjur Braendeland !timeo)
319bece7b23SSjur Braendeland break;
320bece7b23SSjur Braendeland
3219cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
322bece7b23SSjur Braendeland release_sock(sk);
323bece7b23SSjur Braendeland timeo = schedule_timeout(timeo);
324bece7b23SSjur Braendeland lock_sock(sk);
325b48732e4SMark Salyzyn
326b48732e4SMark Salyzyn if (sock_flag(sk, SOCK_DEAD))
327b48732e4SMark Salyzyn break;
328b48732e4SMark Salyzyn
3299cd3e072SEric Dumazet sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
330e6f95ec8SSjur Braendeland }
331e6f95ec8SSjur Braendeland
332bece7b23SSjur Braendeland finish_wait(sk_sleep(sk), &wait);
333bece7b23SSjur Braendeland release_sock(sk);
334bece7b23SSjur Braendeland return timeo;
335e6f95ec8SSjur Braendeland }
336e6f95ec8SSjur Braendeland
337e6f95ec8SSjur Braendeland
338e6f95ec8SSjur Braendeland /*
339bece7b23SSjur Braendeland * Copied from unix_stream_recvmsg, but removed credit checks,
340bece7b23SSjur Braendeland * changed locking calls, changed address handling.
341e6f95ec8SSjur Braendeland */
caif_stream_recvmsg(struct socket * sock,struct msghdr * msg,size_t size,int flags)3421b784140SYing Xue static int caif_stream_recvmsg(struct socket *sock, struct msghdr *msg,
3431b784140SYing Xue size_t size, int flags)
344bece7b23SSjur Braendeland {
345bece7b23SSjur Braendeland struct sock *sk = sock->sk;
346bece7b23SSjur Braendeland int copied = 0;
347bece7b23SSjur Braendeland int target;
348bece7b23SSjur Braendeland int err = 0;
349bece7b23SSjur Braendeland long timeo;
350e6f95ec8SSjur Braendeland
351bece7b23SSjur Braendeland err = -EOPNOTSUPP;
352bece7b23SSjur Braendeland if (flags&MSG_OOB)
353bece7b23SSjur Braendeland goto out;
354e6f95ec8SSjur Braendeland
355bece7b23SSjur Braendeland /*
356bece7b23SSjur Braendeland * Lock the socket to prevent queue disordering
357bece7b23SSjur Braendeland * while sleeps in memcpy_tomsg
358bece7b23SSjur Braendeland */
359bece7b23SSjur Braendeland err = -EAGAIN;
360bece7b23SSjur Braendeland if (sk->sk_state == CAIF_CONNECTING)
361bece7b23SSjur Braendeland goto out;
362e6f95ec8SSjur Braendeland
363bece7b23SSjur Braendeland caif_read_lock(sk);
364bece7b23SSjur Braendeland target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
365bece7b23SSjur Braendeland timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
366e6f95ec8SSjur Braendeland
367e6f95ec8SSjur Braendeland do {
368bece7b23SSjur Braendeland int chunk;
369bece7b23SSjur Braendeland struct sk_buff *skb;
370e6f95ec8SSjur Braendeland
371bece7b23SSjur Braendeland lock_sock(sk);
372b48732e4SMark Salyzyn if (sock_flag(sk, SOCK_DEAD)) {
373b48732e4SMark Salyzyn err = -ECONNRESET;
374b48732e4SMark Salyzyn goto unlock;
375b48732e4SMark Salyzyn }
376bece7b23SSjur Braendeland skb = skb_dequeue(&sk->sk_receive_queue);
377bece7b23SSjur Braendeland caif_check_flow_release(sk);
378bece7b23SSjur Braendeland
379bece7b23SSjur Braendeland if (skb == NULL) {
380bece7b23SSjur Braendeland if (copied >= target)
381bece7b23SSjur Braendeland goto unlock;
382bece7b23SSjur Braendeland /*
383bece7b23SSjur Braendeland * POSIX 1003.1g mandates this order.
384bece7b23SSjur Braendeland */
385bece7b23SSjur Braendeland err = sock_error(sk);
386bece7b23SSjur Braendeland if (err)
387bece7b23SSjur Braendeland goto unlock;
388bece7b23SSjur Braendeland err = -ECONNRESET;
389bece7b23SSjur Braendeland if (sk->sk_shutdown & RCV_SHUTDOWN)
390bece7b23SSjur Braendeland goto unlock;
391bece7b23SSjur Braendeland
392bece7b23SSjur Braendeland err = -EPIPE;
393bece7b23SSjur Braendeland if (sk->sk_state != CAIF_CONNECTED)
394bece7b23SSjur Braendeland goto unlock;
395bece7b23SSjur Braendeland if (sock_flag(sk, SOCK_DEAD))
396bece7b23SSjur Braendeland goto unlock;
397bece7b23SSjur Braendeland
398bece7b23SSjur Braendeland release_sock(sk);
399bece7b23SSjur Braendeland
400bece7b23SSjur Braendeland err = -EAGAIN;
401bece7b23SSjur Braendeland if (!timeo)
402e6f95ec8SSjur Braendeland break;
403e6f95ec8SSjur Braendeland
404bece7b23SSjur Braendeland caif_read_unlock(sk);
405bece7b23SSjur Braendeland
406bece7b23SSjur Braendeland timeo = caif_stream_data_wait(sk, timeo);
407bece7b23SSjur Braendeland
408bece7b23SSjur Braendeland if (signal_pending(current)) {
409bece7b23SSjur Braendeland err = sock_intr_errno(timeo);
410bece7b23SSjur Braendeland goto out;
411bece7b23SSjur Braendeland }
412bece7b23SSjur Braendeland caif_read_lock(sk);
413bece7b23SSjur Braendeland continue;
414bece7b23SSjur Braendeland unlock:
415bece7b23SSjur Braendeland release_sock(sk);
416bece7b23SSjur Braendeland break;
417bece7b23SSjur Braendeland }
418bece7b23SSjur Braendeland release_sock(sk);
419bece7b23SSjur Braendeland chunk = min_t(unsigned int, skb->len, size);
4207eab8d9eSAl Viro if (memcpy_to_msg(msg, skb->data, chunk)) {
421bece7b23SSjur Braendeland skb_queue_head(&sk->sk_receive_queue, skb);
422bece7b23SSjur Braendeland if (copied == 0)
423bece7b23SSjur Braendeland copied = -EFAULT;
424bece7b23SSjur Braendeland break;
425bece7b23SSjur Braendeland }
426bece7b23SSjur Braendeland copied += chunk;
427bece7b23SSjur Braendeland size -= chunk;
428bece7b23SSjur Braendeland
429bece7b23SSjur Braendeland /* Mark read part of skb as used */
430bece7b23SSjur Braendeland if (!(flags & MSG_PEEK)) {
431bece7b23SSjur Braendeland skb_pull(skb, chunk);
432bece7b23SSjur Braendeland
433bece7b23SSjur Braendeland /* put the skb back if we didn't use it up. */
434bece7b23SSjur Braendeland if (skb->len) {
435bece7b23SSjur Braendeland skb_queue_head(&sk->sk_receive_queue, skb);
436bece7b23SSjur Braendeland break;
437bece7b23SSjur Braendeland }
438bece7b23SSjur Braendeland kfree_skb(skb);
439bece7b23SSjur Braendeland
440bece7b23SSjur Braendeland } else {
441bece7b23SSjur Braendeland /*
442bece7b23SSjur Braendeland * It is questionable, see note in unix_dgram_recvmsg.
443bece7b23SSjur Braendeland */
444bece7b23SSjur Braendeland /* put message back and return */
445bece7b23SSjur Braendeland skb_queue_head(&sk->sk_receive_queue, skb);
446bece7b23SSjur Braendeland break;
447bece7b23SSjur Braendeland }
448bece7b23SSjur Braendeland } while (size);
449bece7b23SSjur Braendeland caif_read_unlock(sk);
450bece7b23SSjur Braendeland
451bece7b23SSjur Braendeland out:
452bece7b23SSjur Braendeland return copied ? : err;
453e6f95ec8SSjur Braendeland }
454e6f95ec8SSjur Braendeland
455bece7b23SSjur Braendeland /*
456bece7b23SSjur Braendeland * Copied from sock.c:sock_wait_for_wmem, but change to wait for
457bece7b23SSjur Braendeland * CAIF flow-on and sock_writable.
458bece7b23SSjur Braendeland */
caif_wait_for_flow_on(struct caifsock * cf_sk,int wait_writeable,long timeo,int * err)459bece7b23SSjur Braendeland static long caif_wait_for_flow_on(struct caifsock *cf_sk,
460bece7b23SSjur Braendeland int wait_writeable, long timeo, int *err)
461bece7b23SSjur Braendeland {
462bece7b23SSjur Braendeland struct sock *sk = &cf_sk->sk;
463bece7b23SSjur Braendeland DEFINE_WAIT(wait);
464bece7b23SSjur Braendeland for (;;) {
465bece7b23SSjur Braendeland *err = 0;
466bece7b23SSjur Braendeland if (tx_flow_is_on(cf_sk) &&
467bece7b23SSjur Braendeland (!wait_writeable || sock_writeable(&cf_sk->sk)))
468bece7b23SSjur Braendeland break;
469bece7b23SSjur Braendeland *err = -ETIMEDOUT;
470bece7b23SSjur Braendeland if (!timeo)
471bece7b23SSjur Braendeland break;
472bece7b23SSjur Braendeland *err = -ERESTARTSYS;
473bece7b23SSjur Braendeland if (signal_pending(current))
474bece7b23SSjur Braendeland break;
475bece7b23SSjur Braendeland prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
476bece7b23SSjur Braendeland *err = -ECONNRESET;
477bece7b23SSjur Braendeland if (sk->sk_shutdown & SHUTDOWN_MASK)
478bece7b23SSjur Braendeland break;
479bece7b23SSjur Braendeland *err = -sk->sk_err;
480bece7b23SSjur Braendeland if (sk->sk_err)
481bece7b23SSjur Braendeland break;
482bece7b23SSjur Braendeland *err = -EPIPE;
483bece7b23SSjur Braendeland if (cf_sk->sk.sk_state != CAIF_CONNECTED)
484bece7b23SSjur Braendeland break;
485bece7b23SSjur Braendeland timeo = schedule_timeout(timeo);
486bece7b23SSjur Braendeland }
487bece7b23SSjur Braendeland finish_wait(sk_sleep(sk), &wait);
488bece7b23SSjur Braendeland return timeo;
489e6f95ec8SSjur Braendeland }
490e6f95ec8SSjur Braendeland
491bece7b23SSjur Braendeland /*
492bece7b23SSjur Braendeland * Transmit a SKB. The device may temporarily request re-transmission
493bece7b23SSjur Braendeland * by returning EAGAIN.
494bece7b23SSjur Braendeland */
transmit_skb(struct sk_buff * skb,struct caifsock * cf_sk,int noblock,long timeo)495bece7b23SSjur Braendeland static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
496bece7b23SSjur Braendeland int noblock, long timeo)
497bece7b23SSjur Braendeland {
498bece7b23SSjur Braendeland struct cfpkt *pkt;
499e6f95ec8SSjur Braendeland
500bece7b23SSjur Braendeland pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
5013f874adcSsjur.brandeland@stericsson.com memset(skb->cb, 0, sizeof(struct caif_payload_info));
50244764812SDmitry Tarnyagin cfpkt_set_prio(pkt, cf_sk->sk.sk_priority);
503bece7b23SSjur Braendeland
504ba760574SDmitry Tarnyagin if (cf_sk->layer.dn == NULL) {
505ba760574SDmitry Tarnyagin kfree_skb(skb);
5064dd820c0SSjur Brændeland return -EINVAL;
507ba760574SDmitry Tarnyagin }
508bece7b23SSjur Braendeland
5094dd820c0SSjur Brændeland return cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt);
510e6f95ec8SSjur Braendeland }
511e6f95ec8SSjur Braendeland
512bece7b23SSjur Braendeland /* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */
caif_seqpkt_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)5131b784140SYing Xue static int caif_seqpkt_sendmsg(struct socket *sock, struct msghdr *msg,
5141b784140SYing Xue size_t len)
515e6f95ec8SSjur Braendeland {
516e6f95ec8SSjur Braendeland struct sock *sk = sock->sk;
517e6f95ec8SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
518bece7b23SSjur Braendeland int buffer_size;
519bece7b23SSjur Braendeland int ret = 0;
520bece7b23SSjur Braendeland struct sk_buff *skb = NULL;
521bece7b23SSjur Braendeland int noblock;
522bece7b23SSjur Braendeland long timeo;
523bece7b23SSjur Braendeland caif_assert(cf_sk);
524bece7b23SSjur Braendeland ret = sock_error(sk);
525bece7b23SSjur Braendeland if (ret)
526bece7b23SSjur Braendeland goto err;
527bece7b23SSjur Braendeland
528bece7b23SSjur Braendeland ret = -EOPNOTSUPP;
529bece7b23SSjur Braendeland if (msg->msg_flags&MSG_OOB)
530bece7b23SSjur Braendeland goto err;
531bece7b23SSjur Braendeland
532bece7b23SSjur Braendeland ret = -EOPNOTSUPP;
533bece7b23SSjur Braendeland if (msg->msg_namelen)
534bece7b23SSjur Braendeland goto err;
535bece7b23SSjur Braendeland
536bece7b23SSjur Braendeland noblock = msg->msg_flags & MSG_DONTWAIT;
537bece7b23SSjur Braendeland
538bece7b23SSjur Braendeland timeo = sock_sndtimeo(sk, noblock);
539bece7b23SSjur Braendeland timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
540bece7b23SSjur Braendeland 1, timeo, &ret);
541bece7b23SSjur Braendeland
5422aa40aefSSjur Braendeland if (ret)
5432aa40aefSSjur Braendeland goto err;
544bece7b23SSjur Braendeland ret = -EPIPE;
545bece7b23SSjur Braendeland if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
546bece7b23SSjur Braendeland sock_flag(sk, SOCK_DEAD) ||
547bece7b23SSjur Braendeland (sk->sk_shutdown & RCV_SHUTDOWN))
548bece7b23SSjur Braendeland goto err;
549bece7b23SSjur Braendeland
5502aa40aefSSjur Braendeland /* Error if trying to write more than maximum frame size. */
5512aa40aefSSjur Braendeland ret = -EMSGSIZE;
5522aa40aefSSjur Braendeland if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM)
5532aa40aefSSjur Braendeland goto err;
5542aa40aefSSjur Braendeland
5552aa40aefSSjur Braendeland buffer_size = len + cf_sk->headroom + cf_sk->tailroom;
5562aa40aefSSjur Braendeland
557bece7b23SSjur Braendeland ret = -ENOMEM;
558bece7b23SSjur Braendeland skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
5592aa40aefSSjur Braendeland
5602aa40aefSSjur Braendeland if (!skb || skb_tailroom(skb) < buffer_size)
561bece7b23SSjur Braendeland goto err;
5622aa40aefSSjur Braendeland
5632aa40aefSSjur Braendeland skb_reserve(skb, cf_sk->headroom);
564bece7b23SSjur Braendeland
5656ce8e9ceSAl Viro ret = memcpy_from_msg(skb_put(skb, len), msg, len);
566bece7b23SSjur Braendeland
567bece7b23SSjur Braendeland if (ret)
568bece7b23SSjur Braendeland goto err;
569bece7b23SSjur Braendeland ret = transmit_skb(skb, cf_sk, noblock, timeo);
570bece7b23SSjur Braendeland if (ret < 0)
571c85c2951Ssjur.brandeland@stericsson.com /* skb is already freed */
572c85c2951Ssjur.brandeland@stericsson.com return ret;
573c85c2951Ssjur.brandeland@stericsson.com
574bece7b23SSjur Braendeland return len;
575bece7b23SSjur Braendeland err:
576bece7b23SSjur Braendeland kfree_skb(skb);
577bece7b23SSjur Braendeland return ret;
578e6f95ec8SSjur Braendeland }
579e6f95ec8SSjur Braendeland
580bece7b23SSjur Braendeland /*
581bece7b23SSjur Braendeland * Copied from unix_stream_sendmsg and adapted to CAIF:
582bece7b23SSjur Braendeland * Changed removed permission handling and added waiting for flow on
583bece7b23SSjur Braendeland * and other minor adaptations.
584bece7b23SSjur Braendeland */
caif_stream_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)5851b784140SYing Xue static int caif_stream_sendmsg(struct socket *sock, struct msghdr *msg,
5861b784140SYing Xue size_t len)
587e6f95ec8SSjur Braendeland {
588bece7b23SSjur Braendeland struct sock *sk = sock->sk;
589bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
590bece7b23SSjur Braendeland int err, size;
591bece7b23SSjur Braendeland struct sk_buff *skb;
592bece7b23SSjur Braendeland int sent = 0;
593bece7b23SSjur Braendeland long timeo;
594e6f95ec8SSjur Braendeland
595bece7b23SSjur Braendeland err = -EOPNOTSUPP;
596bece7b23SSjur Braendeland if (unlikely(msg->msg_flags&MSG_OOB))
597bece7b23SSjur Braendeland goto out_err;
598e6f95ec8SSjur Braendeland
599bece7b23SSjur Braendeland if (unlikely(msg->msg_namelen))
600bece7b23SSjur Braendeland goto out_err;
601e6f95ec8SSjur Braendeland
602bece7b23SSjur Braendeland timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
603bece7b23SSjur Braendeland timeo = caif_wait_for_flow_on(cf_sk, 1, timeo, &err);
604bece7b23SSjur Braendeland
605bece7b23SSjur Braendeland if (unlikely(sk->sk_shutdown & SEND_SHUTDOWN))
606bece7b23SSjur Braendeland goto pipe_err;
607bece7b23SSjur Braendeland
608bece7b23SSjur Braendeland while (sent < len) {
609bece7b23SSjur Braendeland
610bece7b23SSjur Braendeland size = len-sent;
611bece7b23SSjur Braendeland
6122aa40aefSSjur Braendeland if (size > cf_sk->maxframe)
6132aa40aefSSjur Braendeland size = cf_sk->maxframe;
614bece7b23SSjur Braendeland
615bece7b23SSjur Braendeland /* If size is more than half of sndbuf, chop up message */
616bece7b23SSjur Braendeland if (size > ((sk->sk_sndbuf >> 1) - 64))
617bece7b23SSjur Braendeland size = (sk->sk_sndbuf >> 1) - 64;
618bece7b23SSjur Braendeland
619bece7b23SSjur Braendeland if (size > SKB_MAX_ALLOC)
620bece7b23SSjur Braendeland size = SKB_MAX_ALLOC;
621bece7b23SSjur Braendeland
622bece7b23SSjur Braendeland skb = sock_alloc_send_skb(sk,
6232aa40aefSSjur Braendeland size + cf_sk->headroom +
6242aa40aefSSjur Braendeland cf_sk->tailroom,
625bece7b23SSjur Braendeland msg->msg_flags&MSG_DONTWAIT,
626bece7b23SSjur Braendeland &err);
627bece7b23SSjur Braendeland if (skb == NULL)
628bece7b23SSjur Braendeland goto out_err;
629bece7b23SSjur Braendeland
6302aa40aefSSjur Braendeland skb_reserve(skb, cf_sk->headroom);
631bece7b23SSjur Braendeland /*
632bece7b23SSjur Braendeland * If you pass two values to the sock_alloc_send_skb
633bece7b23SSjur Braendeland * it tries to grab the large buffer with GFP_NOFS
634bece7b23SSjur Braendeland * (which can fail easily), and if it fails grab the
635bece7b23SSjur Braendeland * fallback size buffer which is under a page and will
636bece7b23SSjur Braendeland * succeed. [Alan]
637bece7b23SSjur Braendeland */
638bece7b23SSjur Braendeland size = min_t(int, size, skb_tailroom(skb));
639bece7b23SSjur Braendeland
6406ce8e9ceSAl Viro err = memcpy_from_msg(skb_put(skb, size), msg, size);
641bece7b23SSjur Braendeland if (err) {
642bece7b23SSjur Braendeland kfree_skb(skb);
643bece7b23SSjur Braendeland goto out_err;
644bece7b23SSjur Braendeland }
645bece7b23SSjur Braendeland err = transmit_skb(skb, cf_sk,
646bece7b23SSjur Braendeland msg->msg_flags&MSG_DONTWAIT, timeo);
647ba760574SDmitry Tarnyagin if (err < 0)
648ba760574SDmitry Tarnyagin /* skb is already freed */
649bece7b23SSjur Braendeland goto pipe_err;
650ba760574SDmitry Tarnyagin
651bece7b23SSjur Braendeland sent += size;
652bece7b23SSjur Braendeland }
653bece7b23SSjur Braendeland
654bece7b23SSjur Braendeland return sent;
655bece7b23SSjur Braendeland
656bece7b23SSjur Braendeland pipe_err:
657bece7b23SSjur Braendeland if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL))
658bece7b23SSjur Braendeland send_sig(SIGPIPE, current, 0);
659bece7b23SSjur Braendeland err = -EPIPE;
660bece7b23SSjur Braendeland out_err:
661bece7b23SSjur Braendeland return sent ? : err;
662e6f95ec8SSjur Braendeland }
663e6f95ec8SSjur Braendeland
setsockopt(struct socket * sock,int lvl,int opt,sockptr_t ov,unsigned int ol)664a7b75c5aSChristoph Hellwig static int setsockopt(struct socket *sock, int lvl, int opt, sockptr_t ov,
665a7b75c5aSChristoph Hellwig unsigned int ol)
666e6f95ec8SSjur Braendeland {
667e6f95ec8SSjur Braendeland struct sock *sk = sock->sk;
668e6f95ec8SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
669f2527ec4SAndré Carvalho de Matos int linksel;
670e6f95ec8SSjur Braendeland
671bece7b23SSjur Braendeland if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
672e6f95ec8SSjur Braendeland return -ENOPROTOOPT;
673bece7b23SSjur Braendeland
674e6f95ec8SSjur Braendeland switch (opt) {
675e6f95ec8SSjur Braendeland case CAIFSO_LINK_SELECT:
676bece7b23SSjur Braendeland if (ol < sizeof(int))
677e6f95ec8SSjur Braendeland return -EINVAL;
678e6f95ec8SSjur Braendeland if (lvl != SOL_CAIF)
679e6f95ec8SSjur Braendeland goto bad_sol;
680a7b75c5aSChristoph Hellwig if (copy_from_sockptr(&linksel, ov, sizeof(int)))
681e6f95ec8SSjur Braendeland return -EINVAL;
682e6f95ec8SSjur Braendeland lock_sock(&(cf_sk->sk));
683e6f95ec8SSjur Braendeland cf_sk->conn_req.link_selector = linksel;
684e6f95ec8SSjur Braendeland release_sock(&cf_sk->sk);
685e6f95ec8SSjur Braendeland return 0;
686e6f95ec8SSjur Braendeland
687e6f95ec8SSjur Braendeland case CAIFSO_REQ_PARAM:
688e6f95ec8SSjur Braendeland if (lvl != SOL_CAIF)
689e6f95ec8SSjur Braendeland goto bad_sol;
690e6f95ec8SSjur Braendeland if (cf_sk->sk.sk_protocol != CAIFPROTO_UTIL)
691e6f95ec8SSjur Braendeland return -ENOPROTOOPT;
692e6f95ec8SSjur Braendeland lock_sock(&(cf_sk->sk));
693bece7b23SSjur Braendeland if (ol > sizeof(cf_sk->conn_req.param.data) ||
694a7b75c5aSChristoph Hellwig copy_from_sockptr(&cf_sk->conn_req.param.data, ov, ol)) {
695e6f95ec8SSjur Braendeland release_sock(&cf_sk->sk);
696e6f95ec8SSjur Braendeland return -EINVAL;
697e6f95ec8SSjur Braendeland }
69891b5c98cSDan Rosenberg cf_sk->conn_req.param.size = ol;
699e6f95ec8SSjur Braendeland release_sock(&cf_sk->sk);
700e6f95ec8SSjur Braendeland return 0;
701e6f95ec8SSjur Braendeland
702e6f95ec8SSjur Braendeland default:
703bece7b23SSjur Braendeland return -ENOPROTOOPT;
704e6f95ec8SSjur Braendeland }
705e6f95ec8SSjur Braendeland
706e6f95ec8SSjur Braendeland return 0;
707e6f95ec8SSjur Braendeland bad_sol:
708e6f95ec8SSjur Braendeland return -ENOPROTOOPT;
709e6f95ec8SSjur Braendeland
710e6f95ec8SSjur Braendeland }
711e6f95ec8SSjur Braendeland
712bece7b23SSjur Braendeland /*
713bece7b23SSjur Braendeland * caif_connect() - Connect a CAIF Socket
714bece7b23SSjur Braendeland * Copied and modified af_irda.c:irda_connect().
715bece7b23SSjur Braendeland *
716bece7b23SSjur Braendeland * Note : by consulting "errno", the user space caller may learn the cause
717bece7b23SSjur Braendeland * of the failure. Most of them are visible in the function, others may come
718bece7b23SSjur Braendeland * from subroutines called and are listed here :
719bece7b23SSjur Braendeland * o -EAFNOSUPPORT: bad socket family or type.
720bece7b23SSjur Braendeland * o -ESOCKTNOSUPPORT: bad socket type or protocol
721bece7b23SSjur Braendeland * o -EINVAL: bad socket address, or CAIF link type
722bece7b23SSjur Braendeland * o -ECONNREFUSED: remote end refused the connection.
723bece7b23SSjur Braendeland * o -EINPROGRESS: connect request sent but timed out (or non-blocking)
724bece7b23SSjur Braendeland * o -EISCONN: already connected.
725bece7b23SSjur Braendeland * o -ETIMEDOUT: Connection timed out (send timeout)
726bece7b23SSjur Braendeland * o -ENODEV: No link layer to send request
727bece7b23SSjur Braendeland * o -ECONNRESET: Received Shutdown indication or lost link layer
728bece7b23SSjur Braendeland * o -ENOMEM: Out of memory
729bece7b23SSjur Braendeland *
730bece7b23SSjur Braendeland * State Strategy:
731bece7b23SSjur Braendeland * o sk_state: holds the CAIF_* protocol state, it's updated by
732bece7b23SSjur Braendeland * caif_ctrl_cb.
733bece7b23SSjur Braendeland * o sock->state: holds the SS_* socket state and is updated by connect and
734bece7b23SSjur Braendeland * disconnect.
735bece7b23SSjur Braendeland */
caif_connect(struct socket * sock,struct sockaddr * uaddr,int addr_len,int flags)736bece7b23SSjur Braendeland static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
737bece7b23SSjur Braendeland int addr_len, int flags)
738e6f95ec8SSjur Braendeland {
739e6f95ec8SSjur Braendeland struct sock *sk = sock->sk;
740bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
741bece7b23SSjur Braendeland long timeo;
742bece7b23SSjur Braendeland int err;
7432aa40aefSSjur Braendeland int ifindex, headroom, tailroom;
74479315068SEric Dumazet unsigned int mtu;
7452aa40aefSSjur Braendeland struct net_device *dev;
7462aa40aefSSjur Braendeland
747bece7b23SSjur Braendeland lock_sock(sk);
748e6f95ec8SSjur Braendeland
74920a3d5bfSMateusz Jurczyk err = -EINVAL;
75020a3d5bfSMateusz Jurczyk if (addr_len < offsetofend(struct sockaddr, sa_family))
75120a3d5bfSMateusz Jurczyk goto out;
75220a3d5bfSMateusz Jurczyk
753bece7b23SSjur Braendeland err = -EAFNOSUPPORT;
754bece7b23SSjur Braendeland if (uaddr->sa_family != AF_CAIF)
755e6f95ec8SSjur Braendeland goto out;
756e6f95ec8SSjur Braendeland
757bece7b23SSjur Braendeland switch (sock->state) {
758bece7b23SSjur Braendeland case SS_UNCONNECTED:
759bece7b23SSjur Braendeland /* Normal case, a fresh connect */
760bece7b23SSjur Braendeland caif_assert(sk->sk_state == CAIF_DISCONNECTED);
761bece7b23SSjur Braendeland break;
762bece7b23SSjur Braendeland case SS_CONNECTING:
763bece7b23SSjur Braendeland switch (sk->sk_state) {
764bece7b23SSjur Braendeland case CAIF_CONNECTED:
765bece7b23SSjur Braendeland sock->state = SS_CONNECTED;
766bece7b23SSjur Braendeland err = -EISCONN;
767bece7b23SSjur Braendeland goto out;
768bece7b23SSjur Braendeland case CAIF_DISCONNECTED:
769bece7b23SSjur Braendeland /* Reconnect allowed */
770bece7b23SSjur Braendeland break;
771bece7b23SSjur Braendeland case CAIF_CONNECTING:
772bece7b23SSjur Braendeland err = -EALREADY;
773bece7b23SSjur Braendeland if (flags & O_NONBLOCK)
774bece7b23SSjur Braendeland goto out;
775bece7b23SSjur Braendeland goto wait_connect;
776e6f95ec8SSjur Braendeland }
777bece7b23SSjur Braendeland break;
778bece7b23SSjur Braendeland case SS_CONNECTED:
779bece7b23SSjur Braendeland caif_assert(sk->sk_state == CAIF_CONNECTED ||
780bece7b23SSjur Braendeland sk->sk_state == CAIF_DISCONNECTED);
781bece7b23SSjur Braendeland if (sk->sk_shutdown & SHUTDOWN_MASK) {
782bece7b23SSjur Braendeland /* Allow re-connect after SHUTDOWN_IND */
783bee925dbSsjur.brandeland@stericsson.com caif_disconnect_client(sock_net(sk), &cf_sk->layer);
78454e90fb5Ssjur.brandeland@stericsson.com caif_free_client(&cf_sk->layer);
785bece7b23SSjur Braendeland break;
786e6f95ec8SSjur Braendeland }
787bece7b23SSjur Braendeland /* No reconnect on a seqpacket socket */
788bece7b23SSjur Braendeland err = -EISCONN;
789bece7b23SSjur Braendeland goto out;
790bece7b23SSjur Braendeland case SS_DISCONNECTING:
791bece7b23SSjur Braendeland case SS_FREE:
792bece7b23SSjur Braendeland caif_assert(1); /*Should never happen */
793bece7b23SSjur Braendeland break;
794bece7b23SSjur Braendeland }
795bece7b23SSjur Braendeland sk->sk_state = CAIF_DISCONNECTED;
796bece7b23SSjur Braendeland sock->state = SS_UNCONNECTED;
797bece7b23SSjur Braendeland sk_stream_kill_queues(&cf_sk->sk);
798e6f95ec8SSjur Braendeland
799bece7b23SSjur Braendeland err = -EINVAL;
800f5d72af9SDan Carpenter if (addr_len != sizeof(struct sockaddr_caif))
801bece7b23SSjur Braendeland goto out;
802bece7b23SSjur Braendeland
803bece7b23SSjur Braendeland memcpy(&cf_sk->conn_req.sockaddr, uaddr,
804e6f95ec8SSjur Braendeland sizeof(struct sockaddr_caif));
805e6f95ec8SSjur Braendeland
806bece7b23SSjur Braendeland /* Move to connecting socket, start sending Connect Requests */
807bece7b23SSjur Braendeland sock->state = SS_CONNECTING;
808bece7b23SSjur Braendeland sk->sk_state = CAIF_CONNECTING;
809e6f95ec8SSjur Braendeland
81033b2f559Ssjur.brandeland@stericsson.com /* Check priority value comming from socket */
811f2527ec4SAndré Carvalho de Matos /* if priority value is out of range it will be ajusted */
812f2527ec4SAndré Carvalho de Matos if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
813f2527ec4SAndré Carvalho de Matos cf_sk->conn_req.priority = CAIF_PRIO_MAX;
814f2527ec4SAndré Carvalho de Matos else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN)
815f2527ec4SAndré Carvalho de Matos cf_sk->conn_req.priority = CAIF_PRIO_MIN;
816f2527ec4SAndré Carvalho de Matos else
817f2527ec4SAndré Carvalho de Matos cf_sk->conn_req.priority = cf_sk->sk.sk_priority;
818f2527ec4SAndré Carvalho de Matos
819f2527ec4SAndré Carvalho de Matos /*ifindex = id of the interface.*/
820f2527ec4SAndré Carvalho de Matos cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if;
821f2527ec4SAndré Carvalho de Matos
822e6f95ec8SSjur Braendeland cf_sk->layer.receive = caif_sktrecv_cb;
823b3ccfbe4Ssjur.brandeland@stericsson.com
824bee925dbSsjur.brandeland@stericsson.com err = caif_connect_client(sock_net(sk), &cf_sk->conn_req,
8252aa40aefSSjur Braendeland &cf_sk->layer, &ifindex, &headroom, &tailroom);
826b3ccfbe4Ssjur.brandeland@stericsson.com
827bece7b23SSjur Braendeland if (err < 0) {
828bece7b23SSjur Braendeland cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
829bece7b23SSjur Braendeland cf_sk->sk.sk_state = CAIF_DISCONNECTED;
830bece7b23SSjur Braendeland goto out;
831e6f95ec8SSjur Braendeland }
83279315068SEric Dumazet
8332aa40aefSSjur Braendeland err = -ENODEV;
83479315068SEric Dumazet rcu_read_lock();
83579315068SEric Dumazet dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
83679315068SEric Dumazet if (!dev) {
83779315068SEric Dumazet rcu_read_unlock();
83879315068SEric Dumazet goto out;
83979315068SEric Dumazet }
8402aa40aefSSjur Braendeland cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
84179315068SEric Dumazet mtu = dev->mtu;
84279315068SEric Dumazet rcu_read_unlock();
84379315068SEric Dumazet
8442aa40aefSSjur Braendeland cf_sk->tailroom = tailroom;
84579315068SEric Dumazet cf_sk->maxframe = mtu - (headroom + tailroom);
8462aa40aefSSjur Braendeland if (cf_sk->maxframe < 1) {
847b31fa5baSJoe Perches pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
848f2527ec4SAndré Carvalho de Matos err = -ENODEV;
8492aa40aefSSjur Braendeland goto out;
8502aa40aefSSjur Braendeland }
851e6f95ec8SSjur Braendeland
852bece7b23SSjur Braendeland err = -EINPROGRESS;
853bece7b23SSjur Braendeland wait_connect:
854bece7b23SSjur Braendeland
855bece7b23SSjur Braendeland if (sk->sk_state != CAIF_CONNECTED && (flags & O_NONBLOCK))
856bece7b23SSjur Braendeland goto out;
857bece7b23SSjur Braendeland
858bece7b23SSjur Braendeland timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
859bece7b23SSjur Braendeland
860bece7b23SSjur Braendeland release_sock(sk);
8619e4b816bSSjur Braendeland err = -ERESTARTSYS;
8629e4b816bSSjur Braendeland timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
863bece7b23SSjur Braendeland sk->sk_state != CAIF_CONNECTING,
864bece7b23SSjur Braendeland timeo);
865bece7b23SSjur Braendeland lock_sock(sk);
8669e4b816bSSjur Braendeland if (timeo < 0)
867bece7b23SSjur Braendeland goto out; /* -ERESTARTSYS */
868e6f95ec8SSjur Braendeland
8699e4b816bSSjur Braendeland err = -ETIMEDOUT;
8709e4b816bSSjur Braendeland if (timeo == 0 && sk->sk_state != CAIF_CONNECTED)
8719e4b816bSSjur Braendeland goto out;
872bece7b23SSjur Braendeland if (sk->sk_state != CAIF_CONNECTED) {
873e6f95ec8SSjur Braendeland sock->state = SS_UNCONNECTED;
874bece7b23SSjur Braendeland err = sock_error(sk);
875bece7b23SSjur Braendeland if (!err)
876bece7b23SSjur Braendeland err = -ECONNREFUSED;
877bece7b23SSjur Braendeland goto out;
878bece7b23SSjur Braendeland }
879bece7b23SSjur Braendeland sock->state = SS_CONNECTED;
880bece7b23SSjur Braendeland err = 0;
881e6f95ec8SSjur Braendeland out:
882bece7b23SSjur Braendeland release_sock(sk);
883bece7b23SSjur Braendeland return err;
884e6f95ec8SSjur Braendeland }
885e6f95ec8SSjur Braendeland
886e6f95ec8SSjur Braendeland /*
887bece7b23SSjur Braendeland * caif_release() - Disconnect a CAIF Socket
888bece7b23SSjur Braendeland * Copied and modified af_irda.c:irda_release().
889e6f95ec8SSjur Braendeland */
caif_release(struct socket * sock)890e6f95ec8SSjur Braendeland static int caif_release(struct socket *sock)
891e6f95ec8SSjur Braendeland {
892e6f95ec8SSjur Braendeland struct sock *sk = sock->sk;
893bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
894bece7b23SSjur Braendeland
895bece7b23SSjur Braendeland if (!sk)
896bece7b23SSjur Braendeland return 0;
897bece7b23SSjur Braendeland
898bece7b23SSjur Braendeland set_tx_flow_off(cf_sk);
899bece7b23SSjur Braendeland
900bece7b23SSjur Braendeland /*
901bece7b23SSjur Braendeland * Ensure that packets are not queued after this point in time.
902bece7b23SSjur Braendeland * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock,
903bece7b23SSjur Braendeland * this ensures no packets when sock is dead.
904bece7b23SSjur Braendeland */
905c85c2951Ssjur.brandeland@stericsson.com spin_lock_bh(&sk->sk_receive_queue.lock);
906bece7b23SSjur Braendeland sock_set_flag(sk, SOCK_DEAD);
907c85c2951Ssjur.brandeland@stericsson.com spin_unlock_bh(&sk->sk_receive_queue.lock);
908bece7b23SSjur Braendeland sock->sk = NULL;
909bece7b23SSjur Braendeland
91033b2f559Ssjur.brandeland@stericsson.com WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir));
911e6f95ec8SSjur Braendeland debugfs_remove_recursive(cf_sk->debugfs_socket_dir);
912e6f95ec8SSjur Braendeland
913e6f95ec8SSjur Braendeland lock_sock(&(cf_sk->sk));
914bece7b23SSjur Braendeland sk->sk_state = CAIF_DISCONNECTED;
915e6f95ec8SSjur Braendeland sk->sk_shutdown = SHUTDOWN_MASK;
916e6f95ec8SSjur Braendeland
91754e90fb5Ssjur.brandeland@stericsson.com caif_disconnect_client(sock_net(sk), &cf_sk->layer);
918bece7b23SSjur Braendeland cf_sk->sk.sk_socket->state = SS_DISCONNECTING;
919a9a08845SLinus Torvalds wake_up_interruptible_poll(sk_sleep(sk), EPOLLERR|EPOLLHUP);
920e6f95ec8SSjur Braendeland
921bece7b23SSjur Braendeland sock_orphan(sk);
922bece7b23SSjur Braendeland sk_stream_kill_queues(&cf_sk->sk);
923bece7b23SSjur Braendeland release_sock(sk);
924e6f95ec8SSjur Braendeland sock_put(sk);
92554e90fb5Ssjur.brandeland@stericsson.com return 0;
926e6f95ec8SSjur Braendeland }
927e6f95ec8SSjur Braendeland
928bece7b23SSjur Braendeland /* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */
caif_poll(struct file * file,struct socket * sock,poll_table * wait)929a11e1d43SLinus Torvalds static __poll_t caif_poll(struct file *file,
930a11e1d43SLinus Torvalds struct socket *sock, poll_table *wait)
931bece7b23SSjur Braendeland {
932bece7b23SSjur Braendeland struct sock *sk = sock->sk;
933a11e1d43SLinus Torvalds __poll_t mask;
934bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
935a11e1d43SLinus Torvalds
93689ab066dSKarsten Graul sock_poll_wait(file, sock, wait);
937a11e1d43SLinus Torvalds mask = 0;
938bece7b23SSjur Braendeland
939bece7b23SSjur Braendeland /* exceptional events? */
940bece7b23SSjur Braendeland if (sk->sk_err)
941a9a08845SLinus Torvalds mask |= EPOLLERR;
942bece7b23SSjur Braendeland if (sk->sk_shutdown == SHUTDOWN_MASK)
943a9a08845SLinus Torvalds mask |= EPOLLHUP;
944bece7b23SSjur Braendeland if (sk->sk_shutdown & RCV_SHUTDOWN)
945a9a08845SLinus Torvalds mask |= EPOLLRDHUP;
946bece7b23SSjur Braendeland
947bece7b23SSjur Braendeland /* readable? */
9483ef7cf57SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue) ||
949bece7b23SSjur Braendeland (sk->sk_shutdown & RCV_SHUTDOWN))
950a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM;
951bece7b23SSjur Braendeland
952bece7b23SSjur Braendeland /*
953bece7b23SSjur Braendeland * we set writable also when the other side has shut down the
954bece7b23SSjur Braendeland * connection. This prevents stuck sockets.
955bece7b23SSjur Braendeland */
956bece7b23SSjur Braendeland if (sock_writeable(sk) && tx_flow_is_on(cf_sk))
957a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
958bece7b23SSjur Braendeland
959bece7b23SSjur Braendeland return mask;
960bece7b23SSjur Braendeland }
961bece7b23SSjur Braendeland
962bece7b23SSjur Braendeland static const struct proto_ops caif_seqpacket_ops = {
963e6f95ec8SSjur Braendeland .family = PF_CAIF,
964e6f95ec8SSjur Braendeland .owner = THIS_MODULE,
965e6f95ec8SSjur Braendeland .release = caif_release,
966e6f95ec8SSjur Braendeland .bind = sock_no_bind,
967e6f95ec8SSjur Braendeland .connect = caif_connect,
968e6f95ec8SSjur Braendeland .socketpair = sock_no_socketpair,
969e6f95ec8SSjur Braendeland .accept = sock_no_accept,
970e6f95ec8SSjur Braendeland .getname = sock_no_getname,
971a11e1d43SLinus Torvalds .poll = caif_poll,
972e6f95ec8SSjur Braendeland .ioctl = sock_no_ioctl,
973e6f95ec8SSjur Braendeland .listen = sock_no_listen,
974bece7b23SSjur Braendeland .shutdown = sock_no_shutdown,
975e6f95ec8SSjur Braendeland .setsockopt = setsockopt,
976bece7b23SSjur Braendeland .sendmsg = caif_seqpkt_sendmsg,
977bece7b23SSjur Braendeland .recvmsg = caif_seqpkt_recvmsg,
978e6f95ec8SSjur Braendeland .mmap = sock_no_mmap,
979bece7b23SSjur Braendeland };
980bece7b23SSjur Braendeland
981bece7b23SSjur Braendeland static const struct proto_ops caif_stream_ops = {
982bece7b23SSjur Braendeland .family = PF_CAIF,
983bece7b23SSjur Braendeland .owner = THIS_MODULE,
984bece7b23SSjur Braendeland .release = caif_release,
985bece7b23SSjur Braendeland .bind = sock_no_bind,
986bece7b23SSjur Braendeland .connect = caif_connect,
987bece7b23SSjur Braendeland .socketpair = sock_no_socketpair,
988bece7b23SSjur Braendeland .accept = sock_no_accept,
989bece7b23SSjur Braendeland .getname = sock_no_getname,
990a11e1d43SLinus Torvalds .poll = caif_poll,
991bece7b23SSjur Braendeland .ioctl = sock_no_ioctl,
992bece7b23SSjur Braendeland .listen = sock_no_listen,
993bece7b23SSjur Braendeland .shutdown = sock_no_shutdown,
994bece7b23SSjur Braendeland .setsockopt = setsockopt,
995bece7b23SSjur Braendeland .sendmsg = caif_stream_sendmsg,
996bece7b23SSjur Braendeland .recvmsg = caif_stream_recvmsg,
997bece7b23SSjur Braendeland .mmap = sock_no_mmap,
998e6f95ec8SSjur Braendeland };
999e6f95ec8SSjur Braendeland
1000e6f95ec8SSjur Braendeland /* This function is called when a socket is finally destroyed. */
caif_sock_destructor(struct sock * sk)1001e6f95ec8SSjur Braendeland static void caif_sock_destructor(struct sock *sk)
1002e6f95ec8SSjur Braendeland {
1003bece7b23SSjur Braendeland struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
100414afee4bSReshetova, Elena caif_assert(!refcount_read(&sk->sk_wmem_alloc));
1005e6f95ec8SSjur Braendeland caif_assert(sk_unhashed(sk));
1006e6f95ec8SSjur Braendeland caif_assert(!sk->sk_socket);
1007e6f95ec8SSjur Braendeland if (!sock_flag(sk, SOCK_DEAD)) {
100833b2f559Ssjur.brandeland@stericsson.com pr_debug("Attempt to release alive CAIF socket: %p\n", sk);
1009e6f95ec8SSjur Braendeland return;
1010e6f95ec8SSjur Braendeland }
1011bece7b23SSjur Braendeland sk_stream_kill_queues(&cf_sk->sk);
1012*62ec33b4SKuniyuki Iwashima WARN_ON_ONCE(sk->sk_forward_alloc);
1013b3ccfbe4Ssjur.brandeland@stericsson.com caif_free_client(&cf_sk->layer);
1014e6f95ec8SSjur Braendeland }
1015e6f95ec8SSjur Braendeland
caif_create(struct net * net,struct socket * sock,int protocol,int kern)1016e6f95ec8SSjur Braendeland static int caif_create(struct net *net, struct socket *sock, int protocol,
1017e6f95ec8SSjur Braendeland int kern)
1018e6f95ec8SSjur Braendeland {
1019e6f95ec8SSjur Braendeland struct sock *sk = NULL;
1020e6f95ec8SSjur Braendeland struct caifsock *cf_sk = NULL;
1021e6f95ec8SSjur Braendeland static struct proto prot = {.name = "PF_CAIF",
1022e6f95ec8SSjur Braendeland .owner = THIS_MODULE,
1023e6f95ec8SSjur Braendeland .obj_size = sizeof(struct caifsock),
102493070d33SDavid Windsor .useroffset = offsetof(struct caifsock, conn_req.param),
102593070d33SDavid Windsor .usersize = sizeof_field(struct caifsock, conn_req.param)
1026e6f95ec8SSjur Braendeland };
1027e6f95ec8SSjur Braendeland
1028bece7b23SSjur Braendeland if (!capable(CAP_SYS_ADMIN) && !capable(CAP_NET_ADMIN))
1029bece7b23SSjur Braendeland return -EPERM;
1030e6f95ec8SSjur Braendeland /*
1031e6f95ec8SSjur Braendeland * The sock->type specifies the socket type to use.
1032bece7b23SSjur Braendeland * The CAIF socket is a packet stream in the sense
1033bece7b23SSjur Braendeland * that it is packet based. CAIF trusts the reliability
1034bece7b23SSjur Braendeland * of the link, no resending is implemented.
1035e6f95ec8SSjur Braendeland */
1036bece7b23SSjur Braendeland if (sock->type == SOCK_SEQPACKET)
1037bece7b23SSjur Braendeland sock->ops = &caif_seqpacket_ops;
1038bece7b23SSjur Braendeland else if (sock->type == SOCK_STREAM)
1039bece7b23SSjur Braendeland sock->ops = &caif_stream_ops;
1040bece7b23SSjur Braendeland else
1041e6f95ec8SSjur Braendeland return -ESOCKTNOSUPPORT;
1042e6f95ec8SSjur Braendeland
1043e6f95ec8SSjur Braendeland if (protocol < 0 || protocol >= CAIFPROTO_MAX)
1044e6f95ec8SSjur Braendeland return -EPROTONOSUPPORT;
1045e6f95ec8SSjur Braendeland /*
1046bece7b23SSjur Braendeland * Set the socket state to unconnected. The socket state
1047bece7b23SSjur Braendeland * is really not used at all in the net/core or socket.c but the
1048e6f95ec8SSjur Braendeland * initialization makes sure that sock->state is not uninitialized.
1049e6f95ec8SSjur Braendeland */
105011aa9c28SEric W. Biederman sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot, kern);
1051e6f95ec8SSjur Braendeland if (!sk)
1052e6f95ec8SSjur Braendeland return -ENOMEM;
1053e6f95ec8SSjur Braendeland
1054e6f95ec8SSjur Braendeland cf_sk = container_of(sk, struct caifsock, sk);
1055e6f95ec8SSjur Braendeland
1056e6f95ec8SSjur Braendeland /* Store the protocol */
1057e6f95ec8SSjur Braendeland sk->sk_protocol = (unsigned char) protocol;
1058e6f95ec8SSjur Braendeland
105944764812SDmitry Tarnyagin /* Initialize default priority for well-known cases */
106044764812SDmitry Tarnyagin switch (protocol) {
106144764812SDmitry Tarnyagin case CAIFPROTO_AT:
106244764812SDmitry Tarnyagin sk->sk_priority = TC_PRIO_CONTROL;
106344764812SDmitry Tarnyagin break;
106444764812SDmitry Tarnyagin case CAIFPROTO_RFM:
106544764812SDmitry Tarnyagin sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
106644764812SDmitry Tarnyagin break;
106744764812SDmitry Tarnyagin default:
106844764812SDmitry Tarnyagin sk->sk_priority = TC_PRIO_BESTEFFORT;
106944764812SDmitry Tarnyagin }
107044764812SDmitry Tarnyagin
1071e6f95ec8SSjur Braendeland /*
1072e6f95ec8SSjur Braendeland * Lock in order to try to stop someone from opening the socket
1073e6f95ec8SSjur Braendeland * too early.
1074e6f95ec8SSjur Braendeland */
1075e6f95ec8SSjur Braendeland lock_sock(&(cf_sk->sk));
1076e6f95ec8SSjur Braendeland
1077e6f95ec8SSjur Braendeland /* Initialize the nozero default sock structure data. */
1078e6f95ec8SSjur Braendeland sock_init_data(sock, sk);
1079e6f95ec8SSjur Braendeland sk->sk_destruct = caif_sock_destructor;
1080e6f95ec8SSjur Braendeland
1081bece7b23SSjur Braendeland mutex_init(&cf_sk->readlock); /* single task reading lock */
1082bece7b23SSjur Braendeland cf_sk->layer.ctrlcmd = caif_ctrl_cb;
1083bece7b23SSjur Braendeland cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
1084bece7b23SSjur Braendeland cf_sk->sk.sk_state = CAIF_DISCONNECTED;
1085e6f95ec8SSjur Braendeland
1086bece7b23SSjur Braendeland set_tx_flow_off(cf_sk);
1087bece7b23SSjur Braendeland set_rx_flow_on(cf_sk);
1088e6f95ec8SSjur Braendeland
1089e6f95ec8SSjur Braendeland /* Set default options on configuration */
1090bece7b23SSjur Braendeland cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
1091e6f95ec8SSjur Braendeland cf_sk->conn_req.protocol = protocol;
1092e6f95ec8SSjur Braendeland release_sock(&cf_sk->sk);
1093e6f95ec8SSjur Braendeland return 0;
1094e6f95ec8SSjur Braendeland }
1095e6f95ec8SSjur Braendeland
1096bece7b23SSjur Braendeland
1097173e7837Slinzhang static const struct net_proto_family caif_family_ops = {
1098e6f95ec8SSjur Braendeland .family = PF_CAIF,
1099e6f95ec8SSjur Braendeland .create = caif_create,
1100e6f95ec8SSjur Braendeland .owner = THIS_MODULE,
1101e6f95ec8SSjur Braendeland };
1102e6f95ec8SSjur Braendeland
caif_sktinit_module(void)11034a695823Ssjur.brandeland@stericsson.com static int __init caif_sktinit_module(void)
1104e6f95ec8SSjur Braendeland {
1105c79e167cSPan Bian return sock_register(&caif_family_ops);
1106e6f95ec8SSjur Braendeland }
1107e6f95ec8SSjur Braendeland
caif_sktexit_module(void)1108e6f95ec8SSjur Braendeland static void __exit caif_sktexit_module(void)
1109e6f95ec8SSjur Braendeland {
1110e6f95ec8SSjur Braendeland sock_unregister(PF_CAIF);
1111e6f95ec8SSjur Braendeland }
1112e6f95ec8SSjur Braendeland module_init(caif_sktinit_module);
1113e6f95ec8SSjur Braendeland module_exit(caif_sktexit_module);
1114