~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/phonet/socket.c

Version: ~ [ linux-5.9-rc5 ] ~ [ linux-5.8.10 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.66 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.146 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.198 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.236 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.236 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp