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 /* $DragonFly: src/sys/netbt/rfcomm_upper.c,v 1.3 2008/06/20 20:52:29 aggelos Exp $ */
    2 /* $OpenBSD: src/sys/netbt/rfcomm_upper.c,v 1.4 2008/02/24 21:34:48 uwe Exp $ */
    3 /* $NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $ */
    4 
    5 /*-
    6  * Copyright (c) 2006 Itronix Inc.
    7  * All rights reserved.
    8  *
    9  * Written by Iain Hibbert for Itronix Inc.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. The name of Itronix Inc. may not be used to endorse
   20  *    or promote products derived from this software without specific
   21  *    prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   30  * ON ANY THEORY OF LIABILITY, WHETHER IN
   31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/proc.h>
   40 #include <sys/systm.h>
   41 #include <sys/socketvar.h>
   42 
   43 #include <netbt/bluetooth.h>
   44 #include <netbt/hci.h>
   45 #include <netbt/l2cap.h>
   46 #include <netbt/rfcomm.h>
   47 
   48 /****************************************************************************
   49  *
   50  *      RFCOMM DLC - Upper Protocol API
   51  *
   52  * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
   53  * but it is should be possible to provide a pseudo-device for a direct
   54  * tty interface.
   55  */
   56 
   57 /*
   58  * rfcomm_attach(handle, proto, upper)
   59  *
   60  * attach a new RFCOMM DLC to handle, populate with reasonable defaults
   61  */
   62 int
   63 rfcomm_attach(struct rfcomm_dlc **handle,
   64                 const struct btproto *proto, void *upper)
   65 {
   66         struct rfcomm_dlc *dlc;
   67 
   68         KKASSERT(handle != NULL);
   69         KKASSERT(proto != NULL);
   70         KKASSERT(upper != NULL);
   71 
   72         dlc = kmalloc(sizeof(*dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
   73         if (dlc == NULL)
   74                 return ENOMEM;
   75 
   76         dlc->rd_state = RFCOMM_DLC_CLOSED;
   77         dlc->rd_mtu = rfcomm_mtu_default;
   78 
   79         dlc->rd_proto = proto;
   80         dlc->rd_upper = upper;
   81 
   82         dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
   83         dlc->rd_laddr.bt_family = AF_BLUETOOTH;
   84         dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
   85 
   86         dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
   87         dlc->rd_raddr.bt_family = AF_BLUETOOTH;
   88         dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
   89 
   90         dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
   91 
   92         callout_init(&dlc->rd_timeout);
   93 
   94         *handle = dlc;
   95         return 0;
   96 }
   97 
   98 /*
   99  * rfcomm_bind(dlc, sockaddr)
  100  *
  101  * bind DLC to local address
  102  */
  103 int
  104 rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  105 {
  106 
  107         memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
  108         return 0;
  109 }
  110 
  111 /*
  112  * rfcomm_sockaddr(dlc, sockaddr)
  113  *
  114  * return local address
  115  */
  116 int
  117 rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  118 {
  119 
  120         memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
  121         return 0;
  122 }
  123 
  124 /*
  125  * rfcomm_connect(dlc, sockaddr)
  126  *
  127  * Initiate connection of RFCOMM DLC to remote address.
  128  */
  129 int
  130 rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
  131 {
  132         struct rfcomm_session *rs;
  133         int err = 0;
  134 
  135         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  136                 return EISCONN;
  137 
  138         memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
  139 
  140         if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
  141             || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
  142             || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
  143                 return EDESTADDRREQ;
  144 
  145         if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
  146                 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
  147         else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
  148             && (dlc->rd_raddr.bt_psm < 0x1001
  149             || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
  150                 return EINVAL;
  151 
  152         /*
  153          * We are allowed only one RFCOMM session between any 2 Bluetooth
  154          * devices, so see if there is a session already otherwise create
  155          * one and set it connecting.
  156          */
  157         rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
  158         if (rs == NULL) {
  159                 rs = rfcomm_session_alloc(&rfcomm_session_active,
  160                                                 &dlc->rd_laddr);
  161                 if (rs == NULL)
  162                         return ENOMEM;
  163 
  164                 rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
  165                 rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
  166 
  167                 err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
  168                 if (err) {
  169                         rfcomm_session_free(rs);
  170                         return err;
  171                 }
  172 
  173                 /*
  174                  * This session will start up automatically when its
  175                  * L2CAP channel is connected.
  176                  */
  177         }
  178 
  179         /* construct DLC */
  180         dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
  181         if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
  182                 return EBUSY;
  183 
  184         l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
  185 
  186         /*
  187          * attach the DLC to the session and start it off
  188          */
  189         dlc->rd_session = rs;
  190         dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
  191         LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
  192 
  193         if (rs->rs_state == RFCOMM_SESSION_OPEN)
  194                 err = rfcomm_dlc_connect(dlc);
  195 
  196         return err;
  197 }
  198 
  199 /*
  200  * rfcomm_peeraddr(dlc, sockaddr)
  201  *
  202  * return remote address
  203  */
  204 int
  205 rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
  206 {
  207 
  208         memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
  209         return 0;
  210 }
  211 
  212 /*
  213  * rfcomm_disconnect(dlc, linger)
  214  *
  215  * disconnect RFCOMM DLC
  216  */
  217 int
  218 rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
  219 {
  220         struct rfcomm_session *rs = dlc->rd_session;
  221         int err = 0;
  222 
  223         KKASSERT(dlc != NULL);
  224 
  225         switch (dlc->rd_state) {
  226         case RFCOMM_DLC_CLOSED:
  227         case RFCOMM_DLC_LISTEN:
  228                 return EINVAL;
  229 
  230         case RFCOMM_DLC_WAIT_SEND_UA:
  231                 err = rfcomm_session_send_frame(rs,
  232                                 RFCOMM_FRAME_DM, dlc->rd_dlci);
  233 
  234                 /* fall through */
  235         case RFCOMM_DLC_WAIT_SESSION:
  236         case RFCOMM_DLC_WAIT_CONNECT:
  237         case RFCOMM_DLC_WAIT_SEND_SABM:
  238                 rfcomm_dlc_close(dlc, 0);
  239                 break;
  240 
  241         case RFCOMM_DLC_OPEN:
  242                 if (dlc->rd_txbuf != NULL && linger != 0) {
  243                         dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
  244                         break;
  245                 }
  246 
  247                 /* else fall through */
  248         case RFCOMM_DLC_WAIT_RECV_UA:
  249                 dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
  250                 err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
  251                                                         dlc->rd_dlci);
  252                 callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
  253                     rfcomm_dlc_timeout, dlc);
  254                 break;
  255 
  256         case RFCOMM_DLC_WAIT_DISCONNECT:
  257                 err = EALREADY;
  258                 break;
  259 
  260         default:
  261                 UNKNOWN(dlc->rd_state);
  262                 break;
  263         }
  264 
  265         return err;
  266 }
  267 
  268 /*
  269  * rfcomm_detach(handle)
  270  *
  271  * detach RFCOMM DLC from handle
  272  */
  273 int
  274 rfcomm_detach(struct rfcomm_dlc **handle)
  275 {
  276         struct rfcomm_dlc *dlc = *handle;
  277 
  278         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  279                 rfcomm_dlc_close(dlc, 0);
  280 
  281         if (dlc->rd_txbuf != NULL) {
  282                 m_freem(dlc->rd_txbuf);
  283                 dlc->rd_txbuf = NULL;
  284         }
  285 
  286         dlc->rd_upper = NULL;
  287         *handle = NULL;
  288 
  289         /*
  290          * If callout is invoking we can't free the DLC so
  291          * mark it and let the callout release it.
  292          */
  293         if (callout_active(&dlc->rd_timeout))
  294                 dlc->rd_flags |= RFCOMM_DLC_DETACH;
  295         else
  296                 kfree(dlc, M_BLUETOOTH);
  297 
  298         return 0;
  299 }
  300 
  301 /*
  302  * rfcomm_listen(dlc)
  303  *
  304  * This DLC is a listener. We look for an existing listening session
  305  * with a matching address to attach to or else create a new one on
  306  * the listeners list. If the ANY channel is given, allocate the first
  307  * available for the session.
  308  */
  309 int
  310 rfcomm_listen(struct rfcomm_dlc *dlc)
  311 {
  312         struct rfcomm_session *rs;
  313         struct rfcomm_dlc *used;
  314         struct sockaddr_bt addr;
  315         int err, channel;
  316 
  317         if (dlc->rd_state != RFCOMM_DLC_CLOSED)
  318                 return EISCONN;
  319 
  320         if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
  321             && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
  322             || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
  323                 return EADDRNOTAVAIL;
  324 
  325         if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
  326                 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
  327         else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
  328             && (dlc->rd_laddr.bt_psm < 0x1001
  329             || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
  330                 return EADDRNOTAVAIL;
  331 
  332         LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
  333                 l2cap_sockaddr(rs->rs_l2cap, &addr);
  334 
  335                 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
  336                         continue;
  337 
  338                 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
  339                         break;
  340         }
  341 
  342         if (rs == NULL) {
  343                 rs = rfcomm_session_alloc(&rfcomm_session_listen,
  344                                                 &dlc->rd_laddr);
  345                 if (rs == NULL)
  346                         return ENOMEM;
  347 
  348                 rs->rs_state = RFCOMM_SESSION_LISTEN;
  349 
  350                 err = l2cap_listen(rs->rs_l2cap);
  351                 if (err) {
  352                         rfcomm_session_free(rs);
  353                         return err;
  354                 }
  355         }
  356 
  357         if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
  358                 channel = RFCOMM_CHANNEL_MIN;
  359                 used = LIST_FIRST(&rs->rs_dlcs);
  360 
  361                 while (used != NULL) {
  362                         if (used->rd_laddr.bt_channel == channel) {
  363                                 if (channel++ == RFCOMM_CHANNEL_MAX)
  364                                         return EADDRNOTAVAIL;
  365 
  366                                 used = LIST_FIRST(&rs->rs_dlcs);
  367                         } else {
  368                                 used = LIST_NEXT(used, rd_next);
  369                         }
  370                 }
  371 
  372                 dlc->rd_laddr.bt_channel = channel;
  373         }
  374 
  375         dlc->rd_session = rs;
  376         dlc->rd_state = RFCOMM_DLC_LISTEN;
  377         LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
  378 
  379         return 0;
  380 }
  381 
  382 /*
  383  * rfcomm_send(dlc, mbuf)
  384  *
  385  * Output data on DLC. This is streamed data, so we add it
  386  * to our buffer and start the DLC, which will assemble
  387  * packets and send them if it can.
  388  */
  389 int
  390 rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
  391 {
  392 
  393         if (dlc->rd_txbuf != NULL) {
  394                 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
  395                 m_cat(dlc->rd_txbuf, m);
  396         } else {
  397                 dlc->rd_txbuf = m;
  398         }
  399 
  400         if (dlc->rd_state == RFCOMM_DLC_OPEN)
  401                 rfcomm_dlc_start(dlc);
  402 
  403         return 0;
  404 }
  405 
  406 /*
  407  * rfcomm_rcvd(dlc, space)
  408  *
  409  * Indicate space now available in receive buffer
  410  *
  411  * This should be used to give an initial value of the receive buffer
  412  * size when the DLC is attached and anytime data is cleared from the
  413  * buffer after that.
  414  */
  415 int
  416 rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
  417 {
  418 
  419         KKASSERT(dlc != NULL);
  420 
  421         dlc->rd_rxsize = space;
  422 
  423         /*
  424          * if we are using credit based flow control, we may
  425          * want to send some credits..
  426          */
  427         if (dlc->rd_state == RFCOMM_DLC_OPEN
  428             && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
  429                 rfcomm_dlc_start(dlc);
  430 
  431         return 0;
  432 }
  433 
  434 /*
  435  * rfcomm_setopt(dlc, option, addr)
  436  *
  437  * set DLC options
  438  */
  439 int
  440 rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
  441 {
  442         int mode, err = 0;
  443         uint16_t mtu;
  444 
  445         switch (opt) {
  446         case SO_RFCOMM_MTU:
  447                 mtu = *(uint16_t *)addr;
  448                 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
  449                         err = EINVAL;
  450                 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
  451                         dlc->rd_mtu = mtu;
  452                 else
  453                         err = EBUSY;
  454 
  455                 break;
  456 
  457         case SO_RFCOMM_LM:
  458                 mode = *(int *)addr;
  459                 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
  460 
  461                 if (mode & RFCOMM_LM_SECURE)
  462                         mode |= RFCOMM_LM_ENCRYPT;
  463 
  464                 if (mode & RFCOMM_LM_ENCRYPT)
  465                         mode |= RFCOMM_LM_AUTH;
  466 
  467                 dlc->rd_mode = mode;
  468 
  469                 if (dlc->rd_state == RFCOMM_DLC_OPEN)
  470                         err = rfcomm_dlc_setmode(dlc);
  471 
  472                 break;
  473 
  474         default:
  475                 err = ENOPROTOOPT;
  476                 break;
  477         }
  478         return err;
  479 }
  480 
  481 
  482 int
  483 rfcomm_setopt2(struct rfcomm_dlc *dlc, int opt, struct socket *so,
  484     struct sockopt *sopt)
  485 {
  486         int mode, err = 0;
  487         uint16_t mtu;
  488 
  489         switch (opt) {
  490         case SO_RFCOMM_MTU:
  491                 err = soopt_to_kbuf(sopt, &mtu, sizeof(uint16_t),
  492                     sizeof(uint16_t)); 
  493                 if (err) break;
  494 
  495                 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
  496                         err = EINVAL;
  497                 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
  498                         dlc->rd_mtu = mtu;
  499                 else
  500                         err = EBUSY;
  501 
  502                 break;
  503 
  504         case SO_RFCOMM_LM:
  505                 err = soopt_to_kbuf(sopt, &mode, sizeof(int), sizeof(int)); 
  506                 if (err) break;
  507 
  508                 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
  509 
  510                 if (mode & RFCOMM_LM_SECURE)
  511                         mode |= RFCOMM_LM_ENCRYPT;
  512 
  513                 if (mode & RFCOMM_LM_ENCRYPT)
  514                         mode |= RFCOMM_LM_AUTH;
  515 
  516                 dlc->rd_mode = mode;
  517 
  518                 if (dlc->rd_state == RFCOMM_DLC_OPEN)
  519                         err = rfcomm_dlc_setmode(dlc);
  520 
  521                 break;
  522 
  523         default:
  524                 err = ENOPROTOOPT;
  525                 break;
  526         }
  527         return err;
  528 }
  529 
  530 /*
  531  * rfcomm_getopt(dlc, option, addr)
  532  *
  533  * get DLC options
  534  */
  535 int
  536 rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
  537 {
  538         struct rfcomm_fc_info *fc;
  539 
  540         switch (opt) {
  541         case SO_RFCOMM_MTU:
  542                 *(uint16_t *)addr = dlc->rd_mtu;
  543                 return sizeof(uint16_t);
  544 
  545         case SO_RFCOMM_FC_INFO:
  546                 fc = addr;
  547                 memset(fc, 0, sizeof(*fc));
  548                 fc->lmodem = dlc->rd_lmodem;
  549                 fc->rmodem = dlc->rd_rmodem;
  550                 fc->tx_cred = max(dlc->rd_txcred, 0xff);
  551                 fc->rx_cred = max(dlc->rd_rxcred, 0xff);
  552                 if (dlc->rd_session
  553                     && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
  554                         fc->cfc = 1;
  555 
  556                 return sizeof(*fc);
  557 
  558         case SO_RFCOMM_LM:
  559                 *(int *)addr = dlc->rd_mode;
  560                 return sizeof(int);
  561 
  562         default:
  563                 break;
  564         }
  565 
  566         return 0;
  567 }

Cache object: 6d826eb9fd9296434d20573bfd7f5246


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