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/rfcomm_upper.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: rfcomm_upper.c,v 1.23 2018/09/03 16:29:36 riastradh Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 2006 Itronix Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Iain Hibbert for Itronix Inc.
    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 __KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.23 2018/09/03 16:29:36 riastradh Exp $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/kmem.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/systm.h>
   43 
   44 #include <netbt/bluetooth.h>
   45 #include <netbt/hci.h>
   46 #include <netbt/l2cap.h>
   47 #include <netbt/rfcomm.h>
   48 
   49 /****************************************************************************
   50  *
   51  *      RFCOMM DLC - Upper Protocol API
   52  *
   53  * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
   54  * but it is should be possible to provide a pseudo-device for a direct
   55  * tty interface.
   56  */
   57 
   58 /*
   59  * rfcomm_attach_pcb(handle, proto, upper)
   60  *
   61  * attach a new RFCOMM DLC to handle, populate with reasonable defaults
   62  */
   63 int
   64 rfcomm_attach_pcb(struct rfcomm_dlc **handle,
   65                 const struct btproto *proto, void *upper)
   66 {
   67         struct rfcomm_dlc *dlc;
   68 
   69         KASSERT(handle != NULL);
   70         KASSERT(proto != NULL);
   71         KASSERT(upper != NULL);
   72 
   73         dlc = kmem_intr_zalloc(sizeof(struct rfcomm_dlc), KM_NOSLEEP);
   74         if (dlc == NULL)
   75                 return ENOMEM;
   76 
   77         dlc->rd_state = RFCOMM_DLC_CLOSED;
   78         dlc->rd_mtu = rfcomm_mtu_default;
   79 
   80         dlc->rd_proto = proto;
   81         dlc->rd_upper = upper;
   82 
   83         dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
   84         dlc->rd_laddr.bt_family = AF_BLUETOOTH;
   85         dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
   86 
   87         dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
   88         dlc->rd_raddr.bt_family = AF_BLUETOOTH;
   89         dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
   90 
   91         dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
   92 
   93         callout_init(&dlc->rd_timeout, 0);
   94         callout_setfunc(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
   95 
   96         *handle = dlc;
   97         return 0;
   98 }
   99 
  100 /*
  101  * rfcomm_bind_pcb(dlc, sockaddr)
  102  *
  103  * bind DLC to local address
  104  */
  105 int
  106 rfcomm_bind_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  107 {
  108 
  109         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  110                 return EINVAL;
  111 
  112         memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
  113         return 0;
  114 }
  115 
  116 /*
  117  * rfcomm_sockaddr_pcb(dlc, sockaddr)
  118  *
  119  * return local address
  120  */
  121 int
  122 rfcomm_sockaddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  123 {
  124 
  125         memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
  126         return 0;
  127 }
  128 
  129 /*
  130  * rfcomm_connect_pcb(dlc, sockaddr)
  131  *
  132  * Initiate connection of RFCOMM DLC to remote address.
  133  */
  134 int
  135 rfcomm_connect_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
  136 {
  137         struct rfcomm_session *rs;
  138         int err = 0;
  139 
  140         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  141                 return EISCONN;
  142 
  143         memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
  144 
  145         if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
  146             || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
  147             || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
  148                 return EDESTADDRREQ;
  149 
  150         if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
  151                 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
  152         else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
  153             && (dlc->rd_raddr.bt_psm < 0x1001
  154             || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
  155                 return EINVAL;
  156 
  157         /*
  158          * We are allowed only one RFCOMM session between any 2 Bluetooth
  159          * devices, so see if there is a session already otherwise create
  160          * one and set it connecting.
  161          */
  162         rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
  163         if (rs == NULL) {
  164                 rs = rfcomm_session_alloc(&rfcomm_session_active,
  165                                                 &dlc->rd_laddr);
  166                 if (rs == NULL)
  167                         return ENOMEM;
  168 
  169                 rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
  170                 rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
  171 
  172                 err = l2cap_connect_pcb(rs->rs_l2cap, &dlc->rd_raddr);
  173                 if (err) {
  174                         rfcomm_session_free(rs);
  175                         return err;
  176                 }
  177 
  178                 /*
  179                  * This session will start up automatically when its
  180                  * L2CAP channel is connected.
  181                  */
  182         }
  183 
  184         /* construct DLC */
  185         dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
  186         if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
  187                 return EBUSY;
  188 
  189         l2cap_sockaddr_pcb(rs->rs_l2cap, &dlc->rd_laddr);
  190 
  191         /*
  192          * attach the DLC to the session and start it off
  193          */
  194         dlc->rd_session = rs;
  195         dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
  196         LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
  197 
  198         if (rs->rs_state == RFCOMM_SESSION_OPEN)
  199                 err = rfcomm_dlc_connect(dlc);
  200 
  201         return err;
  202 }
  203 
  204 /*
  205  * rfcomm_peeraddr_pcb(dlc, sockaddr)
  206  *
  207  * return remote address
  208  */
  209 int
  210 rfcomm_peeraddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  211 {
  212 
  213         memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
  214         return 0;
  215 }
  216 
  217 /*
  218  * rfcomm_disconnect_pcb(dlc, linger)
  219  *
  220  * disconnect RFCOMM DLC
  221  */
  222 int
  223 rfcomm_disconnect_pcb(struct rfcomm_dlc *dlc, int linger)
  224 {
  225         struct rfcomm_session *rs = dlc->rd_session;
  226         int err = 0;
  227 
  228         KASSERT(dlc != NULL);
  229 
  230         switch (dlc->rd_state) {
  231         case RFCOMM_DLC_CLOSED:
  232         case RFCOMM_DLC_LISTEN:
  233                 return EINVAL;
  234 
  235         case RFCOMM_DLC_WAIT_SEND_UA:
  236                 err = rfcomm_session_send_frame(rs,
  237                                 RFCOMM_FRAME_DM, dlc->rd_dlci);
  238 
  239                 /* fall through */
  240         case RFCOMM_DLC_WAIT_SESSION:
  241         case RFCOMM_DLC_WAIT_CONNECT:
  242         case RFCOMM_DLC_WAIT_SEND_SABM:
  243                 rfcomm_dlc_close(dlc, 0);
  244                 break;
  245 
  246         case RFCOMM_DLC_OPEN:
  247                 if (dlc->rd_txbuf != NULL && linger != 0) {
  248                         dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
  249                         break;
  250                 }
  251 
  252                 /* else fall through */
  253         case RFCOMM_DLC_WAIT_RECV_UA:
  254                 dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
  255                 err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
  256                                                         dlc->rd_dlci);
  257                 callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
  258                 break;
  259 
  260         case RFCOMM_DLC_WAIT_DISCONNECT:
  261                 err = EALREADY;
  262                 break;
  263 
  264         default:
  265                 UNKNOWN(dlc->rd_state);
  266                 break;
  267         }
  268 
  269         return err;
  270 }
  271 
  272 /*
  273  * rfcomm_detach_pcb(handle)
  274  *
  275  * detach RFCOMM DLC from handle
  276  */
  277 void
  278 rfcomm_detach_pcb(struct rfcomm_dlc **handle)
  279 {
  280         struct rfcomm_dlc *dlc = *handle;
  281 
  282         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  283                 rfcomm_dlc_close(dlc, 0);
  284 
  285         if (dlc->rd_txbuf != NULL) {
  286                 m_freem(dlc->rd_txbuf);
  287                 dlc->rd_txbuf = NULL;
  288         }
  289 
  290         dlc->rd_upper = NULL;
  291         *handle = NULL;
  292 
  293         /*
  294          * If callout is invoking we can't free the DLC so
  295          * mark it and let the callout release it.
  296          */
  297         if (callout_invoking(&dlc->rd_timeout))
  298                 dlc->rd_flags |= RFCOMM_DLC_DETACH;
  299         else {
  300                 callout_destroy(&dlc->rd_timeout);
  301                 kmem_intr_free(dlc, sizeof(*dlc));
  302         }
  303 }
  304 
  305 /*
  306  * rfcomm_listen_pcb(dlc)
  307  *
  308  * This DLC is a listener. We look for an existing listening session
  309  * with a matching address to attach to or else create a new one on
  310  * the listeners list. If the ANY channel is given, allocate the first
  311  * available for the session.
  312  */
  313 int
  314 rfcomm_listen_pcb(struct rfcomm_dlc *dlc)
  315 {
  316         struct rfcomm_session *rs;
  317         struct rfcomm_dlc *used;
  318         struct sockaddr_bt addr;
  319         int err, channel;
  320 
  321         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  322                 return EISCONN;
  323 
  324         if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
  325             && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
  326             || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
  327                 return EADDRNOTAVAIL;
  328 
  329         if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
  330                 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
  331         else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
  332             && (dlc->rd_laddr.bt_psm < 0x1001
  333             || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
  334                 return EADDRNOTAVAIL;
  335 
  336         LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
  337                 l2cap_sockaddr_pcb(rs->rs_l2cap, &addr);
  338 
  339                 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
  340                         continue;
  341 
  342                 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
  343                         break;
  344         }
  345 
  346         if (rs == NULL) {
  347                 rs = rfcomm_session_alloc(&rfcomm_session_listen,
  348                                                 &dlc->rd_laddr);
  349                 if (rs == NULL)
  350                         return ENOMEM;
  351 
  352                 rs->rs_state = RFCOMM_SESSION_LISTEN;
  353 
  354                 err = l2cap_listen_pcb(rs->rs_l2cap);
  355                 if (err) {
  356                         rfcomm_session_free(rs);
  357                         return err;
  358                 }
  359         }
  360 
  361         if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
  362                 channel = RFCOMM_CHANNEL_MIN;
  363                 used = LIST_FIRST(&rs->rs_dlcs);
  364 
  365                 while (used != NULL) {
  366                         if (used->rd_laddr.bt_channel == channel) {
  367                                 if (channel++ == RFCOMM_CHANNEL_MAX)
  368                                         return EADDRNOTAVAIL;
  369 
  370                                 used = LIST_FIRST(&rs->rs_dlcs);
  371                         } else {
  372                                 used = LIST_NEXT(used, rd_next);
  373                         }
  374                 }
  375 
  376                 dlc->rd_laddr.bt_channel = channel;
  377         }
  378 
  379         dlc->rd_session = rs;
  380         dlc->rd_state = RFCOMM_DLC_LISTEN;
  381         LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
  382 
  383         return 0;
  384 }
  385 
  386 /*
  387  * rfcomm_send_pcb(dlc, mbuf)
  388  *
  389  * Output data on DLC. This is streamed data, so we add it
  390  * to our buffer and start the DLC, which will assemble
  391  * packets and send them if it can.
  392  */
  393 int
  394 rfcomm_send_pcb(struct rfcomm_dlc *dlc, struct mbuf *m)
  395 {
  396 
  397         if (dlc->rd_txbuf != NULL) {
  398                 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
  399                 m_cat(dlc->rd_txbuf, m);
  400         } else {
  401                 dlc->rd_txbuf = m;
  402         }
  403 
  404         if (dlc->rd_state == RFCOMM_DLC_OPEN)
  405                 rfcomm_dlc_start(dlc);
  406 
  407         return 0;
  408 }
  409 
  410 /*
  411  * rfcomm_rcvd_pcb(dlc, space)
  412  *
  413  * Indicate space now available in receive buffer
  414  *
  415  * This should be used to give an initial value of the receive buffer
  416  * size when the DLC is attached and anytime data is cleared from the
  417  * buffer after that.
  418  */
  419 int
  420 rfcomm_rcvd_pcb(struct rfcomm_dlc *dlc, size_t space)
  421 {
  422 
  423         KASSERT(dlc != NULL);
  424 
  425         dlc->rd_rxsize = space;
  426 
  427         /*
  428          * if we are using credit based flow control, we may
  429          * want to send some credits..
  430          */
  431         if (dlc->rd_state == RFCOMM_DLC_OPEN
  432             && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
  433                 rfcomm_dlc_start(dlc);
  434 
  435         return 0;
  436 }
  437 
  438 /*
  439  * rfcomm_setopt(dlc, sopt)
  440  *
  441  * set DLC options
  442  */
  443 int
  444 rfcomm_setopt(struct rfcomm_dlc *dlc, const struct sockopt *sopt)
  445 {
  446         int mode, err = 0;
  447         uint16_t mtu;
  448 
  449         switch (sopt->sopt_name) {
  450         case SO_RFCOMM_MTU:
  451                 err = sockopt_get(sopt, &mtu, sizeof(mtu));
  452                 if (err)
  453                         break;
  454 
  455                 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
  456                         err = EINVAL;
  457                 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
  458                         dlc->rd_mtu = mtu;
  459                 else
  460                         err = EBUSY;
  461 
  462                 break;
  463 
  464         case SO_RFCOMM_LM:
  465                 err = sockopt_getint(sopt, &mode);
  466                 if (err)
  467                         break;
  468 
  469                 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
  470 
  471                 if (mode & RFCOMM_LM_SECURE)
  472                         mode |= RFCOMM_LM_ENCRYPT;
  473 
  474                 if (mode & RFCOMM_LM_ENCRYPT)
  475                         mode |= RFCOMM_LM_AUTH;
  476 
  477                 dlc->rd_mode = mode;
  478 
  479                 if (dlc->rd_state == RFCOMM_DLC_OPEN)
  480                         err = rfcomm_dlc_setmode(dlc);
  481 
  482                 break;
  483 
  484         default:
  485                 err = ENOPROTOOPT;
  486                 break;
  487         }
  488         return err;
  489 }
  490 
  491 /*
  492  * rfcomm_getopt(dlc, sopt)
  493  *
  494  * get DLC options
  495  */
  496 int
  497 rfcomm_getopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
  498 {
  499         struct rfcomm_fc_info fc;
  500 
  501         switch (sopt->sopt_name) {
  502         case SO_RFCOMM_MTU:
  503                 return sockopt_set(sopt, &dlc->rd_mtu, sizeof(uint16_t));
  504 
  505         case SO_RFCOMM_FC_INFO:
  506                 memset(&fc, 0, sizeof(fc));
  507                 fc.lmodem = dlc->rd_lmodem;
  508                 fc.rmodem = dlc->rd_rmodem;
  509                 fc.tx_cred = uimax(dlc->rd_txcred, 0xff);
  510                 fc.rx_cred = uimax(dlc->rd_rxcred, 0xff);
  511                 if (dlc->rd_session
  512                     && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
  513                         fc.cfc = 1;
  514 
  515                 return sockopt_set(sopt, &fc, sizeof(fc));
  516 
  517         case SO_RFCOMM_LM:
  518                 return sockopt_setint(sopt, dlc->rd_mode);
  519 
  520         default:
  521                 break;
  522         }
  523 
  524         return ENOPROTOOPT;
  525 }

Cache object: 4b13417a91aa85a7cb813b278930439d


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