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.9 2008/08/06 15:01:24 plunky 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.9 2008/08/06 15:01:24 plunky 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 /*
   86  * User Request.
   87  * up is socket
   88  * m is either
   89  *      optional mbuf chain containing message
   90  *      ioctl command (PRU_CONTROL)
   91  * nam is either
   92  *      optional mbuf chain containing an address
   93  *      ioctl data (PRU_CONTROL)
   94  *      optionally protocol number (PRU_ATTACH)
   95  *      message flags (PRU_RCVD)
   96  * ctl is either
   97  *      optional mbuf chain containing socket options
   98  *      optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
   99  * l is pointer to process requesting action (if any)
  100  *
  101  * we are responsible for disposing of m and ctl if
  102  * they are mbuf chains
  103  */
  104 int
  105 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
  106     struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
  107 {
  108         struct l2cap_channel *pcb = up->so_pcb;
  109         struct sockaddr_bt *sa;
  110         struct mbuf *m0;
  111         int err = 0;
  112 
  113         DPRINTFN(2, "%s\n", prurequests[req]);
  114 
  115         switch (req) {
  116         case PRU_CONTROL:
  117                 return EPASSTHROUGH;
  118 
  119         case PRU_PURGEIF:
  120                 return EOPNOTSUPP;
  121 
  122         case PRU_ATTACH:
  123                 if (up->so_lock == NULL) {
  124                         mutex_obj_hold(bt_lock);
  125                         up->so_lock = bt_lock;
  126                         solock(up);
  127                 }
  128                 KASSERT(solocked(up));
  129                 if (pcb != NULL)
  130                         return EINVAL;
  131                 /*
  132                  * For L2CAP socket PCB we just use an l2cap_channel structure
  133                  * since we have nothing to add..
  134                  */
  135                 err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
  136                 if (err)
  137                         return err;
  138 
  139                 return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
  140                                         &l2cap_proto, up);
  141         }
  142 
  143         if (pcb == NULL) {
  144                 err = EINVAL;
  145                 goto release;
  146         }
  147 
  148         switch(req) {
  149         case PRU_DISCONNECT:
  150                 soisdisconnecting(up);
  151                 return l2cap_disconnect(pcb, up->so_linger);
  152 
  153         case PRU_ABORT:
  154                 l2cap_disconnect(pcb, 0);
  155                 soisdisconnected(up);
  156                 /* fall through to */
  157         case PRU_DETACH:
  158                 return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
  159 
  160         case PRU_BIND:
  161                 KASSERT(nam != NULL);
  162                 sa = mtod(nam, struct sockaddr_bt *);
  163 
  164                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  165                         return EINVAL;
  166 
  167                 if (sa->bt_family != AF_BLUETOOTH)
  168                         return EAFNOSUPPORT;
  169 
  170                 return l2cap_bind(pcb, sa);
  171 
  172         case PRU_CONNECT:
  173                 KASSERT(nam != NULL);
  174                 sa = mtod(nam, struct sockaddr_bt *);
  175 
  176                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  177                         return EINVAL;
  178 
  179                 if (sa->bt_family != AF_BLUETOOTH)
  180                         return EAFNOSUPPORT;
  181 
  182                 soisconnecting(up);
  183                 return l2cap_connect(pcb, sa);
  184 
  185         case PRU_PEERADDR:
  186                 KASSERT(nam != NULL);
  187                 sa = mtod(nam, struct sockaddr_bt *);
  188                 nam->m_len = sizeof(struct sockaddr_bt);
  189                 return l2cap_peeraddr(pcb, sa);
  190 
  191         case PRU_SOCKADDR:
  192                 KASSERT(nam != NULL);
  193                 sa = mtod(nam, struct sockaddr_bt *);
  194                 nam->m_len = sizeof(struct sockaddr_bt);
  195                 return l2cap_sockaddr(pcb, sa);
  196 
  197         case PRU_SHUTDOWN:
  198                 socantsendmore(up);
  199                 break;
  200 
  201         case PRU_SEND:
  202                 KASSERT(m != NULL);
  203                 if (m->m_pkthdr.len == 0)
  204                         break;
  205 
  206                 if (m->m_pkthdr.len > pcb->lc_omtu) {
  207                         err = EMSGSIZE;
  208                         break;
  209                 }
  210 
  211                 m0 = m_copypacket(m, M_DONTWAIT);
  212                 if (m0 == NULL) {
  213                         err = ENOMEM;
  214                         break;
  215                 }
  216 
  217                 if (ctl)        /* no use for that */
  218                         m_freem(ctl);
  219 
  220                 sbappendrecord(&up->so_snd, m);
  221                 return l2cap_send(pcb, m0);
  222 
  223         case PRU_SENSE:
  224                 return 0;               /* (no release) */
  225 
  226         case PRU_RCVD:
  227         case PRU_RCVOOB:
  228                 return EOPNOTSUPP;      /* (no release) */
  229 
  230         case PRU_LISTEN:
  231                 return l2cap_listen(pcb);
  232 
  233         case PRU_ACCEPT:
  234                 KASSERT(nam != NULL);
  235                 sa = mtod(nam, struct sockaddr_bt *);
  236                 nam->m_len = sizeof(struct sockaddr_bt);
  237                 return l2cap_peeraddr(pcb, sa);
  238 
  239         case PRU_CONNECT2:
  240         case PRU_SENDOOB:
  241         case PRU_FASTTIMO:
  242         case PRU_SLOWTIMO:
  243         case PRU_PROTORCV:
  244         case PRU_PROTOSEND:
  245                 err = EOPNOTSUPP;
  246                 break;
  247 
  248         default:
  249                 UNKNOWN(req);
  250                 err = EOPNOTSUPP;
  251                 break;
  252         }
  253 
  254 release:
  255         if (m) m_freem(m);
  256         if (ctl) m_freem(ctl);
  257         return err;
  258 }
  259 
  260 /*
  261  * l2cap_ctloutput(req, socket, sockopt)
  262  *
  263  *      Apply configuration commands to channel. This corresponds to
  264  *      "Reconfigure Channel Request" in the L2CAP specification.
  265  */
  266 int
  267 l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
  268 {
  269         struct l2cap_channel *pcb = so->so_pcb;
  270         int err = 0;
  271 
  272         DPRINTFN(2, "%s\n", prcorequests[req]);
  273 
  274         if (pcb == NULL)
  275                 return EINVAL;
  276 
  277         if (sopt->sopt_level != BTPROTO_L2CAP)
  278                 return ENOPROTOOPT;
  279 
  280         switch(req) {
  281         case PRCO_GETOPT:
  282                 err = l2cap_getopt(pcb, sopt);
  283                 break;
  284 
  285         case PRCO_SETOPT:
  286                 err = l2cap_setopt(pcb, sopt);
  287                 break;
  288 
  289         default:
  290                 err = ENOPROTOOPT;
  291                 break;
  292         }
  293 
  294         return err;
  295 }
  296 
  297 /**********************************************************************
  298  *
  299  *      L2CAP Protocol socket callbacks
  300  *
  301  */
  302 
  303 static void
  304 l2cap_connecting(void *arg)
  305 {
  306         struct socket *so = arg;
  307 
  308         DPRINTF("Connecting\n");
  309         soisconnecting(so);
  310 }
  311 
  312 static void
  313 l2cap_connected(void *arg)
  314 {
  315         struct socket *so = arg;
  316 
  317         DPRINTF("Connected\n");
  318         soisconnected(so);
  319 }
  320 
  321 static void
  322 l2cap_disconnected(void *arg, int err)
  323 {
  324         struct socket *so = arg;
  325 
  326         DPRINTF("Disconnected (%d)\n", err);
  327 
  328         so->so_error = err;
  329         soisdisconnected(so);
  330 }
  331 
  332 static void *
  333 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
  334     struct sockaddr_bt *raddr)
  335 {
  336         struct socket *so = arg;
  337 
  338         DPRINTF("New Connection\n");
  339         so = sonewconn(so, 0);
  340         if (so == NULL)
  341                 return NULL;
  342 
  343         soisconnecting(so);
  344 
  345         return so->so_pcb;
  346 }
  347 
  348 static void
  349 l2cap_complete(void *arg, int count)
  350 {
  351         struct socket *so = arg;
  352 
  353         while (count-- > 0)
  354                 sbdroprecord(&so->so_snd);
  355 
  356         sowwakeup(so);
  357 }
  358 
  359 static void
  360 l2cap_linkmode(void *arg, int new)
  361 {
  362         struct socket *so = arg;
  363         struct sockopt sopt;
  364         int mode;
  365 
  366         DPRINTF("auth %s, encrypt %s, secure %s\n",
  367                 (new & L2CAP_LM_AUTH ? "on" : "off"),
  368                 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
  369                 (new & L2CAP_LM_SECURE ? "on" : "off"));
  370 
  371         sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
  372         (void)l2cap_getopt(so->so_pcb, &sopt);
  373         (void)sockopt_getint(&sopt, &mode);
  374         sockopt_destroy(&sopt);
  375 
  376         if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
  377             || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
  378             || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
  379                 l2cap_disconnect(so->so_pcb, 0);
  380 }
  381 
  382 static void
  383 l2cap_input(void *arg, struct mbuf *m)
  384 {
  385         struct socket *so = arg;
  386 
  387         if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
  388                 printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
  389                         __func__, m->m_pkthdr.len);
  390                 m_freem(m);
  391                 return;
  392         }
  393 
  394         DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
  395 
  396         sbappendrecord(&so->so_rcv, m);
  397         sorwakeup(so);
  398 }

Cache object: cdbdbb6fcef6e2b1fee16dbf8ecc43dc


[ 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.