blob: b776c2541a8e508739fe613c6ff394fb8ce96d48 [file] [log] [blame]
/*
* Copyright 2018 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef _L2CAP_H_
#define _L2CAP_H_
#include "newblue-macros.h"
#include "multiNotif.h"
#include "types.h"
#include "uniq.h"
#include "hci.h"
#include "bt.h"
#include "sg.h"
NEWBLUE_BEGIN_DECLS
#define OUR_MTU 0xEFFF /* no reason to limit it pointlessly */
#define L2C_MAX_SAFE_MTU 0x7FFF /* some buggy devices think MTU is signed. This is safe */
typedef uint16_t psm_t;
typedef uniq_t l2c_handle_t; /* a 0-valued handle is invalid and indicates error */
typedef uniq_t acl_handle_t; /* a 0-valued handle is invalid and indicates error */
#define HANDLEFMT UNIQ_FMT"x"
#define HANDLECNV(x) UNIQ_CONV(x)
/* ONE_TIME L2CAP INIT */
/* call this to perform one-time init of l2cap */
int l2cInit(void) NEWBLUE_EXPORT;
void l2cDeinit(void) NEWBLUE_EXPORT;
#define L2C_TX_ACCEPTED 0 /* data will be sent if connection remains - done */
#define L2C_TX_NO_CONN 1 /* no such connection - do not retry */
#define L2C_TX_TRY_LATER 2 /* no send capacity now - retry later */
#define L2C_TX_ERROR 3 /* some other error - do not retry */
/* HIGHER LAYER INTERFACE API */
/* callbacks for connections */
struct l2cEncrState {
bool isEncr;
bool isMitmSafe;
};
struct l2cKeyReqState {
uint64_t rand;
uint16_t ediv;
};
#define L2C_STATE_OPEN 0 /* dataPtr points to l2c_handle_t */
#define L2C_STATE_MTU 1 /* dataPtr points to a uint16_t mtu */
#define L2C_STATE_ENCR 2 /* dataPtr points l2cEncrState */
#define L2C_STATE_RX 3 /* dataPtr points to an sg */
#define L2C_STATE_KEY_REQ 4 /* if you are the security manager - key request came in - reply via l2cApiLeProvideLtk(). dataPtr points to l2cKeyReqState */
#define L2C_STATE_ENCR_KEY_REF 5 /* dataPtr points l2cEncrState */
#define L2C_STATE_CLOSED 6 /* dataPtr points nowhere, or error on openining */
typedef void (*l2cStateCbk)(void *userData, void *instance, uint8_t state, const void *data, uint32_t len);
#define SVC_ALLOC_SUCCESS 0 /* must alloc state, success */
#define SVC_ALLOC_DEMAND_ENCR 1 /* return this instead of calling l2cApiDemandEncryption(...,false). do not allocate - you will be called again */
#define SVC_ALLOC_DEMAND_AUTH 2 /* return this instead of calling l2cApiDemandEncryption(..., true). do not allocate - you will be called again */
#define SVC_ALLOC_FAIL_SECURITY 3 /* not secure enough connection */
#define SVC_ALLOC_FAIL_BEING_REMOVED 4 /* being deallocated */
#define SVC_ALLOC_FAIL_NO_CONNS 5 /* do not support conns */
#define SVC_ALLOC_WAIT_FOR_AUTHORIZ 6 /* must alloc state but need user's OK. Standby */
#define SVC_ALLOC_FAIL_OTHER 7 /* some other failure */
/* a PSM-based service is described thusly */
struct l2cServicePsmDescriptor {
void *userData; /* passed to all callbacks */
/* these are null if connectionless only */
uint8_t (*serviceInstanceAlloc)(void *userData, l2c_handle_t handle, void **instanceP); /* return SVC_ALLOC_* */
l2cStateCbk serviceInstanceStateCbk; /* free when called with the close state */
uint16_t mtu; /* max data size we're willing to accept */
/* is null if connection-oriented only */
void (*serviceConnectionlessRx)(void *userData, l2c_handle_t handle, sg payload);
};
/* a FixedCh service is described thusly */
struct l2cServiceFixedChDescriptor {
void *userData; /* passed to all callbacks */
/* called when ACL connection with a party supporting this channel is opened */
uint8_t (*serviceFixedChAlloc)(void *userData, l2c_handle_t handle, void **instanceP); /* return SVC_ALLOC_* */
/* called when data is received */
l2cStateCbk serviceFixedChStateCbk; /* free when called with the close state */
};
typedef bool (*L2capDefaultSecurityManagerCbk)(hci_conn_t hciConn, uint64_t randomNum, uint16_t diversifier);
/* call this to register a PSM-based service. pass 0 for any psm. returns zero or your psm */
psm_t l2cApiServicePsmRegister(psm_t psm, const struct l2cServicePsmDescriptor *service);
/* call this to unregister a PSM-based service. callback called when done, if provided */
bool l2cApiServicePsmUnregister(psm_t psm, void (*doneCbk)(void*), void *cbkData);
/* call this to register a FixedCh service. */
bool l2cApiServiceFixedChRegister(uint16_t chan, const struct l2cServiceFixedChDescriptor *service);
/* call this to unregister a FixedCh service. callback called when done, if provided */
bool l2cApiServiceFixedChUnregister(uint16_t chan, void (*doneCbk)(void*), void *cbkData);
/* call this to connect to a remote PSM-based service Expect an MTU callback. */
bool l2cApiCreatePsmConnection(psm_t psm, const struct bt_addr *addr, uint16_t mtu, l2cStateCbk stateCbk, void *userData, void *instance);
/* call this to connect to a remote FixedCh service. Do not expect an MTU callback. */
bool l2cApiCreateFixedChConnection(uint16_t chan, const struct bt_addr *addr, l2cStateCbk stateCbk, void *userData, void *instance);
/* call this to request a connection parameter update for a given connection */
typedef void (*l2cConnUpdateDoneCbk)(void *userData, bool success);
bool l2cApiUpdateConnectionParams(l2c_handle_t handle, uint16_t intMin, uint16_t intMax, uint16_t latency, uint16_t timeout, l2cConnUpdateDoneCbk doneCbk, void *userData);
/* external code can use this to get remote's bt addr */
bool l2cApiGetBtAddr(l2c_handle_t handle, struct bt_addr *addrP);
/* external code can use this to get own bt addr used to make the connection */
bool l2cApiGetSelfBtAddr(l2c_handle_t handle, struct bt_addr *addrP) NEWBLUE_EXPORT;
/* external code can use this to get L2CAP's ACL handle */
acl_handle_t l2cApiGetAclHandle(l2c_handle_t handle);
/* external code can use this to see if a connection is encrypted */
bool l2cApiIsConnEncrypted(l2c_handle_t handle);
/* external code can use this to see if a connection is encrypted using a mitm-protected ket */
bool l2cApiIsConnMitmSafe(l2c_handle_t handle);
/* external code can use this to demand encrypted be used */
bool l2cApiDemandEncryption(l2c_handle_t handle, bool demandMitmSafe);
/* external code can use this to notify other size of athorization (only if your svc alloc returned SVC_ALLOC_WAIT_FOR_AUTHORIZ). */
bool l2cApiUserAthorizNotify(l2c_handle_t handle, bool authorized);
/* external code can use this to disconnect a channel */
void l2cApiDisconnect(l2c_handle_t handle);
/* external code can use this to send to the other side - never blocks. returns L2C_TX_* */
uint8_t l2cApiDataTx(l2c_handle_t handle, sg data);
/* external code can use this to know when it should retry its write. Do not do that in the callback! - queue it for later */
uniq_t l2cApiRegisterWriteBufNotif(multiNotifCbk cbk, void *cbkData);
/* external code can use this to unregister from notif created by l2cApiRegisterWriteBufNotif() */
void l2cApiUnegisterWriteBufNotif(uniq_t notifHandle);
/* if no connection exists, one will *not* be created. if sending does not work, there is no retry callback */
uint8_t l2cApiConnectionlessDataTx(const struct bt_addr *addr, psm_t psm, sg data);
/* external code can use this to encrypt a connection */
bool l2cApiLeEncryptConn(l2c_handle_t handle, uint64_t randomNum, uint16_t diversifier, const uint8_t *key);
/* external code can use this to become the "security manager" for a given acl connection. only one is allowed per acl conn - first come - first served */
bool l2cApiLeSetSecurityManagerForAclConn(l2c_handle_t handle);
/* external code can call this to provide a LTK (likely in a reply to L2C_STATE_KEY_REQ state message). pass NULL for "no" */
bool l2cApiLeProvideLtk(l2c_handle_t handle, const uint8_t *key);
/* external code can use this to become the "security manager" by default, l2cApiLeSetSecurityManagerForAclConn overrides this.
pass NULL to undo this. Note callback param is an HCI handle since no l2c connection may yet exist */
void l2cApiLeSetDefaultSecurityManager(L2capDefaultSecurityManagerCbk cbk);
/* LOWER LAYER INTERFACE API */
/* lower layer calls this when new ACL link is up */
void l2cAclLinkUp(hci_conn_t aclConn, const struct bt_addr *peerAddr, const struct bt_addr *selfAddr, bool isMaster, bool isEncrypted, bool isMitmSafe);
/* lower layer calls this when an ACL link is down */
void l2cAclLinkDown(hci_conn_t aclConn, uint8_t reason);
/* lower layer calls this when new ACL data arrives */
void l2cAclDataRx(hci_conn_t aclConn, sg packet, bool first);
/* lower layer calls this to tell us that a data credit just became available. called directly. DO NOT BLOCK! */
void l2cAclCreditAvail(bool le);
/* lower layer calls this when connection parameters change */
void l2cAclLinkParamsChange(hci_conn_t aclConn, bool success, uint16_t interval, uint16_t latency, uint16_t timeout);
/* lower layer calls this when connection encryption changes. called with FALSE if encr failed since BT cannot really go from encrypted to not */
void l2cAclLinkEncrChange(hci_conn_t aclConn, bool isEncrypted, bool isMitmSafe);
/* lower layer calls this when connection encryption request from the other side comes */
bool l2cAclLeLtkRequest(hci_conn_t aclConn, uint64_t rand, uint16_t ediv);
/* lower layer calls this when connection encryption key refreshed. called with FALSE if encr failed to resume with a new key since BT cannot really go from encrypted to not */
void l2cAclLinkEncrKeyRefresh(hci_conn_t aclConn, bool isEncrypted, bool isMitmSafe);
NEWBLUE_END_DECLS
#endif