Annotation of sys/netbt/rfcomm_session.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: rfcomm_session.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
! 2: /* $NetBSD: rfcomm_session.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2006 Itronix Inc.
! 6: * All rights reserved.
! 7: *
! 8: * Written by Iain Hibbert for Itronix Inc.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. The name of Itronix Inc. may not be used to endorse
! 19: * or promote products derived from this software without specific
! 20: * prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 24: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 25: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
! 26: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 27: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 28: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
! 29: * ON ANY THEORY OF LIABILITY, WHETHER IN
! 30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 32: * POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: #include <sys/cdefs.h>
! 36:
! 37: #include <sys/param.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/proc.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/types.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 Multiplexer Sessions sit directly on L2CAP channels, and can
! 52: * multiplex up to 30 incoming and 30 outgoing connections.
! 53: * Only one Multiplexer is allowed between any two devices.
! 54: */
! 55:
! 56: static void rfcomm_session_timeout(void *);
! 57: static void rfcomm_session_recv_sabm(struct rfcomm_session *, int);
! 58: static void rfcomm_session_recv_disc(struct rfcomm_session *, int);
! 59: static void rfcomm_session_recv_ua(struct rfcomm_session *, int);
! 60: static void rfcomm_session_recv_dm(struct rfcomm_session *, int);
! 61: static void rfcomm_session_recv_uih(struct rfcomm_session *, int, int, struct mbuf *, int);
! 62: static void rfcomm_session_recv_mcc(struct rfcomm_session *, struct mbuf *);
! 63: static void rfcomm_session_recv_mcc_test(struct rfcomm_session *, int, struct mbuf *);
! 64: static void rfcomm_session_recv_mcc_fcon(struct rfcomm_session *, int);
! 65: static void rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *, int);
! 66: static void rfcomm_session_recv_mcc_msc(struct rfcomm_session *, int, struct mbuf *);
! 67: static void rfcomm_session_recv_mcc_rpn(struct rfcomm_session *, int, struct mbuf *);
! 68: static void rfcomm_session_recv_mcc_rls(struct rfcomm_session *, int, struct mbuf *);
! 69: static void rfcomm_session_recv_mcc_pn(struct rfcomm_session *, int, struct mbuf *);
! 70: static void rfcomm_session_recv_mcc_nsc(struct rfcomm_session *, int, struct mbuf *);
! 71:
! 72: /* L2CAP callbacks */
! 73: static void rfcomm_session_connecting(void *);
! 74: static void rfcomm_session_connected(void *);
! 75: static void rfcomm_session_disconnected(void *, int);
! 76: static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
! 77: static void rfcomm_session_complete(void *, int);
! 78: static void rfcomm_session_linkmode(void *, int);
! 79: static void rfcomm_session_input(void *, struct mbuf *);
! 80:
! 81: static const struct btproto rfcomm_session_proto = {
! 82: rfcomm_session_connecting,
! 83: rfcomm_session_connected,
! 84: rfcomm_session_disconnected,
! 85: rfcomm_session_newconn,
! 86: rfcomm_session_complete,
! 87: rfcomm_session_linkmode,
! 88: rfcomm_session_input,
! 89: };
! 90:
! 91: struct rfcomm_session_list
! 92: rfcomm_session_active = LIST_HEAD_INITIALIZER(rfcomm_session_active);
! 93:
! 94: struct rfcomm_session_list
! 95: rfcomm_session_listen = LIST_HEAD_INITIALIZER(rfcomm_session_listen);
! 96:
! 97: struct pool rfcomm_credit_pool;
! 98:
! 99: /*
! 100: * RFCOMM System Parameters (see section 5.3)
! 101: */
! 102: int rfcomm_mtu_default = 127; /* bytes */
! 103: int rfcomm_ack_timeout = 20; /* seconds */
! 104: int rfcomm_mcc_timeout = 20; /* seconds */
! 105:
! 106: /*
! 107: * Reversed CRC table as per TS 07.10 Annex B.3.5
! 108: */
! 109: static const uint8_t crctable[256] = { /* reversed, 8-bit, poly=0x07 */
! 110: 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
! 111: 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
! 112: 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
! 113: 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
! 114:
! 115: 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
! 116: 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
! 117: 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
! 118: 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
! 119:
! 120: 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
! 121: 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
! 122: 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
! 123: 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
! 124:
! 125: 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
! 126: 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
! 127: 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
! 128: 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
! 129:
! 130: 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
! 131: 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
! 132: 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
! 133: 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
! 134:
! 135: 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
! 136: 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
! 137: 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
! 138: 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
! 139:
! 140: 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
! 141: 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
! 142: 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
! 143: 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
! 144:
! 145: 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
! 146: 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
! 147: 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
! 148: 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
! 149: };
! 150:
! 151: #define FCS(f, d) crctable[(f) ^ (d)]
! 152:
! 153: /*
! 154: * rfcomm_init()
! 155: *
! 156: * initialize the "credit pool".
! 157: */
! 158: void
! 159: rfcomm_init(void)
! 160: {
! 161: pool_init(&rfcomm_credit_pool, 0, 0, 0, 0, "rfcomm_credit", NULL);
! 162: }
! 163:
! 164: /*
! 165: * rfcomm_session_alloc(list, sockaddr)
! 166: *
! 167: * allocate a new session and fill in the blanks, then
! 168: * attach session to front of specified list (active or listen)
! 169: */
! 170: struct rfcomm_session *
! 171: rfcomm_session_alloc(struct rfcomm_session_list *list,
! 172: struct sockaddr_bt *laddr)
! 173: {
! 174: struct rfcomm_session *rs;
! 175: int err;
! 176:
! 177: rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT);
! 178: if (rs == NULL)
! 179: return NULL;
! 180: bzero(rs, sizeof *rs);
! 181:
! 182: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 183:
! 184: timeout_set(&rs->rs_timeout, rfcomm_session_timeout, rs);
! 185:
! 186: SIMPLEQ_INIT(&rs->rs_credits);
! 187: LIST_INIT(&rs->rs_dlcs);
! 188:
! 189: err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs);
! 190: if (err) {
! 191: free(rs, M_BLUETOOTH);
! 192: return NULL;
! 193: }
! 194:
! 195: (void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
! 196:
! 197: if (laddr->bt_psm == L2CAP_PSM_ANY)
! 198: laddr->bt_psm = L2CAP_PSM_RFCOMM;
! 199:
! 200: (void)l2cap_bind(rs->rs_l2cap, laddr);
! 201:
! 202: LIST_INSERT_HEAD(list, rs, rs_next);
! 203:
! 204: return rs;
! 205: }
! 206:
! 207: /*
! 208: * rfcomm_session_free(rfcomm_session)
! 209: *
! 210: * release a session, including any cleanup
! 211: */
! 212: void
! 213: rfcomm_session_free(struct rfcomm_session *rs)
! 214: {
! 215: struct rfcomm_credit *credit;
! 216:
! 217: KASSERT(rs != NULL);
! 218: KASSERT(LIST_EMPTY(&rs->rs_dlcs));
! 219:
! 220: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 221:
! 222: /*
! 223: * If the callout is already invoked we have no way to stop it,
! 224: * but it will call us back right away (there are no DLC's) so
! 225: * not to worry.
! 226: */
! 227: timeout_del(&rs->rs_timeout);
! 228: if (timeout_triggered(&rs->rs_timeout))
! 229: return;
! 230:
! 231: /*
! 232: * Take care that rfcomm_session_disconnected() doesnt call
! 233: * us back either as it will do if the l2cap_channel has not
! 234: * been closed when we detach it..
! 235: */
! 236: if (rs->rs_flags & RFCOMM_SESSION_FREE)
! 237: return;
! 238:
! 239: rs->rs_flags |= RFCOMM_SESSION_FREE;
! 240:
! 241: /* throw away any remaining credit notes */
! 242: while ((credit = SIMPLEQ_FIRST(&rs->rs_credits)) != NULL) {
! 243: SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
! 244: pool_put(&rfcomm_credit_pool, credit);
! 245: }
! 246:
! 247: KASSERT(SIMPLEQ_EMPTY(&rs->rs_credits));
! 248:
! 249: /* Goodbye! */
! 250: LIST_REMOVE(rs, rs_next);
! 251: l2cap_detach(&rs->rs_l2cap);
! 252: free(rs, M_BLUETOOTH);
! 253: }
! 254:
! 255: /*
! 256: * rfcomm_session_lookup(sockaddr, sockaddr)
! 257: *
! 258: * Find active rfcomm session matching src and dest addresses
! 259: * when src is BDADDR_ANY match any local address
! 260: */
! 261: struct rfcomm_session *
! 262: rfcomm_session_lookup(struct sockaddr_bt *src, struct sockaddr_bt *dest)
! 263: {
! 264: struct rfcomm_session *rs;
! 265: struct sockaddr_bt addr;
! 266:
! 267: LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
! 268: if (rs->rs_state == RFCOMM_SESSION_CLOSED)
! 269: continue;
! 270:
! 271: l2cap_sockaddr(rs->rs_l2cap, &addr);
! 272:
! 273: if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0)
! 274: if (bdaddr_any(&src->bt_bdaddr) == 0)
! 275: continue;
! 276:
! 277: l2cap_peeraddr(rs->rs_l2cap, &addr);
! 278:
! 279: if (addr.bt_psm != dest->bt_psm)
! 280: continue;
! 281:
! 282: if (bdaddr_same(&dest->bt_bdaddr, &addr.bt_bdaddr))
! 283: break;
! 284: }
! 285:
! 286: return rs;
! 287: }
! 288:
! 289: /*
! 290: * rfcomm_session_timeout(rfcomm_session)
! 291: *
! 292: * Session timeouts are scheduled when a session is left or
! 293: * created with no DLCs, and when SABM(0) or DISC(0) are
! 294: * sent.
! 295: *
! 296: * So, if it is in an open state with DLC's attached then
! 297: * we leave it alone, otherwise the session is lost.
! 298: */
! 299: static void
! 300: rfcomm_session_timeout(void *arg)
! 301: {
! 302: struct rfcomm_session *rs = arg;
! 303: struct rfcomm_dlc *dlc;
! 304: int s;
! 305:
! 306: KASSERT(rs != NULL);
! 307:
! 308: s = splsoftnet();
! 309:
! 310: if (rs->rs_state != RFCOMM_SESSION_OPEN) {
! 311: DPRINTF("timeout\n");
! 312: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 313:
! 314: while (!LIST_EMPTY(&rs->rs_dlcs)) {
! 315: dlc = LIST_FIRST(&rs->rs_dlcs);
! 316:
! 317: rfcomm_dlc_close(dlc, ETIMEDOUT);
! 318: }
! 319: }
! 320:
! 321: if (LIST_EMPTY(&rs->rs_dlcs)) {
! 322: DPRINTF("expiring\n");
! 323: rfcomm_session_free(rs);
! 324: }
! 325: splx(s);
! 326: }
! 327:
! 328: /***********************************************************************
! 329: *
! 330: * RFCOMM Session L2CAP protocol callbacks
! 331: *
! 332: */
! 333:
! 334: static void
! 335: rfcomm_session_connecting(void *arg)
! 336: {
! 337: /* struct rfcomm_session *rs = arg; */
! 338:
! 339: DPRINTF("Connecting\n");
! 340: }
! 341:
! 342: static void
! 343: rfcomm_session_connected(void *arg)
! 344: {
! 345: struct rfcomm_session *rs = arg;
! 346:
! 347: DPRINTF("Connected\n");
! 348:
! 349: /*
! 350: * L2CAP is open.
! 351: *
! 352: * If we are initiator, we can send our SABM(0)
! 353: * a timeout should be active?
! 354: *
! 355: * We must take note of the L2CAP MTU because currently
! 356: * the L2CAP implementation can only do Basic Mode.
! 357: */
! 358: l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
! 359:
! 360: rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
! 361: if (rs->rs_mtu < RFCOMM_MTU_MIN) {
! 362: rfcomm_session_disconnected(rs, EINVAL);
! 363: return;
! 364: }
! 365:
! 366: if (IS_INITIATOR(rs)) {
! 367: int err;
! 368:
! 369: err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, 0);
! 370: if (err)
! 371: rfcomm_session_disconnected(rs, err);
! 372:
! 373: timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
! 374: }
! 375: }
! 376:
! 377: static void
! 378: rfcomm_session_disconnected(void *arg, int err)
! 379: {
! 380: struct rfcomm_session *rs = arg;
! 381: struct rfcomm_dlc *dlc;
! 382:
! 383: DPRINTF("Disconnected\n");
! 384:
! 385: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 386:
! 387: while (!LIST_EMPTY(&rs->rs_dlcs)) {
! 388: dlc = LIST_FIRST(&rs->rs_dlcs);
! 389:
! 390: rfcomm_dlc_close(dlc, err);
! 391: }
! 392:
! 393: rfcomm_session_free(rs);
! 394: }
! 395:
! 396: static void *
! 397: rfcomm_session_newconn(void *arg, struct sockaddr_bt *laddr,
! 398: struct sockaddr_bt *raddr)
! 399: {
! 400: struct rfcomm_session *new, *rs = arg;
! 401:
! 402: DPRINTF("New Connection\n");
! 403:
! 404: /*
! 405: * Incoming session connect request. We should return a new
! 406: * session pointer if this is acceptable. The L2CAP layer
! 407: * passes local and remote addresses, which we must check as
! 408: * only one RFCOMM session is allowed between any two devices
! 409: */
! 410: new = rfcomm_session_lookup(laddr, raddr);
! 411: if (new != NULL)
! 412: return NULL;
! 413:
! 414: new = rfcomm_session_alloc(&rfcomm_session_active, laddr);
! 415: if (new == NULL)
! 416: return NULL;
! 417:
! 418: new->rs_mtu = rs->rs_mtu;
! 419: new->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
! 420:
! 421: /*
! 422: * schedule an expiry so that if nothing comes of it we
! 423: * can punt.
! 424: */
! 425: timeout_add(&new->rs_timeout, rfcomm_mcc_timeout * hz);
! 426:
! 427: return new->rs_l2cap;
! 428: }
! 429:
! 430: static void
! 431: rfcomm_session_complete(void *arg, int count)
! 432: {
! 433: struct rfcomm_session *rs = arg;
! 434: struct rfcomm_credit *credit;
! 435: struct rfcomm_dlc *dlc;
! 436:
! 437: /*
! 438: * count L2CAP packets are 'complete', meaning that they are cleared
! 439: * our buffers (for best effort) or arrived safe (for guaranteed) so
! 440: * we can take it off our list and pass the message on, so that
! 441: * eventually the data can be removed from the sockbuf
! 442: */
! 443: while (count-- > 0) {
! 444: credit = SIMPLEQ_FIRST(&rs->rs_credits);
! 445: #ifdef DIAGNOSTIC
! 446: if (credit == NULL) {
! 447: printf("%s: too many packets completed!\n", __func__);
! 448: break;
! 449: }
! 450: #endif
! 451: dlc = credit->rc_dlc;
! 452: if (dlc != NULL) {
! 453: dlc->rd_pending--;
! 454: (*dlc->rd_proto->complete)
! 455: (dlc->rd_upper, credit->rc_len);
! 456:
! 457: /*
! 458: * if not using credit flow control, we may push
! 459: * more data now
! 460: */
! 461: if ((rs->rs_flags & RFCOMM_SESSION_CFC) == 0
! 462: && dlc->rd_state == RFCOMM_DLC_OPEN) {
! 463: rfcomm_dlc_start(dlc);
! 464: }
! 465:
! 466: /*
! 467: * When shutdown is indicated, we are just waiting to
! 468: * clear outgoing data.
! 469: */
! 470: if ((dlc->rd_flags & RFCOMM_DLC_SHUTDOWN)
! 471: && dlc->rd_txbuf == NULL && dlc->rd_pending == 0) {
! 472: dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
! 473: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
! 474: dlc->rd_dlci);
! 475: timeout_add(&dlc->rd_timeout,
! 476: rfcomm_ack_timeout * hz);
! 477: }
! 478: }
! 479:
! 480: SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
! 481: pool_put(&rfcomm_credit_pool, credit);
! 482: }
! 483:
! 484: /*
! 485: * If session is closed, we are just waiting to clear the queue
! 486: */
! 487: if (rs->rs_state == RFCOMM_SESSION_CLOSED) {
! 488: if (SIMPLEQ_EMPTY(&rs->rs_credits))
! 489: l2cap_disconnect(rs->rs_l2cap, 0);
! 490: }
! 491: }
! 492:
! 493: /*
! 494: * Link Mode changed
! 495: *
! 496: * This is called when a mode change is complete. Proceed with connections
! 497: * where appropriate, or pass the new mode to any active DLCs.
! 498: */
! 499: static void
! 500: rfcomm_session_linkmode(void *arg, int new)
! 501: {
! 502: struct rfcomm_session *rs = arg;
! 503: struct rfcomm_dlc *dlc, *next;
! 504: int err, mode = 0;
! 505:
! 506: DPRINTF("auth %s, encrypt %s, secure %s\n",
! 507: (new & L2CAP_LM_AUTH ? "on" : "off"),
! 508: (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
! 509: (new & L2CAP_LM_SECURE ? "on" : "off"));
! 510:
! 511: if (new & L2CAP_LM_AUTH)
! 512: mode |= RFCOMM_LM_AUTH;
! 513:
! 514: if (new & L2CAP_LM_ENCRYPT)
! 515: mode |= RFCOMM_LM_ENCRYPT;
! 516:
! 517: if (new & L2CAP_LM_SECURE)
! 518: mode |= RFCOMM_LM_SECURE;
! 519:
! 520: next = LIST_FIRST(&rs->rs_dlcs);
! 521: while ((dlc = next) != NULL) {
! 522: next = LIST_NEXT(dlc, rd_next);
! 523:
! 524: switch (dlc->rd_state) {
! 525: case RFCOMM_DLC_WAIT_SEND_SABM: /* we are connecting */
! 526: if ((mode & dlc->rd_mode) != dlc->rd_mode) {
! 527: rfcomm_dlc_close(dlc, ECONNABORTED);
! 528: } else {
! 529: err = rfcomm_session_send_frame(rs,
! 530: RFCOMM_FRAME_SABM, dlc->rd_dlci);
! 531: if (err) {
! 532: rfcomm_dlc_close(dlc, err);
! 533: } else {
! 534: dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
! 535: timeout_add(&dlc->rd_timeout,
! 536: rfcomm_ack_timeout * hz);
! 537: break;
! 538: }
! 539: }
! 540:
! 541: /*
! 542: * If we aborted the connection and there are no more DLCs
! 543: * on the session, it is our responsibility to disconnect.
! 544: */
! 545: if (!LIST_EMPTY(&rs->rs_dlcs))
! 546: break;
! 547:
! 548: rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
! 549: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
! 550: timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
! 551: break;
! 552:
! 553: case RFCOMM_DLC_WAIT_SEND_UA: /* they are connecting */
! 554: if ((mode & dlc->rd_mode) != dlc->rd_mode) {
! 555: rfcomm_session_send_frame(rs,
! 556: RFCOMM_FRAME_DM, dlc->rd_dlci);
! 557: rfcomm_dlc_close(dlc, ECONNABORTED);
! 558: break;
! 559: }
! 560:
! 561: err = rfcomm_session_send_frame(rs,
! 562: RFCOMM_FRAME_UA, dlc->rd_dlci);
! 563: if (err) {
! 564: rfcomm_session_send_frame(rs,
! 565: RFCOMM_FRAME_DM, dlc->rd_dlci);
! 566: rfcomm_dlc_close(dlc, err);
! 567: break;
! 568: }
! 569:
! 570: err = rfcomm_dlc_open(dlc);
! 571: if (err) {
! 572: rfcomm_session_send_frame(rs,
! 573: RFCOMM_FRAME_DM, dlc->rd_dlci);
! 574: rfcomm_dlc_close(dlc, err);
! 575: break;
! 576: }
! 577:
! 578: break;
! 579:
! 580: case RFCOMM_DLC_WAIT_RECV_UA:
! 581: case RFCOMM_DLC_OPEN: /* already established */
! 582: (*dlc->rd_proto->linkmode)(dlc->rd_upper, mode);
! 583: break;
! 584:
! 585: default:
! 586: break;
! 587: }
! 588: }
! 589: }
! 590:
! 591: /*
! 592: * Receive data from L2CAP layer for session. There is always exactly one
! 593: * RFCOMM frame contained in each L2CAP frame.
! 594: */
! 595: static void
! 596: rfcomm_session_input(void *arg, struct mbuf *m)
! 597: {
! 598: struct rfcomm_session *rs = arg;
! 599: int dlci, len, type, pf;
! 600: uint8_t fcs, b;
! 601:
! 602: KASSERT(m != NULL);
! 603: KASSERT(rs != NULL);
! 604:
! 605: /*
! 606: * UIH frames: FCS is only calculated on address and control fields
! 607: * For other frames: FCS is calculated on address, control and length
! 608: * Length may extend to two octets
! 609: */
! 610: fcs = 0xff;
! 611:
! 612: if (m->m_pkthdr.len < 4) {
! 613: DPRINTF("short frame (%d), discarded\n", m->m_pkthdr.len);
! 614: goto done;
! 615: }
! 616:
! 617: /* address - one octet */
! 618: m_copydata(m, 0, 1, &b);
! 619: m_adj(m, 1);
! 620: fcs = FCS(fcs, b);
! 621: dlci = RFCOMM_DLCI(b);
! 622:
! 623: /* control - one octet */
! 624: m_copydata(m, 0, 1, &b);
! 625: m_adj(m, 1);
! 626: fcs = FCS(fcs, b);
! 627: type = RFCOMM_TYPE(b);
! 628: pf = RFCOMM_PF(b);
! 629:
! 630: /* length - may be two octets */
! 631: m_copydata(m, 0, 1, &b);
! 632: m_adj(m, 1);
! 633: if (type != RFCOMM_FRAME_UIH)
! 634: fcs = FCS(fcs, b);
! 635: len = (b >> 1) & 0x7f;
! 636:
! 637: if (RFCOMM_EA(b) == 0) {
! 638: if (m->m_pkthdr.len < 2) {
! 639: DPRINTF("short frame (%d, EA = 0), discarded\n",
! 640: m->m_pkthdr.len);
! 641: goto done;
! 642: }
! 643:
! 644: m_copydata(m, 0, 1, &b);
! 645: m_adj(m, 1);
! 646: if (type != RFCOMM_FRAME_UIH)
! 647: fcs = FCS(fcs, b);
! 648:
! 649: len |= (b << 7);
! 650: }
! 651:
! 652: /* FCS byte is last octet in frame */
! 653: m_copydata(m, m->m_pkthdr.len - 1, 1, &b);
! 654: m_adj(m, -1);
! 655: fcs = FCS(fcs, b);
! 656:
! 657: if (fcs != 0xcf) {
! 658: DPRINTF("Bad FCS value (%#2.2x), frame discarded\n", fcs);
! 659: goto done;
! 660: }
! 661:
! 662: DPRINTFN(10, "dlci %d, type %2.2x, len = %d\n", dlci, type, len);
! 663:
! 664: switch (type) {
! 665: case RFCOMM_FRAME_SABM:
! 666: if (pf)
! 667: rfcomm_session_recv_sabm(rs, dlci);
! 668: break;
! 669:
! 670: case RFCOMM_FRAME_DISC:
! 671: if (pf)
! 672: rfcomm_session_recv_disc(rs, dlci);
! 673: break;
! 674:
! 675: case RFCOMM_FRAME_UA:
! 676: if (pf)
! 677: rfcomm_session_recv_ua(rs, dlci);
! 678: break;
! 679:
! 680: case RFCOMM_FRAME_DM:
! 681: rfcomm_session_recv_dm(rs, dlci);
! 682: break;
! 683:
! 684: case RFCOMM_FRAME_UIH:
! 685: rfcomm_session_recv_uih(rs, dlci, pf, m, len);
! 686: return; /* (no release) */
! 687:
! 688: default:
! 689: UNKNOWN(type);
! 690: break;
! 691: }
! 692:
! 693: done:
! 694: m_freem(m);
! 695: }
! 696:
! 697: /***********************************************************************
! 698: *
! 699: * RFCOMM Session receive processing
! 700: */
! 701:
! 702: /*
! 703: * rfcomm_session_recv_sabm(rfcomm_session, dlci)
! 704: *
! 705: * Set Asyncrhonous Balanced Mode - open the channel.
! 706: */
! 707: static void
! 708: rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
! 709: {
! 710: struct rfcomm_dlc *dlc;
! 711: int err;
! 712:
! 713: DPRINTFN(5, "SABM(%d)\n", dlci);
! 714:
! 715: if (dlci == 0) { /* Open Session */
! 716: rs->rs_state = RFCOMM_SESSION_OPEN;
! 717: rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
! 718: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
! 719: if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
! 720: rfcomm_dlc_connect(dlc);
! 721: }
! 722: return;
! 723: }
! 724:
! 725: if (rs->rs_state != RFCOMM_SESSION_OPEN) {
! 726: DPRINTF("session was not even open!\n");
! 727: return;
! 728: }
! 729:
! 730: /* validate direction bit */
! 731: if ((IS_INITIATOR(rs) && !RFCOMM_DIRECTION(dlci))
! 732: || (!IS_INITIATOR(rs) && RFCOMM_DIRECTION(dlci))) {
! 733: DPRINTF("Invalid direction bit on DLCI\n");
! 734: return;
! 735: }
! 736:
! 737: /*
! 738: * look for our DLC - this may exist if we received PN
! 739: * already, or we may have to fabricate a new one.
! 740: */
! 741: dlc = rfcomm_dlc_lookup(rs, dlci);
! 742: if (dlc == NULL) {
! 743: dlc = rfcomm_dlc_newconn(rs, dlci);
! 744: if (dlc == NULL)
! 745: return; /* (DM is sent) */
! 746: }
! 747:
! 748: /*
! 749: * ..but if this DLC is not waiting to connect, they did
! 750: * something wrong, ignore it.
! 751: */
! 752: if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
! 753: return;
! 754:
! 755: /* set link mode */
! 756: err = rfcomm_dlc_setmode(dlc);
! 757: if (err == EINPROGRESS) {
! 758: dlc->rd_state = RFCOMM_DLC_WAIT_SEND_UA;
! 759: (*dlc->rd_proto->connecting)(dlc->rd_upper);
! 760: return;
! 761: }
! 762: if (err)
! 763: goto close;
! 764:
! 765: err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
! 766: if (err)
! 767: goto close;
! 768:
! 769: /* and mark it open */
! 770: err = rfcomm_dlc_open(dlc);
! 771: if (err)
! 772: goto close;
! 773:
! 774: return;
! 775:
! 776: close:
! 777: rfcomm_dlc_close(dlc, err);
! 778: }
! 779:
! 780: /*
! 781: * Receive Disconnect Command
! 782: */
! 783: static void
! 784: rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci)
! 785: {
! 786: struct rfcomm_dlc *dlc;
! 787:
! 788: DPRINTFN(5, "DISC(%d)\n", dlci);
! 789:
! 790: if (dlci == 0) {
! 791: /*
! 792: * Disconnect Session
! 793: *
! 794: * We set the session state to CLOSED so that when
! 795: * the UA frame is clear the session will be closed
! 796: * automatically. We wont bother to close any DLC's
! 797: * just yet as there should be none. In the unlikely
! 798: * event that something is left, it will get flushed
! 799: * out as the session goes down.
! 800: */
! 801: rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
! 802: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 803: return;
! 804: }
! 805:
! 806: dlc = rfcomm_dlc_lookup(rs, dlci);
! 807: if (dlc == NULL) {
! 808: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
! 809: return;
! 810: }
! 811:
! 812: rfcomm_dlc_close(dlc, ECONNRESET);
! 813: rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
! 814: }
! 815:
! 816: /*
! 817: * Receive Unnumbered Acknowledgement Response
! 818: *
! 819: * This should be a response to a DISC or SABM frame that we
! 820: * have previously sent. If unexpected, ignore it.
! 821: */
! 822: static void
! 823: rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
! 824: {
! 825: struct rfcomm_dlc *dlc;
! 826:
! 827: DPRINTFN(5, "UA(%d)\n", dlci);
! 828:
! 829: if (dlci == 0) {
! 830: switch (rs->rs_state) {
! 831: case RFCOMM_SESSION_WAIT_CONNECT: /* We sent SABM */
! 832: timeout_del(&rs->rs_timeout);
! 833: rs->rs_state = RFCOMM_SESSION_OPEN;
! 834: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
! 835: if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
! 836: rfcomm_dlc_connect(dlc);
! 837: }
! 838: break;
! 839:
! 840: case RFCOMM_SESSION_WAIT_DISCONNECT: /* We sent DISC */
! 841: timeout_del(&rs->rs_timeout);
! 842: rs->rs_state = RFCOMM_SESSION_CLOSED;
! 843: l2cap_disconnect(rs->rs_l2cap, 0);
! 844: break;
! 845:
! 846: default:
! 847: DPRINTF("Received spurious UA(0)!\n");
! 848: break;
! 849: }
! 850:
! 851: return;
! 852: }
! 853:
! 854: /*
! 855: * If we have no DLC on this dlci, we may have aborted
! 856: * without shutting down properly, so check if the session
! 857: * needs disconnecting.
! 858: */
! 859: dlc = rfcomm_dlc_lookup(rs, dlci);
! 860: if (dlc == NULL)
! 861: goto check;
! 862:
! 863: switch (dlc->rd_state) {
! 864: case RFCOMM_DLC_WAIT_RECV_UA: /* We sent SABM */
! 865: rfcomm_dlc_open(dlc);
! 866: return;
! 867:
! 868: case RFCOMM_DLC_WAIT_DISCONNECT: /* We sent DISC */
! 869: rfcomm_dlc_close(dlc, 0);
! 870: break;
! 871:
! 872: default:
! 873: DPRINTF("Received spurious UA(%d)!\n", dlci);
! 874: return;
! 875: }
! 876:
! 877: check: /* last one out turns out the light */
! 878: if (LIST_EMPTY(&rs->rs_dlcs)) {
! 879: rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
! 880: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
! 881: timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
! 882: }
! 883: }
! 884:
! 885: /*
! 886: * Receive Disconnected Mode Response
! 887: *
! 888: * If this does not apply to a known DLC then we may ignore it.
! 889: */
! 890: static void
! 891: rfcomm_session_recv_dm(struct rfcomm_session *rs, int dlci)
! 892: {
! 893: struct rfcomm_dlc *dlc;
! 894:
! 895: DPRINTFN(5, "DM(%d)\n", dlci);
! 896:
! 897: dlc = rfcomm_dlc_lookup(rs, dlci);
! 898: if (dlc == NULL)
! 899: return;
! 900:
! 901: if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT)
! 902: rfcomm_dlc_close(dlc, ECONNREFUSED);
! 903: else
! 904: rfcomm_dlc_close(dlc, ECONNRESET);
! 905: }
! 906:
! 907: /*
! 908: * Receive Unnumbered Information with Header check (MCC or data packet)
! 909: */
! 910: static void
! 911: rfcomm_session_recv_uih(struct rfcomm_session *rs, int dlci,
! 912: int pf, struct mbuf *m, int len)
! 913: {
! 914: struct rfcomm_dlc *dlc;
! 915: uint8_t credits = 0;
! 916:
! 917: DPRINTFN(10, "UIH(%d)\n", dlci);
! 918:
! 919: if (dlci == 0) {
! 920: rfcomm_session_recv_mcc(rs, m);
! 921: return;
! 922: }
! 923:
! 924: if (m->m_pkthdr.len != len + pf) {
! 925: DPRINTF("Bad Frame Length (%d), frame discarded\n",
! 926: m->m_pkthdr.len);
! 927:
! 928: goto discard;
! 929: }
! 930:
! 931: dlc = rfcomm_dlc_lookup(rs, dlci);
! 932: if (dlc == NULL) {
! 933: DPRINTF("UIH received for non existent DLC, discarded\n");
! 934: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
! 935: goto discard;
! 936: }
! 937:
! 938: if (dlc->rd_state != RFCOMM_DLC_OPEN) {
! 939: DPRINTF("non-open DLC (state = %d), discarded\n",
! 940: dlc->rd_state);
! 941: goto discard;
! 942: }
! 943:
! 944: /* if PF is set, credits were included */
! 945: if (rs->rs_flags & RFCOMM_SESSION_CFC) {
! 946: if (pf != 0) {
! 947: if (m->m_pkthdr.len < sizeof(credits)) {
! 948: DPRINTF("Bad PF value, UIH discarded\n");
! 949: goto discard;
! 950: }
! 951:
! 952: m_copydata(m, 0, sizeof(credits), &credits);
! 953: m_adj(m, sizeof(credits));
! 954:
! 955: dlc->rd_txcred += credits;
! 956:
! 957: if (credits > 0 && dlc->rd_txbuf != NULL)
! 958: rfcomm_dlc_start(dlc);
! 959: }
! 960:
! 961: if (len == 0)
! 962: goto discard;
! 963:
! 964: if (dlc->rd_rxcred == 0) {
! 965: DPRINTF("Credit limit reached, UIH discarded\n");
! 966: goto discard;
! 967: }
! 968:
! 969: if (len > dlc->rd_rxsize) {
! 970: DPRINTF("UIH frame exceeds rxsize, discarded\n");
! 971: goto discard;
! 972: }
! 973:
! 974: dlc->rd_rxcred--;
! 975: dlc->rd_rxsize -= len;
! 976: }
! 977:
! 978: (*dlc->rd_proto->input)(dlc->rd_upper, m);
! 979: return;
! 980:
! 981: discard:
! 982: m_freem(m);
! 983: }
! 984:
! 985: /*
! 986: * Receive Multiplexer Control Command
! 987: */
! 988: static void
! 989: rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m)
! 990: {
! 991: int type, cr, len;
! 992: uint8_t b;
! 993:
! 994: /*
! 995: * Extract MCC header.
! 996: *
! 997: * Fields are variable length using extension bit = 1 to signify the
! 998: * last octet in the sequence.
! 999: *
! 1000: * Only single octet types are defined in TS 07.10/RFCOMM spec
! 1001: *
! 1002: * Length can realistically only use 15 bits (max RFCOMM MTU)
! 1003: */
! 1004: if (m->m_pkthdr.len < sizeof(b)) {
! 1005: DPRINTF("Short MCC header, discarded\n");
! 1006: goto release;
! 1007: }
! 1008:
! 1009: m_copydata(m, 0, sizeof(b), &b);
! 1010: m_adj(m, sizeof(b));
! 1011:
! 1012: if (RFCOMM_EA(b) == 0) { /* verify no extensions */
! 1013: DPRINTF("MCC type EA = 0, discarded\n");
! 1014: goto release;
! 1015: }
! 1016:
! 1017: type = RFCOMM_MCC_TYPE(b);
! 1018: cr = RFCOMM_CR(b);
! 1019:
! 1020: len = 0;
! 1021: do {
! 1022: if (m->m_pkthdr.len < sizeof(b)) {
! 1023: DPRINTF("Short MCC header, discarded\n");
! 1024: goto release;
! 1025: }
! 1026:
! 1027: m_copydata(m, 0, sizeof(b), &b);
! 1028: m_adj(m, sizeof(b));
! 1029:
! 1030: len = (len << 7) | (b >> 1);
! 1031: len = min(len, RFCOMM_MTU_MAX);
! 1032: } while (RFCOMM_EA(b) == 0);
! 1033:
! 1034: if (len != m->m_pkthdr.len) {
! 1035: DPRINTF("Incorrect MCC length, discarded\n");
! 1036: goto release;
! 1037: }
! 1038:
! 1039: DPRINTFN(2, "MCC %s type %2.2x (%d bytes)\n",
! 1040: (cr ? "command" : "response"), type, len);
! 1041:
! 1042: /*
! 1043: * pass to command handler
! 1044: */
! 1045: switch(type) {
! 1046: case RFCOMM_MCC_TEST: /* Test */
! 1047: rfcomm_session_recv_mcc_test(rs, cr, m);
! 1048: break;
! 1049:
! 1050: case RFCOMM_MCC_FCON: /* Flow Control On */
! 1051: rfcomm_session_recv_mcc_fcon(rs, cr);
! 1052: break;
! 1053:
! 1054: case RFCOMM_MCC_FCOFF: /* Flow Control Off */
! 1055: rfcomm_session_recv_mcc_fcoff(rs, cr);
! 1056: break;
! 1057:
! 1058: case RFCOMM_MCC_MSC: /* Modem Status Command */
! 1059: rfcomm_session_recv_mcc_msc(rs, cr, m);
! 1060: break;
! 1061:
! 1062: case RFCOMM_MCC_RPN: /* Remote Port Negotiation */
! 1063: rfcomm_session_recv_mcc_rpn(rs, cr, m);
! 1064: break;
! 1065:
! 1066: case RFCOMM_MCC_RLS: /* Remote Line Status */
! 1067: rfcomm_session_recv_mcc_rls(rs, cr, m);
! 1068: break;
! 1069:
! 1070: case RFCOMM_MCC_PN: /* Parameter Negotiation */
! 1071: rfcomm_session_recv_mcc_pn(rs, cr, m);
! 1072: break;
! 1073:
! 1074: case RFCOMM_MCC_NSC: /* Non Supported Command */
! 1075: rfcomm_session_recv_mcc_nsc(rs, cr, m);
! 1076: break;
! 1077:
! 1078: default:
! 1079: b = RFCOMM_MKMCC_TYPE(cr, type);
! 1080: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_NSC, &b, sizeof(b));
! 1081: }
! 1082:
! 1083: release:
! 1084: m_freem(m);
! 1085: }
! 1086:
! 1087: /*
! 1088: * process TEST command/response
! 1089: */
! 1090: static void
! 1091: rfcomm_session_recv_mcc_test(struct rfcomm_session *rs, int cr, struct mbuf *m)
! 1092: {
! 1093: void *data;
! 1094: int len;
! 1095:
! 1096: if (cr == 0) /* ignore ack */
! 1097: return;
! 1098:
! 1099: /*
! 1100: * we must send all the data they included back as is
! 1101: */
! 1102:
! 1103: len = m->m_pkthdr.len;
! 1104: if (len > RFCOMM_MTU_MAX)
! 1105: return;
! 1106:
! 1107: data = malloc(len, M_BLUETOOTH, M_NOWAIT);
! 1108: if (data == NULL)
! 1109: return;
! 1110:
! 1111: m_copydata(m, 0, len, data);
! 1112: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_TEST, data, len);
! 1113: free(data, M_BLUETOOTH);
! 1114: }
! 1115:
! 1116: /*
! 1117: * process Flow Control ON command/response
! 1118: */
! 1119: static void
! 1120: rfcomm_session_recv_mcc_fcon(struct rfcomm_session *rs, int cr)
! 1121: {
! 1122:
! 1123: if (cr == 0) /* ignore ack */
! 1124: return;
! 1125:
! 1126: rs->rs_flags |= RFCOMM_SESSION_RFC;
! 1127: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCON, NULL, 0);
! 1128: }
! 1129:
! 1130: /*
! 1131: * process Flow Control OFF command/response
! 1132: */
! 1133: static void
! 1134: rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *rs, int cr)
! 1135: {
! 1136:
! 1137: if (cr == 0) /* ignore ack */
! 1138: return;
! 1139:
! 1140: rs->rs_flags &= ~RFCOMM_SESSION_RFC;
! 1141: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCOFF, NULL, 0);
! 1142: }
! 1143:
! 1144: /*
! 1145: * process Modem Status Command command/response
! 1146: */
! 1147: static void
! 1148: rfcomm_session_recv_mcc_msc(struct rfcomm_session *rs, int cr, struct mbuf *m)
! 1149: {
! 1150: struct rfcomm_mcc_msc msc; /* (3 octets) */
! 1151: struct rfcomm_dlc *dlc;
! 1152: int len = 0;
! 1153:
! 1154: /* [ADDRESS] */
! 1155: if (m->m_pkthdr.len < sizeof(msc.address))
! 1156: return;
! 1157:
! 1158: m_copydata(m, 0, sizeof(msc.address), &msc.address);
! 1159: m_adj(m, sizeof(msc.address));
! 1160: len += sizeof(msc.address);
! 1161:
! 1162: dlc = rfcomm_dlc_lookup(rs, RFCOMM_DLCI(msc.address));
! 1163:
! 1164: if (cr == 0) { /* ignore acks */
! 1165: if (dlc != NULL)
! 1166: timeout_del(&dlc->rd_timeout);
! 1167:
! 1168: return;
! 1169: }
! 1170:
! 1171: if (dlc == NULL) {
! 1172: rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM,
! 1173: RFCOMM_DLCI(msc.address));
! 1174: return;
! 1175: }
! 1176:
! 1177: /* [SIGNALS] */
! 1178: if (m->m_pkthdr.len < sizeof(msc.modem))
! 1179: return;
! 1180:
! 1181: m_copydata(m, 0, sizeof(msc.modem), &msc.modem);
! 1182: m_adj(m, sizeof(msc.modem));
! 1183: len += sizeof(msc.modem);
! 1184:
! 1185: dlc->rd_rmodem = msc.modem;
! 1186: /* XXX how do we signal this upstream? */
! 1187:
! 1188: if (RFCOMM_EA(msc.modem) == 0) {
! 1189: if (m->m_pkthdr.len < sizeof(msc.brk))
! 1190: return;
! 1191:
! 1192: m_copydata(m, 0, sizeof(msc.brk), &msc.brk);
! 1193: m_adj(m, sizeof(msc.brk));
! 1194: len += sizeof(msc.brk);
! 1195:
! 1196: /* XXX how do we signal this upstream? */
! 1197: }
! 1198:
! 1199: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_MSC, &msc, len);
! 1200: }
! 1201:
! 1202: /*
! 1203: * process Remote Port Negotiation command/response
! 1204: */
! 1205: static void
! 1206: rfcomm_session_recv_mcc_rpn(struct rfcomm_session *rs, int cr, struct mbuf *m)
! 1207: {
! 1208: struct rfcomm_mcc_rpn rpn;
! 1209: uint16_t mask;
! 1210:
! 1211: if (cr == 0) /* ignore ack */
! 1212: return;
! 1213:
! 1214: /* default values */
! 1215: rpn.bit_rate = RFCOMM_RPN_BR_9600;
! 1216: rpn.line_settings = RFCOMM_RPN_8_N_1;
! 1217: rpn.flow_control = RFCOMM_RPN_FLOW_NONE;
! 1218: rpn.xon_char = RFCOMM_RPN_XON_CHAR;
! 1219: rpn.xoff_char = RFCOMM_RPN_XOFF_CHAR;
! 1220:
! 1221: if (m->m_pkthdr.len == sizeof(rpn)) {
! 1222: m_copydata(m, 0, sizeof(rpn), (caddr_t)&rpn);
! 1223: rpn.param_mask = RFCOMM_RPN_PM_ALL;
! 1224: } else if (m->m_pkthdr.len == 1) {
! 1225: m_copydata(m, 0, 1, (caddr_t)&rpn);
! 1226: rpn.param_mask = letoh16(rpn.param_mask);
! 1227: } else {
! 1228: DPRINTF("Bad RPN length (%d)\n", m->m_pkthdr.len);
! 1229: return;
! 1230: }
! 1231:
! 1232: mask = 0;
! 1233:
! 1234: if (rpn.param_mask & RFCOMM_RPN_PM_RATE)
! 1235: mask |= RFCOMM_RPN_PM_RATE;
! 1236:
! 1237: if (rpn.param_mask & RFCOMM_RPN_PM_DATA
! 1238: && RFCOMM_RPN_DATA_BITS(rpn.line_settings) == RFCOMM_RPN_DATA_8)
! 1239: mask |= RFCOMM_RPN_PM_DATA;
! 1240:
! 1241: if (rpn.param_mask & RFCOMM_RPN_PM_STOP
! 1242: && RFCOMM_RPN_STOP_BITS(rpn.line_settings) == RFCOMM_RPN_STOP_1)
! 1243: mask |= RFCOMM_RPN_PM_STOP;
! 1244:
! 1245: if (rpn.param_mask & RFCOMM_RPN_PM_PARITY
! 1246: && RFCOMM_RPN_PARITY(rpn.line_settings) == RFCOMM_RPN_PARITY_NONE)
! 1247: mask |= RFCOMM_RPN_PM_PARITY;
! 1248:
! 1249: if (rpn.param_mask & RFCOMM_RPN_PM_XON
! 1250: && rpn.xon_char == RFCOMM_RPN_XON_CHAR)
! 1251: mask |= RFCOMM_RPN_PM_XON;
! 1252:
! 1253: if (rpn.param_mask & RFCOMM_RPN_PM_XOFF
! 1254: && rpn.xoff_char == RFCOMM_RPN_XOFF_CHAR)
! 1255: mask |= RFCOMM_RPN_PM_XOFF;
! 1256:
! 1257: if (rpn.param_mask & RFCOMM_RPN_PM_FLOW
! 1258: && rpn.flow_control == RFCOMM_RPN_FLOW_NONE)
! 1259: mask |= RFCOMM_RPN_PM_FLOW;
! 1260:
! 1261: rpn.param_mask = htole16(mask);
! 1262:
! 1263: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RPN, &rpn, sizeof(rpn));
! 1264: }
! 1265:
! 1266: /*
! 1267: * process Remote Line Status command/response
! 1268: */
! 1269: static void
! 1270: rfcomm_session_recv_mcc_rls(struct rfcomm_session *rs, int cr, struct mbuf *m)
! 1271: {
! 1272: struct rfcomm_mcc_rls rls;
! 1273:
! 1274: if (cr == 0) /* ignore ack */
! 1275: return;
! 1276:
! 1277: if (m->m_pkthdr.len != sizeof(rls)) {
! 1278: DPRINTF("Bad RLS length %d\n", m->m_pkthdr.len);
! 1279: return;
! 1280: }
! 1281:
! 1282: m_copydata(m, 0, sizeof(rls), (caddr_t)&rls);
! 1283:
! 1284: /*
! 1285: * So far as I can tell, we just send back what
! 1286: * they sent us. This signifies errors that seem
! 1287: * irrelevent for RFCOMM over L2CAP.
! 1288: */
! 1289: rls.address |= 0x03; /* EA = 1, CR = 1 */
! 1290: rls.status &= 0x0f; /* only 4 bits valid */
! 1291:
! 1292: rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RLS, &rls, sizeof(rls));
! 1293: }
! 1294:
! 1295: /*
! 1296: * process Parameter Negotiation command/response
! 1297: */
! 1298: static void
! 1299: rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m)
! 1300: {
! 1301: struct rfcomm_dlc *dlc;
! 1302: struct rfcomm_mcc_pn pn;
! 1303: int err;
! 1304:
! 1305: if (m->m_pkthdr.len != sizeof(pn)) {
! 1306: DPRINTF("Bad PN length %d\n", m->m_pkthdr.len);
! 1307: return;
! 1308: }
! 1309:
! 1310: m_copydata(m, 0, sizeof(pn), (caddr_t)&pn);
! 1311:
! 1312: pn.dlci &= 0x3f;
! 1313: pn.mtu = letoh16(pn.mtu);
! 1314:
! 1315: dlc = rfcomm_dlc_lookup(rs, pn.dlci);
! 1316: if (cr) { /* Command */
! 1317: /*
! 1318: * If there is no DLC present, this is a new
! 1319: * connection so attempt to make one
! 1320: */
! 1321: if (dlc == NULL) {
! 1322: dlc = rfcomm_dlc_newconn(rs, pn.dlci);
! 1323: if (dlc == NULL)
! 1324: return; /* (DM is sent) */
! 1325: }
! 1326:
! 1327: /* accept any valid MTU, and offer it back */
! 1328: pn.mtu = min(pn.mtu, RFCOMM_MTU_MAX);
! 1329: pn.mtu = min(pn.mtu, rs->rs_mtu);
! 1330: pn.mtu = max(pn.mtu, RFCOMM_MTU_MIN);
! 1331: dlc->rd_mtu = pn.mtu;
! 1332: pn.mtu = htole16(pn.mtu);
! 1333:
! 1334: /* credits are only set before DLC is open */
! 1335: if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
! 1336: && (pn.flow_control & 0xf0) == 0xf0) {
! 1337: rs->rs_flags |= RFCOMM_SESSION_CFC;
! 1338: dlc->rd_txcred = pn.credits & 0x07;
! 1339:
! 1340: dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
! 1341: dlc->rd_rxcred = min(dlc->rd_rxcred,
! 1342: RFCOMM_CREDITS_DEFAULT);
! 1343:
! 1344: pn.flow_control = 0xe0;
! 1345: pn.credits = dlc->rd_rxcred;
! 1346: } else {
! 1347: pn.flow_control = 0x00;
! 1348: pn.credits = 0x00;
! 1349: }
! 1350:
! 1351: /* unused fields must be ignored and set to zero */
! 1352: pn.ack_timer = 0;
! 1353: pn.max_retrans = 0;
! 1354:
! 1355: /* send our response */
! 1356: err = rfcomm_session_send_mcc(rs, 0,
! 1357: RFCOMM_MCC_PN, &pn, sizeof(pn));
! 1358: if (err)
! 1359: goto close;
! 1360:
! 1361: } else { /* Response */
! 1362: /* ignore responses with no matching DLC */
! 1363: if (dlc == NULL)
! 1364: return;
! 1365:
! 1366: timeout_del(&dlc->rd_timeout);
! 1367:
! 1368: if (pn.mtu > RFCOMM_MTU_MAX || pn.mtu > dlc->rd_mtu) {
! 1369: dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
! 1370: err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
! 1371: pn.dlci);
! 1372: if (err)
! 1373: goto close;
! 1374:
! 1375: timeout_add(&dlc->rd_timeout,
! 1376: rfcomm_ack_timeout * hz);
! 1377: return;
! 1378: }
! 1379: dlc->rd_mtu = pn.mtu;
! 1380:
! 1381: /* if DLC is not waiting to connect, we are done */
! 1382: if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
! 1383: return;
! 1384:
! 1385: /* set initial credits according to RFCOMM spec */
! 1386: if ((pn.flow_control & 0xf0) == 0xe0) {
! 1387: rs->rs_flags |= RFCOMM_SESSION_CFC;
! 1388: dlc->rd_txcred = (pn.credits & 0x07);
! 1389: }
! 1390:
! 1391: timeout_add(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
! 1392:
! 1393: /* set link mode */
! 1394: err = rfcomm_dlc_setmode(dlc);
! 1395: if (err == EINPROGRESS) {
! 1396: dlc->rd_state = RFCOMM_DLC_WAIT_SEND_SABM;
! 1397: (*dlc->rd_proto->connecting)(dlc->rd_upper);
! 1398: return;
! 1399: }
! 1400: if (err)
! 1401: goto close;
! 1402:
! 1403: /* we can proceed now */
! 1404: err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci);
! 1405: if (err)
! 1406: goto close;
! 1407:
! 1408: dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
! 1409: }
! 1410: return;
! 1411:
! 1412: close:
! 1413: rfcomm_dlc_close(dlc, err);
! 1414: }
! 1415:
! 1416: /*
! 1417: * process Non Supported Command command/response
! 1418: */
! 1419: static void
! 1420: rfcomm_session_recv_mcc_nsc(struct rfcomm_session *rs,
! 1421: int cr, struct mbuf *m)
! 1422: {
! 1423: struct rfcomm_dlc *dlc, *next;
! 1424:
! 1425: /*
! 1426: * Since we did nothing that is not mandatory,
! 1427: * we just abort the whole session..
! 1428: */
! 1429:
! 1430: next = LIST_FIRST(&rs->rs_dlcs);
! 1431: while ((dlc = next) != NULL) {
! 1432: next = LIST_NEXT(dlc, rd_next);
! 1433: rfcomm_dlc_close(dlc, ECONNABORTED);
! 1434: }
! 1435:
! 1436: rfcomm_session_free(rs);
! 1437: }
! 1438:
! 1439: /***********************************************************************
! 1440: *
! 1441: * RFCOMM Session outward frame/uih/mcc building
! 1442: */
! 1443:
! 1444: /*
! 1445: * SABM/DISC/DM/UA frames are all minimal and mostly identical.
! 1446: */
! 1447: int
! 1448: rfcomm_session_send_frame(struct rfcomm_session *rs, int type, int dlci)
! 1449: {
! 1450: struct rfcomm_cmd_hdr *hdr;
! 1451: struct rfcomm_credit *credit;
! 1452: struct mbuf *m;
! 1453: uint8_t fcs, cr;
! 1454:
! 1455: credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
! 1456: if (credit == NULL)
! 1457: return ENOMEM;
! 1458:
! 1459: m = m_gethdr(M_DONTWAIT, MT_DATA);
! 1460: if (m == NULL) {
! 1461: pool_put(&rfcomm_credit_pool, credit);
! 1462: return ENOMEM;
! 1463: }
! 1464:
! 1465: /*
! 1466: * The CR (command/response) bit identifies the frame either as a
! 1467: * commmand or a response and is used along with the DLCI to form
! 1468: * the address. Commands contain the non-initiator address, whereas
! 1469: * responses contain the initiator address, so the CR value is
! 1470: * also dependent on the session direction.
! 1471: */
! 1472: if (type == RFCOMM_FRAME_UA || type == RFCOMM_FRAME_DM)
! 1473: cr = IS_INITIATOR(rs) ? 0 : 1;
! 1474: else
! 1475: cr = IS_INITIATOR(rs) ? 1 : 0;
! 1476:
! 1477: hdr = mtod(m, struct rfcomm_cmd_hdr *);
! 1478: hdr->address = RFCOMM_MKADDRESS(cr, dlci);
! 1479: hdr->control = RFCOMM_MKCONTROL(type, 1); /* PF = 1 */
! 1480: hdr->length = (0x00 << 1) | 0x01; /* len = 0x00, EA = 1 */
! 1481:
! 1482: fcs = 0xff;
! 1483: fcs = FCS(fcs, hdr->address);
! 1484: fcs = FCS(fcs, hdr->control);
! 1485: fcs = FCS(fcs, hdr->length);
! 1486: fcs = 0xff - fcs; /* ones complement */
! 1487: hdr->fcs = fcs;
! 1488:
! 1489: m->m_pkthdr.len = m->m_len = sizeof(struct rfcomm_cmd_hdr);
! 1490:
! 1491: /* empty credit note */
! 1492: credit->rc_dlc = NULL;
! 1493: credit->rc_len = m->m_pkthdr.len;
! 1494: SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
! 1495:
! 1496: DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n",
! 1497: dlci, type, m->m_pkthdr.len, fcs);
! 1498:
! 1499: return l2cap_send(rs->rs_l2cap, m);
! 1500: }
! 1501:
! 1502: /*
! 1503: * rfcomm_session_send_uih(rfcomm_session, rfcomm_dlc, credits, mbuf)
! 1504: *
! 1505: * UIH frame is per DLC data or Multiplexer Control Commands
! 1506: * when no DLC is given. Data mbuf is optional (just credits
! 1507: * will be sent in that case)
! 1508: */
! 1509: int
! 1510: rfcomm_session_send_uih(struct rfcomm_session *rs, struct rfcomm_dlc *dlc,
! 1511: int credits, struct mbuf *m)
! 1512: {
! 1513: struct rfcomm_credit *credit;
! 1514: struct mbuf *m0 = NULL;
! 1515: int err, len;
! 1516: uint8_t fcs, *hdr;
! 1517:
! 1518: KASSERT(rs != NULL);
! 1519:
! 1520: len = (m == NULL) ? 0 : m->m_pkthdr.len;
! 1521: KASSERT(!(credits == 0 && len == 0));
! 1522:
! 1523: /*
! 1524: * Make a credit note for the completion notification
! 1525: */
! 1526: credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
! 1527: if (credit == NULL)
! 1528: goto nomem;
! 1529:
! 1530: credit->rc_len = len;
! 1531: credit->rc_dlc = dlc;
! 1532:
! 1533: /*
! 1534: * Wrap UIH frame information around payload.
! 1535: *
! 1536: * [ADDRESS] [CONTROL] [LENGTH] [CREDITS] [...] [FCS]
! 1537: *
! 1538: * Address is one octet.
! 1539: * Control is one octet.
! 1540: * Length is one or two octets.
! 1541: * Credits may be one octet.
! 1542: *
! 1543: * FCS is one octet and calculated on address and
! 1544: * control octets only.
! 1545: *
! 1546: * If there are credits to be sent, we will set the PF
! 1547: * flag and include them in the frame.
! 1548: */
! 1549: m0 = m_gethdr(M_DONTWAIT, MT_DATA);
! 1550: if (m0 == NULL)
! 1551: goto nomem;
! 1552:
! 1553: MH_ALIGN(m0, 5); /* (max 5 header octets) */
! 1554: hdr = mtod(m0, uint8_t *);
! 1555:
! 1556: /* CR bit is set according to the initiator of the session */
! 1557: *hdr = RFCOMM_MKADDRESS((IS_INITIATOR(rs) ? 1 : 0),
! 1558: (dlc ? dlc->rd_dlci : 0));
! 1559: fcs = FCS(0xff, *hdr);
! 1560: hdr++;
! 1561:
! 1562: /* PF bit is set if credits are being sent */
! 1563: *hdr = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, (credits > 0 ? 1 : 0));
! 1564: fcs = FCS(fcs, *hdr);
! 1565: hdr++;
! 1566:
! 1567: if (len < (1 << 7)) {
! 1568: *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
! 1569: } else {
! 1570: *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
! 1571: *hdr++ = ((len >> 7) & 0xff); /* 8 bits, no EA */
! 1572: }
! 1573:
! 1574: if (credits > 0)
! 1575: *hdr++ = (uint8_t)credits;
! 1576:
! 1577: m0->m_len = hdr - mtod(m0, uint8_t *);
! 1578:
! 1579: /* Append payload */
! 1580: m0->m_next = m;
! 1581: m = NULL;
! 1582:
! 1583: m0->m_pkthdr.len = m0->m_len + len;
! 1584:
! 1585: /* Append FCS */
! 1586: fcs = 0xff - fcs; /* ones complement */
! 1587: len = m0->m_pkthdr.len;
! 1588: m_copyback(m0, len, sizeof(fcs), &fcs);
! 1589: if (m0->m_pkthdr.len != len + sizeof(fcs))
! 1590: goto nomem;
! 1591:
! 1592: DPRINTFN(10, "dlci %d, pktlen %d (%d data, %d credits), fcs=%#2.2x\n",
! 1593: dlc ? dlc->rd_dlci : 0, m0->m_pkthdr.len, credit->rc_len,
! 1594: credits, fcs);
! 1595:
! 1596: /*
! 1597: * UIH frame ready to go..
! 1598: */
! 1599: err = l2cap_send(rs->rs_l2cap, m0);
! 1600: if (err)
! 1601: goto fail;
! 1602:
! 1603: SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
! 1604: return 0;
! 1605:
! 1606: nomem:
! 1607: err = ENOMEM;
! 1608:
! 1609: if (m0 != NULL)
! 1610: m_freem(m0);
! 1611:
! 1612: if (m != NULL)
! 1613: m_freem(m);
! 1614:
! 1615: fail:
! 1616: if (credit != NULL)
! 1617: pool_put(&rfcomm_credit_pool, credit);
! 1618:
! 1619: return err;
! 1620: }
! 1621:
! 1622: /*
! 1623: * send Multiplexer Control Command (or Response) on session
! 1624: */
! 1625: int
! 1626: rfcomm_session_send_mcc(struct rfcomm_session *rs, int cr,
! 1627: uint8_t type, void *data, int len)
! 1628: {
! 1629: struct mbuf *m;
! 1630: uint8_t *hdr;
! 1631: int hlen;
! 1632:
! 1633: m = m_gethdr(M_DONTWAIT, MT_DATA);
! 1634: if (m == NULL)
! 1635: return ENOMEM;
! 1636:
! 1637: hdr = mtod(m, uint8_t *);
! 1638:
! 1639: /*
! 1640: * Technically the type field can extend past one octet, but none
! 1641: * currently defined will do that.
! 1642: */
! 1643: *hdr++ = RFCOMM_MKMCC_TYPE(cr, type);
! 1644:
! 1645: /*
! 1646: * In the frame, the max length size is 2 octets (15 bits) whereas
! 1647: * no max length size is specified for MCC commands. We must allow
! 1648: * for 3 octets since for MCC frames we use 7 bits + EA in each.
! 1649: *
! 1650: * Only test data can possibly be that big.
! 1651: *
! 1652: * XXX Should we check this against the MTU?
! 1653: */
! 1654: if (len < (1 << 7)) {
! 1655: *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
! 1656: } else if (len < (1 << 14)) {
! 1657: *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
! 1658: *hdr++ = ((len >> 6) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
! 1659: } else if (len < (1 << 15)) {
! 1660: *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
! 1661: *hdr++ = ((len >> 6) & 0xfe); /* 7 bits, EA = 0 */
! 1662: *hdr++ = ((len >> 13) & 0x02) | 0x01; /* 1 bit, EA = 1 */
! 1663: } else {
! 1664: DPRINTF("incredible length! (%d)\n", len);
! 1665: m_freem(m);
! 1666: return EMSGSIZE;
! 1667: }
! 1668:
! 1669: /*
! 1670: * add command data (to same mbuf if possible)
! 1671: */
! 1672: hlen = hdr - mtod(m, uint8_t *);
! 1673:
! 1674: if (len > 0) {
! 1675: m->m_pkthdr.len = m->m_len = MHLEN;
! 1676: m_copyback(m, hlen, len, data);
! 1677: if (m->m_pkthdr.len != max(MHLEN, hlen + len)) {
! 1678: m_freem(m);
! 1679: return ENOMEM;
! 1680: }
! 1681: }
! 1682:
! 1683: m->m_pkthdr.len = hlen + len;
! 1684: m->m_len = min(MHLEN, m->m_pkthdr.len);
! 1685:
! 1686: DPRINTFN(5, "%s type %2.2x len %d\n",
! 1687: (cr ? "command" : "response"), type, m->m_pkthdr.len);
! 1688:
! 1689: return rfcomm_session_send_uih(rs, NULL, 0, m);
! 1690: }
CVSweb