The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netbt/l2cap_socket.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: l2cap_socket.c,v 1.36 2019/01/28 12:53:01 martin Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2005 Iain Hibbert.
    5  * Copyright (c) 2006 Itronix Inc.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of Itronix Inc. may not be used to endorse
   17  *    or promote products derived from this software without specific
   18  *    prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   27  * ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.36 2019/01/28 12:53:01 martin Exp $");
   35 
   36 /* load symbolic names */
   37 #ifdef BLUETOOTH_DEBUG
   38 #define PRUREQUESTS
   39 #define PRCOREQUESTS
   40 #endif
   41 
   42 #include <sys/param.h>
   43 #include <sys/domain.h>
   44 #include <sys/kernel.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/proc.h>
   47 #include <sys/protosw.h>
   48 #include <sys/socket.h>
   49 #include <sys/socketvar.h>
   50 #include <sys/systm.h>
   51 
   52 #include <netbt/bluetooth.h>
   53 #include <netbt/l2cap.h>
   54 
   55 /*
   56  * L2CAP Sockets
   57  *
   58  *      SOCK_SEQPACKET - normal L2CAP connection
   59  *
   60  *      SOCK_DGRAM - connectionless L2CAP - XXX not yet
   61  */
   62 
   63 static void l2cap_connecting(void *);
   64 static void l2cap_connected(void *);
   65 static void l2cap_disconnected(void *, int);
   66 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
   67 static void l2cap_complete(void *, int);
   68 static void l2cap_linkmode(void *, int);
   69 static void l2cap_input(void *, struct mbuf *);
   70 
   71 static const struct btproto l2cap_proto = {
   72         l2cap_connecting,
   73         l2cap_connected,
   74         l2cap_disconnected,
   75         l2cap_newconn,
   76         l2cap_complete,
   77         l2cap_linkmode,
   78         l2cap_input,
   79 };
   80 
   81 /* sysctl variables */
   82 int l2cap_sendspace = 4096;
   83 int l2cap_recvspace = 4096;
   84 
   85 static int
   86 l2cap_attach(struct socket *so, int proto)
   87 {
   88         int error;
   89 
   90         KASSERT(so->so_pcb == NULL);
   91 
   92         if (so->so_lock == NULL) {
   93                 mutex_obj_hold(bt_lock);
   94                 so->so_lock = bt_lock;
   95                 solock(so);
   96         }
   97         KASSERT(solocked(so));
   98 
   99         /*
  100          * For L2CAP socket PCB we just use an l2cap_channel structure
  101          * since we have nothing to add..
  102          */
  103         error = soreserve(so, l2cap_sendspace, l2cap_recvspace);
  104         if (error)
  105                 return error;
  106 
  107         return l2cap_attach_pcb((struct l2cap_channel **)&so->so_pcb,
  108                                 &l2cap_proto, so);
  109 }
  110 
  111 static void
  112 l2cap_detach(struct socket *so)
  113 {
  114         KASSERT(so->so_pcb != NULL);
  115         l2cap_detach_pcb((struct l2cap_channel **)&so->so_pcb);
  116         KASSERT(so->so_pcb == NULL);
  117 }
  118 
  119 static int
  120 l2cap_accept(struct socket *so, struct sockaddr *nam)
  121 {
  122         struct l2cap_channel *pcb = so->so_pcb;
  123 
  124         KASSERT(solocked(so));
  125         KASSERT(nam != NULL);
  126 
  127         if (pcb == NULL)
  128                 return EINVAL;
  129 
  130         return l2cap_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam);
  131 }
  132 
  133 static int
  134 l2cap_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
  135 {
  136         struct l2cap_channel *pcb = so->so_pcb;
  137         struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
  138 
  139         KASSERT(solocked(so));
  140         KASSERT(nam != NULL);
  141 
  142         if (pcb == NULL)
  143                 return EINVAL;
  144 
  145         if (sa->bt_len != sizeof(struct sockaddr_bt))
  146                 return EINVAL;
  147 
  148         if (sa->bt_family != AF_BLUETOOTH)
  149                 return EAFNOSUPPORT;
  150 
  151         return l2cap_bind_pcb(pcb, sa);
  152 }
  153 
  154 static int
  155 l2cap_listen(struct socket *so, struct lwp *l)
  156 {
  157         struct l2cap_channel *pcb = so->so_pcb;
  158 
  159         KASSERT(solocked(so));
  160 
  161         if (pcb == NULL)
  162                 return EINVAL;
  163 
  164         return l2cap_listen_pcb(pcb);
  165 }
  166 
  167 static int
  168 l2cap_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
  169 {
  170         struct l2cap_channel *pcb = so->so_pcb;
  171         struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
  172 
  173         KASSERT(solocked(so));
  174         KASSERT(nam != NULL);
  175 
  176         if (pcb == NULL)
  177                 return EINVAL;
  178 
  179         if (sa->bt_len != sizeof(struct sockaddr_bt))
  180                 return EINVAL;
  181 
  182         if (sa->bt_family != AF_BLUETOOTH)
  183                 return EAFNOSUPPORT;
  184 
  185         soisconnecting(so);
  186         return l2cap_connect_pcb(pcb, sa);
  187 }
  188 
  189 static int
  190 l2cap_connect2(struct socket *so, struct socket *so2)
  191 {
  192         KASSERT(solocked(so));
  193 
  194         if (so->so_pcb == NULL)
  195                 return EINVAL;
  196 
  197         return EOPNOTSUPP;
  198 }
  199 
  200 static int
  201 l2cap_disconnect(struct socket *so)
  202 {
  203         struct l2cap_channel *pcb = so->so_pcb;
  204 
  205         KASSERT(solocked(so));
  206 
  207         if (pcb == NULL)
  208                 return EINVAL;
  209 
  210         soisdisconnecting(so);
  211         return l2cap_disconnect_pcb(pcb, so->so_linger);
  212 }
  213 
  214 static int
  215 l2cap_shutdown(struct socket *so)
  216 {
  217         KASSERT(solocked(so));
  218 
  219         socantsendmore(so);
  220         return 0;
  221 }
  222 
  223 static int
  224 l2cap_abort(struct socket *so)
  225 {
  226         struct l2cap_channel *pcb = so->so_pcb;
  227 
  228         KASSERT(solocked(so));
  229 
  230         if (pcb == NULL)
  231                 return EINVAL;
  232 
  233         l2cap_disconnect_pcb(pcb, 0);
  234         soisdisconnected(so);
  235         l2cap_detach(so);
  236         return 0;
  237 }
  238 
  239 static int
  240 l2cap_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
  241 {
  242         return EPASSTHROUGH;
  243 }
  244 
  245 static int
  246 l2cap_stat(struct socket *so, struct stat *ub)
  247 {
  248         KASSERT(solocked(so));
  249 
  250         return 0;
  251 }
  252 
  253 static int
  254 l2cap_peeraddr(struct socket *so, struct sockaddr *nam)
  255 {
  256         struct l2cap_channel *pcb = so->so_pcb;
  257 
  258         KASSERT(solocked(so));
  259         KASSERT(pcb != NULL);
  260         KASSERT(nam != NULL);
  261 
  262         return l2cap_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam);
  263 }
  264 
  265 static int
  266 l2cap_sockaddr(struct socket *so, struct sockaddr *nam)
  267 {
  268         struct l2cap_channel *pcb = so->so_pcb;
  269 
  270         KASSERT(solocked(so));
  271         KASSERT(pcb != NULL);
  272         KASSERT(nam != NULL);
  273 
  274         return l2cap_sockaddr_pcb(pcb, (struct sockaddr_bt *)nam);
  275 }
  276 
  277 static int
  278 l2cap_rcvd(struct socket *so, int flags, struct lwp *l)
  279 {
  280         KASSERT(solocked(so));
  281 
  282         return EOPNOTSUPP;
  283 }
  284 
  285 static int
  286 l2cap_recvoob(struct socket *so, struct mbuf *m, int flags)
  287 {
  288         KASSERT(solocked(so));
  289 
  290         return EOPNOTSUPP;
  291 }
  292 
  293 static int
  294 l2cap_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
  295     struct mbuf *control, struct lwp *l)
  296 {
  297         struct l2cap_channel *pcb = so->so_pcb;
  298         struct mbuf *m0;
  299         int error = 0;
  300 
  301         KASSERT(solocked(so));
  302         KASSERT(m != NULL);
  303 
  304         if (control)
  305                 m_freem(control);
  306 
  307         if (pcb == NULL) {
  308                 error = EINVAL;
  309                 goto release;
  310         }
  311 
  312         if (m->m_pkthdr.len == 0)
  313                 goto release;
  314 
  315         if (m->m_pkthdr.len > pcb->lc_omtu) {
  316                 error = EMSGSIZE;
  317                 goto release;
  318         }
  319 
  320         m0 = m_copypacket(m, M_DONTWAIT);
  321         if (m0 == NULL) {
  322                 error = ENOMEM;
  323                 goto release;
  324         }
  325 
  326         sbappendrecord(&so->so_snd, m);
  327         return l2cap_send_pcb(pcb, m0);
  328 
  329 release:
  330         if (m)
  331                 m_freem(m);
  332 
  333         return error;
  334 }
  335 
  336 static int
  337 l2cap_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
  338 {
  339         KASSERT(solocked(so));
  340 
  341         m_freem(m);
  342         m_freem(control);
  343 
  344         return EOPNOTSUPP;
  345 }
  346 
  347 static int
  348 l2cap_purgeif(struct socket *so, struct ifnet *ifp)
  349 {
  350 
  351         return EOPNOTSUPP;
  352 }
  353 
  354 /*
  355  * l2cap_ctloutput(req, socket, sockopt)
  356  *
  357  *      Apply configuration commands to channel. This corresponds to
  358  *      "Reconfigure Channel Request" in the L2CAP specification.
  359  */
  360 int
  361 l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
  362 {
  363         struct l2cap_channel *pcb = so->so_pcb;
  364         int err = 0;
  365 
  366         DPRINTFN(2, "%s\n", prcorequests[req]);
  367 
  368         if (pcb == NULL)
  369                 return EINVAL;
  370 
  371         if (sopt->sopt_level != BTPROTO_L2CAP)
  372                 return ENOPROTOOPT;
  373 
  374         switch(req) {
  375         case PRCO_GETOPT:
  376                 err = l2cap_getopt(pcb, sopt);
  377                 break;
  378 
  379         case PRCO_SETOPT:
  380                 err = l2cap_setopt(pcb, sopt);
  381                 break;
  382 
  383         default:
  384                 err = ENOPROTOOPT;
  385                 break;
  386         }
  387 
  388         return err;
  389 }
  390 
  391 /**********************************************************************
  392  *
  393  *      L2CAP Protocol socket callbacks
  394  *
  395  */
  396 
  397 static void
  398 l2cap_connecting(void *arg)
  399 {
  400         struct socket *so = arg;
  401 
  402         DPRINTF("Connecting\n");
  403         soisconnecting(so);
  404 }
  405 
  406 static void
  407 l2cap_connected(void *arg)
  408 {
  409         struct socket *so = arg;
  410 
  411         DPRINTF("Connected\n");
  412         soisconnected(so);
  413 }
  414 
  415 static void
  416 l2cap_disconnected(void *arg, int err)
  417 {
  418         struct socket *so = arg;
  419 
  420         DPRINTF("Disconnected (%d)\n", err);
  421 
  422         so->so_error = err;
  423         soisdisconnected(so);
  424 }
  425 
  426 static void *
  427 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
  428     struct sockaddr_bt *raddr)
  429 {
  430         struct socket *so = arg;
  431 
  432         DPRINTF("New Connection\n");
  433         so = sonewconn(so, false);
  434         if (so == NULL)
  435                 return NULL;
  436 
  437         soisconnecting(so);
  438 
  439         return so->so_pcb;
  440 }
  441 
  442 static void
  443 l2cap_complete(void *arg, int count)
  444 {
  445         struct socket *so = arg;
  446 
  447         while (count-- > 0)
  448                 sbdroprecord(&so->so_snd);
  449 
  450         sowwakeup(so);
  451 }
  452 
  453 static void
  454 l2cap_linkmode(void *arg, int new)
  455 {
  456         struct socket *so = arg;
  457         struct sockopt sopt;
  458         int mode;
  459 
  460         DPRINTF("auth %s, encrypt %s, secure %s\n",
  461                 (new & L2CAP_LM_AUTH ? "on" : "off"),
  462                 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
  463                 (new & L2CAP_LM_SECURE ? "on" : "off"));
  464 
  465         sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
  466         (void)l2cap_getopt(so->so_pcb, &sopt);
  467         (void)sockopt_getint(&sopt, &mode);
  468         sockopt_destroy(&sopt);
  469 
  470         if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
  471             || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
  472             || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
  473                 l2cap_disconnect_pcb(so->so_pcb, 0);
  474 }
  475 
  476 static void
  477 l2cap_input(void *arg, struct mbuf *m)
  478 {
  479         struct socket *so = arg;
  480 
  481         if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
  482                 printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
  483                         __func__, m->m_pkthdr.len);
  484                 m_freem(m);
  485                 return;
  486         }
  487 
  488         DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
  489 
  490         sbappendrecord(&so->so_rcv, m);
  491         sorwakeup(so);
  492 }
  493 
  494 PR_WRAP_USRREQS(l2cap)
  495 
  496 #define l2cap_attach            l2cap_attach_wrapper
  497 #define l2cap_detach            l2cap_detach_wrapper
  498 #define l2cap_accept            l2cap_accept_wrapper
  499 #define l2cap_bind              l2cap_bind_wrapper
  500 #define l2cap_listen            l2cap_listen_wrapper
  501 #define l2cap_connect           l2cap_connect_wrapper
  502 #define l2cap_connect2          l2cap_connect2_wrapper
  503 #define l2cap_disconnect        l2cap_disconnect_wrapper
  504 #define l2cap_shutdown          l2cap_shutdown_wrapper
  505 #define l2cap_abort             l2cap_abort_wrapper
  506 #define l2cap_ioctl             l2cap_ioctl_wrapper
  507 #define l2cap_stat              l2cap_stat_wrapper
  508 #define l2cap_peeraddr          l2cap_peeraddr_wrapper
  509 #define l2cap_sockaddr          l2cap_sockaddr_wrapper
  510 #define l2cap_rcvd              l2cap_rcvd_wrapper
  511 #define l2cap_recvoob           l2cap_recvoob_wrapper
  512 #define l2cap_send              l2cap_send_wrapper
  513 #define l2cap_sendoob           l2cap_sendoob_wrapper
  514 #define l2cap_purgeif           l2cap_purgeif_wrapper
  515 
  516 const struct pr_usrreqs l2cap_usrreqs = {
  517         .pr_attach      = l2cap_attach,
  518         .pr_detach      = l2cap_detach,
  519         .pr_accept      = l2cap_accept,
  520         .pr_bind        = l2cap_bind,
  521         .pr_listen      = l2cap_listen,
  522         .pr_connect     = l2cap_connect,
  523         .pr_connect2    = l2cap_connect2,
  524         .pr_disconnect  = l2cap_disconnect,
  525         .pr_shutdown    = l2cap_shutdown,
  526         .pr_abort       = l2cap_abort,
  527         .pr_ioctl       = l2cap_ioctl,
  528         .pr_stat        = l2cap_stat,
  529         .pr_peeraddr    = l2cap_peeraddr,
  530         .pr_sockaddr    = l2cap_sockaddr,
  531         .pr_rcvd        = l2cap_rcvd,
  532         .pr_recvoob     = l2cap_recvoob,
  533         .pr_send        = l2cap_send,
  534         .pr_sendoob     = l2cap_sendoob,
  535         .pr_purgeif     = l2cap_purgeif,
  536 };

Cache object: 4df29600e0ad760b6ecd246948079d4b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.