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 /* $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 /* load symbolic names */
   35 #ifdef BLUETOOTH_DEBUG
   36 #define PRUREQUESTS
   37 #define PRCOREQUESTS
   38 #endif
   39 
   40 #include <sys/param.h>
   41 #include <sys/domain.h>
   42 #include <sys/kernel.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/proc.h>
   45 #include <sys/protosw.h>
   46 #include <sys/socket.h>
   47 #include <sys/socketvar.h>
   48 #include <sys/systm.h>
   49 
   50 #include <sys/msgport2.h>
   51 
   52 #include <vm/vm_zone.h>
   53 
   54 #include <netbt/bluetooth.h>
   55 #include <netbt/hci.h>          /* XXX for EPASSTHROUGH */
   56 #include <netbt/l2cap.h>
   57 
   58 /*
   59  * L2CAP Sockets
   60  *
   61  *      SOCK_SEQPACKET - normal L2CAP connection
   62  *
   63  *      SOCK_DGRAM - connectionless L2CAP - XXX not yet
   64  */
   65 
   66 static void l2cap_connecting(void *);
   67 static void l2cap_connected(void *);
   68 static void l2cap_disconnected(void *, int);
   69 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
   70 static void l2cap_complete(void *, int);
   71 static void l2cap_linkmode(void *, int);
   72 static void l2cap_input(void *, struct mbuf *);
   73 
   74 static const struct btproto l2cap_proto = {
   75         l2cap_connecting,
   76         l2cap_connected,
   77         l2cap_disconnected,
   78         l2cap_newconn,
   79         l2cap_complete,
   80         l2cap_linkmode,
   81         l2cap_input,
   82 };
   83 
   84 /* sysctl variables */
   85 int l2cap_sendspace = 4096;
   86 int l2cap_recvspace = 4096;
   87 
   88 /*
   89  * l2cap_ctloutput(request, socket, level, optname, opt)
   90  *
   91  *      Apply configuration commands to channel. This corresponds to
   92  *      "Reconfigure Channel Request" in the L2CAP specification.
   93  */
   94 void
   95 l2cap_ctloutput(netmsg_t msg)
   96 {
   97         struct socket *so = msg->ctloutput.base.nm_so;
   98         struct sockopt *sopt = msg->ctloutput.nm_sopt;
   99         struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
  100         struct mbuf *m;
  101         int error = 0;
  102 
  103 #ifdef notyet                   /* XXX */
  104         DPRINTFN(2, "%s\n", prcorequests[req]);
  105 #endif
  106 
  107         if (pcb == NULL) {
  108                 error = EINVAL;
  109                 goto out;
  110         }
  111 
  112         if (sopt->sopt_level != BTPROTO_L2CAP) {
  113                 error = ENOPROTOOPT;
  114                 goto out;
  115         }
  116 
  117         switch(sopt->sopt_dir) {
  118         case PRCO_GETOPT:
  119                 m = m_get(M_NOWAIT, MT_DATA);
  120                 if (m == NULL) {
  121                     error = ENOMEM;
  122                     break;
  123                 }
  124                 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
  125                 if (m->m_len == 0) {
  126                         m_freem(m);
  127                         m = NULL;
  128                         error = ENOPROTOOPT;
  129                 }
  130                 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
  131                 break;
  132 
  133         case PRCO_SETOPT:
  134                 error = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
  135                 break;
  136 
  137         default:
  138                 error = ENOPROTOOPT;
  139                 break;
  140         }
  141 out:
  142         lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
  143 }
  144 
  145 /**********************************************************************
  146  *
  147  *      L2CAP Protocol socket callbacks
  148  *
  149  */
  150 
  151 static void
  152 l2cap_connecting(void *arg)
  153 {
  154         struct socket *so = arg;
  155 
  156         DPRINTF("Connecting\n");
  157         soisconnecting(so);
  158 }
  159 
  160 static void
  161 l2cap_connected(void *arg)
  162 {
  163         struct socket *so = arg;
  164 
  165         DPRINTF("Connected\n");
  166         soisconnected(so);
  167 }
  168 
  169 static void
  170 l2cap_disconnected(void *arg, int err)
  171 {
  172         struct socket *so = arg;
  173 
  174         DPRINTF("Disconnected (%d)\n", err);
  175 
  176         so->so_error = err;
  177         soisdisconnected(so);
  178 }
  179 
  180 static void *
  181 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
  182     struct sockaddr_bt *raddr)
  183 {
  184         struct socket *so = arg;
  185 
  186         DPRINTF("New Connection\n");
  187         so = sonewconn(so, 0);
  188         if (so == NULL)
  189                 return NULL;
  190 
  191         soisconnecting(so);
  192 
  193         return so->so_pcb;
  194 }
  195 
  196 static void
  197 l2cap_complete(void *arg, int count)
  198 {
  199         struct socket *so = arg;
  200 
  201         while (count-- > 0)
  202                 sbdroprecord(&so->so_snd.sb);
  203 
  204         sowwakeup(so);
  205 }
  206 
  207 static void
  208 l2cap_linkmode(void *arg, int new)
  209 {
  210         struct socket *so = arg;
  211         int mode;
  212 
  213         DPRINTF("auth %s, encrypt %s, secure %s\n",
  214                 (new & L2CAP_LM_AUTH ? "on" : "off"),
  215                 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
  216                 (new & L2CAP_LM_SECURE ? "on" : "off"));
  217 
  218         (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
  219         if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
  220             || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
  221             || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
  222                 l2cap_disconnect(so->so_pcb, 0);
  223 }
  224 
  225 static void
  226 l2cap_input(void *arg, struct mbuf *m)
  227 {
  228         struct socket *so = arg;
  229 
  230         if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
  231                 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
  232                         __func__, m->m_pkthdr.len);
  233                 m_freem(m);
  234                 return;
  235         }
  236 
  237         DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
  238 
  239         sbappendrecord(&so->so_rcv.sb, m);
  240         sorwakeup(so);
  241 }
  242 
  243 
  244 /*
  245  * Implementation of usrreqs.
  246  */
  247 static void
  248 l2cap_sdetach(netmsg_t msg)
  249 {
  250         struct socket *so = msg->detach.base.nm_so;
  251         int error;
  252 
  253         error = l2cap_detach((struct l2cap_channel **)&so->so_pcb);
  254         lwkt_replymsg(&msg->detach.base.lmsg, error);
  255 }
  256 
  257 /*
  258  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
  259  *       will sofree() it when we return.
  260  */
  261 static void
  262 l2cap_sabort(netmsg_t msg)
  263 {
  264         struct socket *so = msg->abort.base.nm_so;
  265         struct l2cap_channel *pcb = so->so_pcb;
  266         
  267         l2cap_disconnect(pcb, 0);
  268         soisdisconnected(so);
  269         
  270         l2cap_sdetach(msg);
  271         /* msg invalid now */
  272 }
  273 
  274 static void
  275 l2cap_sdisconnect(netmsg_t msg)
  276 {
  277         struct socket *so = msg->disconnect.base.nm_so;
  278         struct l2cap_channel *pcb = so->so_pcb;
  279         int error;
  280         
  281         soisdisconnecting(so);
  282         
  283         error = l2cap_disconnect(pcb, so->so_linger);
  284         lwkt_replymsg(&msg->disconnect.base.lmsg, error);
  285 }
  286 
  287 static void
  288 l2cap_scontrol(netmsg_t msg)
  289 {
  290         lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
  291 }
  292 
  293 static void
  294 l2cap_sattach(netmsg_t msg)
  295 {
  296         struct socket *so = msg->attach.base.nm_so;
  297         struct l2cap_channel *pcb = so->so_pcb;
  298         int error;
  299 
  300         if (pcb != NULL) {
  301                 error = EINVAL;
  302                 goto out;
  303         }
  304 
  305         /*
  306          * For L2CAP socket PCB we just use an l2cap_channel structure
  307          * since we have nothing to add..
  308          */
  309         error = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
  310         if (error == 0) {
  311                 error = l2cap_attach((struct l2cap_channel **)&so->so_pcb,
  312                                      &l2cap_proto, so);
  313         }
  314 out:
  315         lwkt_replymsg(&msg->attach.base.lmsg, error);
  316 }
  317 
  318 static void
  319 l2cap_sbind (netmsg_t msg)
  320 {
  321         struct socket *so = msg->bind.base.nm_so;
  322         struct sockaddr *nam = msg->bind.nm_nam;
  323         struct l2cap_channel *pcb = so->so_pcb;
  324         struct sockaddr_bt *sa;
  325         int error;
  326 
  327         KKASSERT(nam != NULL);
  328         sa = (struct sockaddr_bt *)nam;
  329 
  330         if (sa->bt_len != sizeof(struct sockaddr_bt)) {
  331                 error = EINVAL;
  332         } else if (sa->bt_family != AF_BLUETOOTH) {
  333                 error = EAFNOSUPPORT;
  334         } else {
  335                 error = l2cap_bind(pcb, sa);
  336         }
  337         lwkt_replymsg(&msg->bind.base.lmsg, error);
  338 }
  339 
  340 static void
  341 l2cap_sconnect(netmsg_t msg)
  342 {
  343         struct socket *so = msg->connect.base.nm_so;
  344         struct sockaddr *nam = msg->connect.nm_nam;
  345         struct l2cap_channel *pcb = so->so_pcb;
  346         struct sockaddr_bt *sa;
  347         int error;
  348 
  349         KKASSERT(nam != NULL);
  350         sa = (struct sockaddr_bt *)nam;
  351 
  352         if (sa->bt_len != sizeof(struct sockaddr_bt)) {
  353                 error = EINVAL;
  354         } else if (sa->bt_family != AF_BLUETOOTH) {
  355                 error = EAFNOSUPPORT;
  356         } else {
  357                 soisconnecting(so);
  358                 error = l2cap_connect(pcb, sa);
  359         }
  360         lwkt_replymsg(&msg->connect.base.lmsg, error);
  361 }
  362 
  363 static void
  364 l2cap_speeraddr(netmsg_t msg)
  365 {
  366         struct socket *so = msg->peeraddr.base.nm_so;
  367         struct sockaddr **nam = msg->peeraddr.nm_nam;
  368         struct l2cap_channel *pcb = so->so_pcb;
  369         struct sockaddr_bt *sa, ssa;
  370         int error;
  371 
  372         sa = &ssa;
  373         bzero(sa, sizeof *sa);
  374         sa->bt_len = sizeof(struct sockaddr_bt);
  375         sa->bt_family = AF_BLUETOOTH;
  376         error = l2cap_peeraddr(pcb, sa);
  377         *nam = dup_sockaddr((struct sockaddr *)sa);
  378 
  379         lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
  380 }
  381 
  382 static void
  383 l2cap_ssockaddr(netmsg_t msg)
  384 {
  385         struct socket *so = msg->sockaddr.base.nm_so;
  386         struct sockaddr **nam = msg->sockaddr.nm_nam;
  387         struct l2cap_channel *pcb = so->so_pcb;
  388         struct sockaddr_bt *sa, ssa;
  389         int error;
  390 
  391         sa = &ssa;
  392         bzero(sa, sizeof *sa);
  393         sa->bt_len = sizeof(struct sockaddr_bt);
  394         sa->bt_family = AF_BLUETOOTH;
  395         error = l2cap_sockaddr(pcb, sa);
  396         *nam = dup_sockaddr((struct sockaddr *)sa);
  397 
  398         lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
  399 }
  400 
  401 static void
  402 l2cap_sshutdown(netmsg_t msg)
  403 {
  404         struct socket *so = msg->shutdown.base.nm_so;
  405 
  406         socantsendmore(so);
  407 
  408         lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
  409 }
  410 
  411 static void
  412 l2cap_ssend(netmsg_t msg)
  413 {
  414         struct socket *so = msg->send.base.nm_so;
  415         struct mbuf *m = msg->send.nm_m;
  416         struct mbuf *control = msg->send.nm_control;
  417         struct l2cap_channel *pcb = so->so_pcb;
  418         struct mbuf *m0;
  419         int error;
  420 
  421         KKASSERT(m != NULL);
  422         if (m->m_pkthdr.len == 0) {
  423                 error = 0;
  424                 goto out;
  425         }
  426 
  427         if (m->m_pkthdr.len > pcb->lc_omtu) {
  428                 error = EMSGSIZE;
  429                 goto out;
  430         }
  431 
  432         m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
  433         if (m0 == NULL) {
  434                 error = ENOMEM;
  435                 goto out;
  436         }
  437 
  438         m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
  439         if (m0 == NULL) {
  440                 error = ENOMEM;
  441                 goto out;
  442         }
  443 
  444         /* no use for that */
  445         if (control) {
  446                 m_freem(control);
  447                 control = NULL;
  448         }
  449         sbappendrecord(&so->so_snd.sb, m);
  450         error = l2cap_send(pcb, m0);
  451         m = NULL;
  452 out:
  453         if (m)
  454                 m_freem(m);
  455         if (control)
  456                 m_freem(control);
  457 
  458         lwkt_replymsg(&msg->send.base.lmsg, error);
  459 }
  460 
  461 static void
  462 l2cap_saccept(netmsg_t msg)
  463 {
  464         struct socket *so = msg->accept.base.nm_so;
  465         struct sockaddr **nam = msg->accept.nm_nam;
  466         struct l2cap_channel *pcb = so->so_pcb;
  467         struct sockaddr_bt sa;
  468         int error;
  469                 
  470         KKASSERT(nam != NULL);
  471         
  472         bzero(&sa, sizeof (sa) );
  473         sa.bt_len = sizeof(struct sockaddr_bt);
  474         sa.bt_family = AF_BLUETOOTH;
  475 
  476         error = l2cap_peeraddr(pcb, &sa);
  477         *nam = dup_sockaddr((struct sockaddr *)&sa);
  478 
  479         lwkt_replymsg(&msg->accept.base.lmsg, error);
  480 }
  481 
  482 static void
  483 l2cap_slisten(netmsg_t msg)
  484 {
  485         struct socket *so = msg->listen.base.nm_so;
  486         struct l2cap_channel *pcb = so->so_pcb;
  487         int error;
  488 
  489         error = l2cap_listen(pcb);
  490         lwkt_replymsg(&msg->accept.base.lmsg, error);
  491 }
  492 
  493 
  494 struct pr_usrreqs l2cap_usrreqs = {
  495         .pru_abort = l2cap_sabort,
  496         .pru_accept = l2cap_saccept,
  497         .pru_attach = l2cap_sattach,
  498         .pru_bind = l2cap_sbind,
  499         .pru_connect = l2cap_sconnect,
  500         .pru_connect2 = pr_generic_notsupp,
  501         .pru_control = l2cap_scontrol,
  502         .pru_detach = l2cap_sdetach,
  503         .pru_disconnect = l2cap_sdisconnect,
  504         .pru_listen = l2cap_slisten,
  505         .pru_peeraddr = l2cap_speeraddr,
  506         .pru_rcvd = pr_generic_notsupp,
  507         .pru_rcvoob = pr_generic_notsupp,
  508         .pru_send = l2cap_ssend,
  509         .pru_sense = pru_sense_null,
  510         .pru_shutdown = l2cap_sshutdown,
  511         .pru_sockaddr = l2cap_ssockaddr,
  512         .pru_sosend = sosend,
  513         .pru_soreceive = soreceive
  514 };

Cache object: 3791bd39a63e6683cd1034e307e87320


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