root/netbt/l2cap_socket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. l2cap_usrreq
  2. l2cap_ctloutput
  3. l2cap_connecting
  4. l2cap_connected
  5. l2cap_disconnected
  6. l2cap_newconn
  7. l2cap_complete
  8. l2cap_linkmode
  9. l2cap_input

    1 /*      $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $    */
    2 /*      $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 2005 Iain Hibbert.
    6  * Copyright (c) 2006 Itronix Inc.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of Itronix Inc. may not be used to endorse
   18  *    or promote products derived from this software without specific
   19  *    prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   28  * ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   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/hci.h>          /* XXX for EPASSTHROUGH */
   54 #include <netbt/l2cap.h>
   55 
   56 /*
   57  * L2CAP Sockets
   58  *
   59  *      SOCK_SEQPACKET - normal L2CAP connection
   60  *
   61  *      SOCK_DGRAM - connectionless L2CAP - XXX not yet
   62  */
   63 
   64 static void l2cap_connecting(void *);
   65 static void l2cap_connected(void *);
   66 static void l2cap_disconnected(void *, int);
   67 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
   68 static void l2cap_complete(void *, int);
   69 static void l2cap_linkmode(void *, int);
   70 static void l2cap_input(void *, struct mbuf *);
   71 
   72 static const struct btproto l2cap_proto = {
   73         l2cap_connecting,
   74         l2cap_connected,
   75         l2cap_disconnected,
   76         l2cap_newconn,
   77         l2cap_complete,
   78         l2cap_linkmode,
   79         l2cap_input,
   80 };
   81 
   82 /* sysctl variables */
   83 int l2cap_sendspace = 4096;
   84 int l2cap_recvspace = 4096;
   85 
   86 /*
   87  * User Request.
   88  * up is socket
   89  * m is either
   90  *      optional mbuf chain containing message
   91  *      ioctl command (PRU_CONTROL)
   92  * nam is either
   93  *      optional mbuf chain containing an address
   94  *      ioctl data (PRU_CONTROL)
   95  *      optionally protocol number (PRU_ATTACH)
   96  *      message flags (PRU_RCVD)
   97  * ctl is either
   98  *      optional mbuf chain containing socket options
   99  *      optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
  100  * l is pointer to process requesting action (if any)
  101  *
  102  * we are responsible for disposing of m and ctl if
  103  * they are mbuf chains
  104  */
  105 int
  106 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
  107     struct mbuf *nam, struct mbuf *ctl)
  108 {
  109         struct l2cap_channel *pcb = up->so_pcb;
  110         struct sockaddr_bt *sa;
  111         struct mbuf *m0;
  112         int err = 0;
  113 
  114 #ifdef notyet                   /* XXX */
  115         DPRINTFN(2, "%s\n", prurequests[req]);
  116 #endif
  117 
  118         switch (req) {
  119         case PRU_CONTROL:
  120                 return EPASSTHROUGH;
  121 
  122 #ifdef notyet                   /* XXX */
  123         case PRU_PURGEIF:
  124                 return EOPNOTSUPP;
  125 #endif
  126 
  127         case PRU_ATTACH:
  128                 if (pcb != NULL)
  129                         return EINVAL;
  130 
  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_copym(m, 0, M_COPYALL, 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(request, socket, level, optname, opt)
  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, int level,
  268                 int optname, struct mbuf **opt)
  269 {
  270         struct l2cap_channel *pcb = so->so_pcb;
  271         struct mbuf *m;
  272         int err = 0;
  273 
  274 #ifdef notyet                   /* XXX */
  275         DPRINTFN(2, "%s\n", prcorequests[req]);
  276 #endif
  277 
  278         if (pcb == NULL)
  279                 return EINVAL;
  280 
  281         if (level != BTPROTO_L2CAP)
  282                 return ENOPROTOOPT;
  283 
  284         switch(req) {
  285         case PRCO_GETOPT:
  286                 m = m_get(M_WAIT, MT_SOOPTS);
  287                 m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
  288                 if (m->m_len == 0) {
  289                         m_freem(m);
  290                         m = NULL;
  291                         err = ENOPROTOOPT;
  292                 }
  293                 *opt = m;
  294                 break;
  295 
  296         case PRCO_SETOPT:
  297                 m = *opt;
  298                 KASSERT(m != NULL);
  299                 err = l2cap_setopt(pcb, optname, mtod(m, void *));
  300                 m_freem(m);
  301                 break;
  302 
  303         default:
  304                 err = ENOPROTOOPT;
  305                 break;
  306         }
  307 
  308         return err;
  309 }
  310 
  311 /**********************************************************************
  312  *
  313  *      L2CAP Protocol socket callbacks
  314  *
  315  */
  316 
  317 static void
  318 l2cap_connecting(void *arg)
  319 {
  320         struct socket *so = arg;
  321 
  322         DPRINTF("Connecting\n");
  323         soisconnecting(so);
  324 }
  325 
  326 static void
  327 l2cap_connected(void *arg)
  328 {
  329         struct socket *so = arg;
  330 
  331         DPRINTF("Connected\n");
  332         soisconnected(so);
  333 }
  334 
  335 static void
  336 l2cap_disconnected(void *arg, int err)
  337 {
  338         struct socket *so = arg;
  339 
  340         DPRINTF("Disconnected (%d)\n", err);
  341 
  342         so->so_error = err;
  343         soisdisconnected(so);
  344 }
  345 
  346 static void *
  347 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
  348     struct sockaddr_bt *raddr)
  349 {
  350         struct socket *so = arg;
  351 
  352         DPRINTF("New Connection\n");
  353         so = sonewconn(so, 0);
  354         if (so == NULL)
  355                 return NULL;
  356 
  357         soisconnecting(so);
  358 
  359         return so->so_pcb;
  360 }
  361 
  362 static void
  363 l2cap_complete(void *arg, int count)
  364 {
  365         struct socket *so = arg;
  366 
  367         while (count-- > 0)
  368                 sbdroprecord(&so->so_snd);
  369 
  370         sowwakeup(so);
  371 }
  372 
  373 static void
  374 l2cap_linkmode(void *arg, int new)
  375 {
  376         struct socket *so = arg;
  377         int mode;
  378 
  379         DPRINTF("auth %s, encrypt %s, secure %s\n",
  380                 (new & L2CAP_LM_AUTH ? "on" : "off"),
  381                 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
  382                 (new & L2CAP_LM_SECURE ? "on" : "off"));
  383 
  384         (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
  385         if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
  386             || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
  387             || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
  388                 l2cap_disconnect(so->so_pcb, 0);
  389 }
  390 
  391 static void
  392 l2cap_input(void *arg, struct mbuf *m)
  393 {
  394         struct socket *so = arg;
  395 
  396         if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
  397                 printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
  398                         __func__, m->m_pkthdr.len);
  399                 m_freem(m);
  400                 return;
  401         }
  402 
  403         DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
  404 
  405         sbappendrecord(&so->so_rcv, m);
  406         sorwakeup(so);
  407 }

/* [<][>][^][v][top][bottom][index][help] */