Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/phonet/socket.c
15109 views
1
/*
2
* File: socket.c
3
*
4
* 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/gfp.h>
27
#include <linux/kernel.h>
28
#include <linux/net.h>
29
#include <linux/poll.h>
30
#include <net/sock.h>
31
#include <net/tcp_states.h>
32
33
#include <linux/phonet.h>
34
#include <net/phonet/phonet.h>
35
#include <net/phonet/pep.h>
36
#include <net/phonet/pn_dev.h>
37
38
static int pn_socket_release(struct socket *sock)
39
{
40
struct sock *sk = sock->sk;
41
42
if (sk) {
43
sock->sk = NULL;
44
sk->sk_prot->close(sk, 0);
45
}
46
return 0;
47
}
48
49
#define PN_HASHSIZE 16
50
#define PN_HASHMASK (PN_HASHSIZE-1)
51
52
53
static struct {
54
struct hlist_head hlist[PN_HASHSIZE];
55
struct mutex lock;
56
} pnsocks;
57
58
void __init pn_sock_init(void)
59
{
60
unsigned i;
61
62
for (i = 0; i < PN_HASHSIZE; i++)
63
INIT_HLIST_HEAD(pnsocks.hlist + i);
64
mutex_init(&pnsocks.lock);
65
}
66
67
static struct hlist_head *pn_hash_list(u16 obj)
68
{
69
return pnsocks.hlist + (obj & PN_HASHMASK);
70
}
71
72
/*
73
* Find address based on socket address, match only certain fields.
74
* Also grab sock if it was found. Remember to sock_put it later.
75
*/
76
struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
77
{
78
struct hlist_node *node;
79
struct sock *sknode;
80
struct sock *rval = NULL;
81
u16 obj = pn_sockaddr_get_object(spn);
82
u8 res = spn->spn_resource;
83
struct hlist_head *hlist = pn_hash_list(obj);
84
85
rcu_read_lock();
86
sk_for_each_rcu(sknode, node, hlist) {
87
struct pn_sock *pn = pn_sk(sknode);
88
BUG_ON(!pn->sobject); /* unbound socket */
89
90
if (!net_eq(sock_net(sknode), net))
91
continue;
92
if (pn_port(obj)) {
93
/* Look up socket by port */
94
if (pn_port(pn->sobject) != pn_port(obj))
95
continue;
96
} else {
97
/* If port is zero, look up by resource */
98
if (pn->resource != res)
99
continue;
100
}
101
if (pn_addr(pn->sobject) &&
102
pn_addr(pn->sobject) != pn_addr(obj))
103
continue;
104
105
rval = sknode;
106
sock_hold(sknode);
107
break;
108
}
109
rcu_read_unlock();
110
111
return rval;
112
}
113
114
/* Deliver a broadcast packet (only in bottom-half) */
115
void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
116
{
117
struct hlist_head *hlist = pnsocks.hlist;
118
unsigned h;
119
120
rcu_read_lock();
121
for (h = 0; h < PN_HASHSIZE; h++) {
122
struct hlist_node *node;
123
struct sock *sknode;
124
125
sk_for_each(sknode, node, hlist) {
126
struct sk_buff *clone;
127
128
if (!net_eq(sock_net(sknode), net))
129
continue;
130
if (!sock_flag(sknode, SOCK_BROADCAST))
131
continue;
132
133
clone = skb_clone(skb, GFP_ATOMIC);
134
if (clone) {
135
sock_hold(sknode);
136
sk_receive_skb(sknode, clone, 0);
137
}
138
}
139
hlist++;
140
}
141
rcu_read_unlock();
142
}
143
144
void pn_sock_hash(struct sock *sk)
145
{
146
struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
147
148
mutex_lock(&pnsocks.lock);
149
sk_add_node_rcu(sk, hlist);
150
mutex_unlock(&pnsocks.lock);
151
}
152
EXPORT_SYMBOL(pn_sock_hash);
153
154
void pn_sock_unhash(struct sock *sk)
155
{
156
mutex_lock(&pnsocks.lock);
157
sk_del_node_init_rcu(sk);
158
mutex_unlock(&pnsocks.lock);
159
pn_sock_unbind_all_res(sk);
160
synchronize_rcu();
161
}
162
EXPORT_SYMBOL(pn_sock_unhash);
163
164
static DEFINE_MUTEX(port_mutex);
165
166
static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
167
{
168
struct sock *sk = sock->sk;
169
struct pn_sock *pn = pn_sk(sk);
170
struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
171
int err;
172
u16 handle;
173
u8 saddr;
174
175
if (sk->sk_prot->bind)
176
return sk->sk_prot->bind(sk, addr, len);
177
178
if (len < sizeof(struct sockaddr_pn))
179
return -EINVAL;
180
if (spn->spn_family != AF_PHONET)
181
return -EAFNOSUPPORT;
182
183
handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
184
saddr = pn_addr(handle);
185
if (saddr && phonet_address_lookup(sock_net(sk), saddr))
186
return -EADDRNOTAVAIL;
187
188
lock_sock(sk);
189
if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
190
err = -EINVAL; /* attempt to rebind */
191
goto out;
192
}
193
WARN_ON(sk_hashed(sk));
194
mutex_lock(&port_mutex);
195
err = sk->sk_prot->get_port(sk, pn_port(handle));
196
if (err)
197
goto out_port;
198
199
/* get_port() sets the port, bind() sets the address if applicable */
200
pn->sobject = pn_object(saddr, pn_port(pn->sobject));
201
pn->resource = spn->spn_resource;
202
203
/* Enable RX on the socket */
204
sk->sk_prot->hash(sk);
205
out_port:
206
mutex_unlock(&port_mutex);
207
out:
208
release_sock(sk);
209
return err;
210
}
211
212
static int pn_socket_autobind(struct socket *sock)
213
{
214
struct sockaddr_pn sa;
215
int err;
216
217
memset(&sa, 0, sizeof(sa));
218
sa.spn_family = AF_PHONET;
219
err = pn_socket_bind(sock, (struct sockaddr *)&sa,
220
sizeof(struct sockaddr_pn));
221
if (err != -EINVAL)
222
return err;
223
BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
224
return 0; /* socket was already bound */
225
}
226
227
static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
228
int len, int flags)
229
{
230
struct sock *sk = sock->sk;
231
struct pn_sock *pn = pn_sk(sk);
232
struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
233
struct task_struct *tsk = current;
234
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
235
int err;
236
237
if (pn_socket_autobind(sock))
238
return -ENOBUFS;
239
if (len < sizeof(struct sockaddr_pn))
240
return -EINVAL;
241
if (spn->spn_family != AF_PHONET)
242
return -EAFNOSUPPORT;
243
244
lock_sock(sk);
245
246
switch (sock->state) {
247
case SS_UNCONNECTED:
248
if (sk->sk_state != TCP_CLOSE) {
249
err = -EISCONN;
250
goto out;
251
}
252
break;
253
case SS_CONNECTING:
254
err = -EALREADY;
255
goto out;
256
default:
257
err = -EISCONN;
258
goto out;
259
}
260
261
pn->dobject = pn_sockaddr_get_object(spn);
262
pn->resource = pn_sockaddr_get_resource(spn);
263
sock->state = SS_CONNECTING;
264
265
err = sk->sk_prot->connect(sk, addr, len);
266
if (err) {
267
sock->state = SS_UNCONNECTED;
268
pn->dobject = 0;
269
goto out;
270
}
271
272
while (sk->sk_state == TCP_SYN_SENT) {
273
DEFINE_WAIT(wait);
274
275
if (!timeo) {
276
err = -EINPROGRESS;
277
goto out;
278
}
279
if (signal_pending(tsk)) {
280
err = sock_intr_errno(timeo);
281
goto out;
282
}
283
284
prepare_to_wait_exclusive(sk_sleep(sk), &wait,
285
TASK_INTERRUPTIBLE);
286
release_sock(sk);
287
timeo = schedule_timeout(timeo);
288
lock_sock(sk);
289
finish_wait(sk_sleep(sk), &wait);
290
}
291
292
if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
293
err = 0;
294
else if (sk->sk_state == TCP_CLOSE_WAIT)
295
err = -ECONNRESET;
296
else
297
err = -ECONNREFUSED;
298
sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
299
out:
300
release_sock(sk);
301
return err;
302
}
303
304
static int pn_socket_accept(struct socket *sock, struct socket *newsock,
305
int flags)
306
{
307
struct sock *sk = sock->sk;
308
struct sock *newsk;
309
int err;
310
311
if (unlikely(sk->sk_state != TCP_LISTEN))
312
return -EINVAL;
313
314
newsk = sk->sk_prot->accept(sk, flags, &err);
315
if (!newsk)
316
return err;
317
318
lock_sock(newsk);
319
sock_graft(newsk, newsock);
320
newsock->state = SS_CONNECTED;
321
release_sock(newsk);
322
return 0;
323
}
324
325
static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
326
int *sockaddr_len, int peer)
327
{
328
struct sock *sk = sock->sk;
329
struct pn_sock *pn = pn_sk(sk);
330
331
memset(addr, 0, sizeof(struct sockaddr_pn));
332
addr->sa_family = AF_PHONET;
333
if (!peer) /* Race with bind() here is userland's problem. */
334
pn_sockaddr_set_object((struct sockaddr_pn *)addr,
335
pn->sobject);
336
337
*sockaddr_len = sizeof(struct sockaddr_pn);
338
return 0;
339
}
340
341
static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
342
poll_table *wait)
343
{
344
struct sock *sk = sock->sk;
345
struct pep_sock *pn = pep_sk(sk);
346
unsigned int mask = 0;
347
348
poll_wait(file, sk_sleep(sk), wait);
349
350
if (sk->sk_state == TCP_CLOSE)
351
return POLLERR;
352
if (!skb_queue_empty(&sk->sk_receive_queue))
353
mask |= POLLIN | POLLRDNORM;
354
if (!skb_queue_empty(&pn->ctrlreq_queue))
355
mask |= POLLPRI;
356
if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
357
return POLLHUP;
358
359
if (sk->sk_state == TCP_ESTABLISHED &&
360
atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
361
atomic_read(&pn->tx_credits))
362
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
363
364
return mask;
365
}
366
367
static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
368
unsigned long arg)
369
{
370
struct sock *sk = sock->sk;
371
struct pn_sock *pn = pn_sk(sk);
372
373
if (cmd == SIOCPNGETOBJECT) {
374
struct net_device *dev;
375
u16 handle;
376
u8 saddr;
377
378
if (get_user(handle, (__u16 __user *)arg))
379
return -EFAULT;
380
381
lock_sock(sk);
382
if (sk->sk_bound_dev_if)
383
dev = dev_get_by_index(sock_net(sk),
384
sk->sk_bound_dev_if);
385
else
386
dev = phonet_device_get(sock_net(sk));
387
if (dev && (dev->flags & IFF_UP))
388
saddr = phonet_address_get(dev, pn_addr(handle));
389
else
390
saddr = PN_NO_ADDR;
391
release_sock(sk);
392
393
if (dev)
394
dev_put(dev);
395
if (saddr == PN_NO_ADDR)
396
return -EHOSTUNREACH;
397
398
handle = pn_object(saddr, pn_port(pn->sobject));
399
return put_user(handle, (__u16 __user *)arg);
400
}
401
402
return sk->sk_prot->ioctl(sk, cmd, arg);
403
}
404
405
static int pn_socket_listen(struct socket *sock, int backlog)
406
{
407
struct sock *sk = sock->sk;
408
int err = 0;
409
410
if (pn_socket_autobind(sock))
411
return -ENOBUFS;
412
413
lock_sock(sk);
414
if (sock->state != SS_UNCONNECTED) {
415
err = -EINVAL;
416
goto out;
417
}
418
419
if (sk->sk_state != TCP_LISTEN) {
420
sk->sk_state = TCP_LISTEN;
421
sk->sk_ack_backlog = 0;
422
}
423
sk->sk_max_ack_backlog = backlog;
424
out:
425
release_sock(sk);
426
return err;
427
}
428
429
static int pn_socket_sendmsg(struct kiocb *iocb, struct socket *sock,
430
struct msghdr *m, size_t total_len)
431
{
432
struct sock *sk = sock->sk;
433
434
if (pn_socket_autobind(sock))
435
return -EAGAIN;
436
437
return sk->sk_prot->sendmsg(iocb, sk, m, total_len);
438
}
439
440
const struct proto_ops phonet_dgram_ops = {
441
.family = AF_PHONET,
442
.owner = THIS_MODULE,
443
.release = pn_socket_release,
444
.bind = pn_socket_bind,
445
.connect = sock_no_connect,
446
.socketpair = sock_no_socketpair,
447
.accept = sock_no_accept,
448
.getname = pn_socket_getname,
449
.poll = datagram_poll,
450
.ioctl = pn_socket_ioctl,
451
.listen = sock_no_listen,
452
.shutdown = sock_no_shutdown,
453
.setsockopt = sock_no_setsockopt,
454
.getsockopt = sock_no_getsockopt,
455
#ifdef CONFIG_COMPAT
456
.compat_setsockopt = sock_no_setsockopt,
457
.compat_getsockopt = sock_no_getsockopt,
458
#endif
459
.sendmsg = pn_socket_sendmsg,
460
.recvmsg = sock_common_recvmsg,
461
.mmap = sock_no_mmap,
462
.sendpage = sock_no_sendpage,
463
};
464
465
const struct proto_ops phonet_stream_ops = {
466
.family = AF_PHONET,
467
.owner = THIS_MODULE,
468
.release = pn_socket_release,
469
.bind = pn_socket_bind,
470
.connect = pn_socket_connect,
471
.socketpair = sock_no_socketpair,
472
.accept = pn_socket_accept,
473
.getname = pn_socket_getname,
474
.poll = pn_socket_poll,
475
.ioctl = pn_socket_ioctl,
476
.listen = pn_socket_listen,
477
.shutdown = sock_no_shutdown,
478
.setsockopt = sock_common_setsockopt,
479
.getsockopt = sock_common_getsockopt,
480
#ifdef CONFIG_COMPAT
481
.compat_setsockopt = compat_sock_common_setsockopt,
482
.compat_getsockopt = compat_sock_common_getsockopt,
483
#endif
484
.sendmsg = pn_socket_sendmsg,
485
.recvmsg = sock_common_recvmsg,
486
.mmap = sock_no_mmap,
487
.sendpage = sock_no_sendpage,
488
};
489
EXPORT_SYMBOL(phonet_stream_ops);
490
491
/* allocate port for a socket */
492
int pn_sock_get_port(struct sock *sk, unsigned short sport)
493
{
494
static int port_cur;
495
struct net *net = sock_net(sk);
496
struct pn_sock *pn = pn_sk(sk);
497
struct sockaddr_pn try_sa;
498
struct sock *tmpsk;
499
500
memset(&try_sa, 0, sizeof(struct sockaddr_pn));
501
try_sa.spn_family = AF_PHONET;
502
WARN_ON(!mutex_is_locked(&port_mutex));
503
if (!sport) {
504
/* search free port */
505
int port, pmin, pmax;
506
507
phonet_get_local_port_range(&pmin, &pmax);
508
for (port = pmin; port <= pmax; port++) {
509
port_cur++;
510
if (port_cur < pmin || port_cur > pmax)
511
port_cur = pmin;
512
513
pn_sockaddr_set_port(&try_sa, port_cur);
514
tmpsk = pn_find_sock_by_sa(net, &try_sa);
515
if (tmpsk == NULL) {
516
sport = port_cur;
517
goto found;
518
} else
519
sock_put(tmpsk);
520
}
521
} else {
522
/* try to find specific port */
523
pn_sockaddr_set_port(&try_sa, sport);
524
tmpsk = pn_find_sock_by_sa(net, &try_sa);
525
if (tmpsk == NULL)
526
/* No sock there! We can use that port... */
527
goto found;
528
else
529
sock_put(tmpsk);
530
}
531
/* the port must be in use already */
532
return -EADDRINUSE;
533
534
found:
535
pn->sobject = pn_object(pn_addr(pn->sobject), sport);
536
return 0;
537
}
538
EXPORT_SYMBOL(pn_sock_get_port);
539
540
#ifdef CONFIG_PROC_FS
541
static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
542
{
543
struct net *net = seq_file_net(seq);
544
struct hlist_head *hlist = pnsocks.hlist;
545
struct hlist_node *node;
546
struct sock *sknode;
547
unsigned h;
548
549
for (h = 0; h < PN_HASHSIZE; h++) {
550
sk_for_each_rcu(sknode, node, hlist) {
551
if (!net_eq(net, sock_net(sknode)))
552
continue;
553
if (!pos)
554
return sknode;
555
pos--;
556
}
557
hlist++;
558
}
559
return NULL;
560
}
561
562
static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
563
{
564
struct net *net = seq_file_net(seq);
565
566
do
567
sk = sk_next(sk);
568
while (sk && !net_eq(net, sock_net(sk)));
569
570
return sk;
571
}
572
573
static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
574
__acquires(rcu)
575
{
576
rcu_read_lock();
577
return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
578
}
579
580
static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
581
{
582
struct sock *sk;
583
584
if (v == SEQ_START_TOKEN)
585
sk = pn_sock_get_idx(seq, 0);
586
else
587
sk = pn_sock_get_next(seq, v);
588
(*pos)++;
589
return sk;
590
}
591
592
static void pn_sock_seq_stop(struct seq_file *seq, void *v)
593
__releases(rcu)
594
{
595
rcu_read_unlock();
596
}
597
598
static int pn_sock_seq_show(struct seq_file *seq, void *v)
599
{
600
int len;
601
602
if (v == SEQ_START_TOKEN)
603
seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue "
604
" uid inode ref pointer drops", &len);
605
else {
606
struct sock *sk = v;
607
struct pn_sock *pn = pn_sk(sk);
608
609
seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
610
"%d %pK %d%n",
611
sk->sk_protocol, pn->sobject, pn->dobject,
612
pn->resource, sk->sk_state,
613
sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
614
sock_i_uid(sk), sock_i_ino(sk),
615
atomic_read(&sk->sk_refcnt), sk,
616
atomic_read(&sk->sk_drops), &len);
617
}
618
seq_printf(seq, "%*s\n", 127 - len, "");
619
return 0;
620
}
621
622
static const struct seq_operations pn_sock_seq_ops = {
623
.start = pn_sock_seq_start,
624
.next = pn_sock_seq_next,
625
.stop = pn_sock_seq_stop,
626
.show = pn_sock_seq_show,
627
};
628
629
static int pn_sock_open(struct inode *inode, struct file *file)
630
{
631
return seq_open_net(inode, file, &pn_sock_seq_ops,
632
sizeof(struct seq_net_private));
633
}
634
635
const struct file_operations pn_sock_seq_fops = {
636
.owner = THIS_MODULE,
637
.open = pn_sock_open,
638
.read = seq_read,
639
.llseek = seq_lseek,
640
.release = seq_release_net,
641
};
642
#endif
643
644
static struct {
645
struct sock *sk[256];
646
} pnres;
647
648
/*
649
* Find and hold socket based on resource.
650
*/
651
struct sock *pn_find_sock_by_res(struct net *net, u8 res)
652
{
653
struct sock *sk;
654
655
if (!net_eq(net, &init_net))
656
return NULL;
657
658
rcu_read_lock();
659
sk = rcu_dereference(pnres.sk[res]);
660
if (sk)
661
sock_hold(sk);
662
rcu_read_unlock();
663
return sk;
664
}
665
666
static DEFINE_MUTEX(resource_mutex);
667
668
int pn_sock_bind_res(struct sock *sk, u8 res)
669
{
670
int ret = -EADDRINUSE;
671
672
if (!net_eq(sock_net(sk), &init_net))
673
return -ENOIOCTLCMD;
674
if (!capable(CAP_SYS_ADMIN))
675
return -EPERM;
676
if (pn_socket_autobind(sk->sk_socket))
677
return -EAGAIN;
678
679
mutex_lock(&resource_mutex);
680
if (pnres.sk[res] == NULL) {
681
sock_hold(sk);
682
rcu_assign_pointer(pnres.sk[res], sk);
683
ret = 0;
684
}
685
mutex_unlock(&resource_mutex);
686
return ret;
687
}
688
689
int pn_sock_unbind_res(struct sock *sk, u8 res)
690
{
691
int ret = -ENOENT;
692
693
if (!capable(CAP_SYS_ADMIN))
694
return -EPERM;
695
696
mutex_lock(&resource_mutex);
697
if (pnres.sk[res] == sk) {
698
rcu_assign_pointer(pnres.sk[res], NULL);
699
ret = 0;
700
}
701
mutex_unlock(&resource_mutex);
702
703
if (ret == 0) {
704
synchronize_rcu();
705
sock_put(sk);
706
}
707
return ret;
708
}
709
710
void pn_sock_unbind_all_res(struct sock *sk)
711
{
712
unsigned res, match = 0;
713
714
mutex_lock(&resource_mutex);
715
for (res = 0; res < 256; res++) {
716
if (pnres.sk[res] == sk) {
717
rcu_assign_pointer(pnres.sk[res], NULL);
718
match++;
719
}
720
}
721
mutex_unlock(&resource_mutex);
722
723
while (match > 0) {
724
__sock_put(sk);
725
match--;
726
}
727
/* Caller is responsible for RCU sync before final sock_put() */
728
}
729
730
#ifdef CONFIG_PROC_FS
731
static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
732
{
733
struct net *net = seq_file_net(seq);
734
unsigned i;
735
736
if (!net_eq(net, &init_net))
737
return NULL;
738
739
for (i = 0; i < 256; i++) {
740
if (pnres.sk[i] == NULL)
741
continue;
742
if (!pos)
743
return pnres.sk + i;
744
pos--;
745
}
746
return NULL;
747
}
748
749
static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
750
{
751
struct net *net = seq_file_net(seq);
752
unsigned i;
753
754
BUG_ON(!net_eq(net, &init_net));
755
756
for (i = (sk - pnres.sk) + 1; i < 256; i++)
757
if (pnres.sk[i])
758
return pnres.sk + i;
759
return NULL;
760
}
761
762
static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
763
__acquires(resource_mutex)
764
{
765
mutex_lock(&resource_mutex);
766
return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
767
}
768
769
static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
770
{
771
struct sock **sk;
772
773
if (v == SEQ_START_TOKEN)
774
sk = pn_res_get_idx(seq, 0);
775
else
776
sk = pn_res_get_next(seq, v);
777
(*pos)++;
778
return sk;
779
}
780
781
static void pn_res_seq_stop(struct seq_file *seq, void *v)
782
__releases(resource_mutex)
783
{
784
mutex_unlock(&resource_mutex);
785
}
786
787
static int pn_res_seq_show(struct seq_file *seq, void *v)
788
{
789
int len;
790
791
if (v == SEQ_START_TOKEN)
792
seq_printf(seq, "%s%n", "rs uid inode", &len);
793
else {
794
struct sock **psk = v;
795
struct sock *sk = *psk;
796
797
seq_printf(seq, "%02X %5d %lu%n",
798
(int) (psk - pnres.sk), sock_i_uid(sk),
799
sock_i_ino(sk), &len);
800
}
801
seq_printf(seq, "%*s\n", 63 - len, "");
802
return 0;
803
}
804
805
static const struct seq_operations pn_res_seq_ops = {
806
.start = pn_res_seq_start,
807
.next = pn_res_seq_next,
808
.stop = pn_res_seq_stop,
809
.show = pn_res_seq_show,
810
};
811
812
static int pn_res_open(struct inode *inode, struct file *file)
813
{
814
return seq_open_net(inode, file, &pn_res_seq_ops,
815
sizeof(struct seq_net_private));
816
}
817
818
const struct file_operations pn_res_seq_fops = {
819
.owner = THIS_MODULE,
820
.open = pn_res_open,
821
.read = seq_read,
822
.llseek = seq_lseek,
823
.release = seq_release_net,
824
};
825
#endif
826
827