Bluetooth: RFCOMM: Handle security for outgoing DLCs

Security needs to be elevated based on dlc required sec_level
before creating dlc. If L2CAP connection is not created then
setting dlc required sec_level to chan would do the job.

Change-Id: I21debd3559c9ccfb79011160d676932bc2a54604
Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com>
This commit is contained in:
Jaganath Kanakkassery 2016-11-11 21:37:37 +05:30 committed by Johan Hedberg
commit dd94c3b3eb

View file

@ -718,29 +718,46 @@ static int rfcomm_send_credit(struct bt_rfcomm_dlc *dlc, uint8_t credits)
return bt_l2cap_chan_send(&dlc->session->br_chan.chan, buf); return bt_l2cap_chan_send(&dlc->session->br_chan.chan, buf);
} }
static void rfcomm_dlc_start(struct bt_rfcomm_dlc *dlc) static int rfcomm_dlc_start(struct bt_rfcomm_dlc *dlc)
{ {
enum security_result result;
BT_DBG("dlc %p", dlc); BT_DBG("dlc %p", dlc);
/* TODO: Need to check Security */ result = rfcomm_dlc_security(dlc);
dlc->mtu = min(dlc->mtu, dlc->session->mtu); switch (result) {
dlc->state = BT_RFCOMM_STATE_CONFIG; case RFCOMM_SECURITY_PASSED:
rfcomm_send_pn(dlc, BT_RFCOMM_MSG_CMD_CR); dlc->mtu = min(dlc->mtu, dlc->session->mtu);
dlc->state = BT_RFCOMM_STATE_CONFIG;
rfcomm_send_pn(dlc, BT_RFCOMM_MSG_CMD_CR);
break;
case RFCOMM_SECURITY_PENDING:
dlc->state = BT_RFCOMM_STATE_SECURITY_PENDING;
break;
case RFCOMM_SECURITY_REJECT:
default:
return -EIO;
}
return 0;
} }
static void rfcomm_handle_ua(struct bt_rfcomm_session *session, uint8_t dlci) static void rfcomm_handle_ua(struct bt_rfcomm_session *session, uint8_t dlci)
{ {
struct bt_rfcomm_dlc *dlc; struct bt_rfcomm_dlc *dlc, *tmp;
if (!dlci) { if (!dlci) {
if (session->state != BT_RFCOMM_STATE_CONNECTING) { if (session->state != BT_RFCOMM_STATE_CONNECTING) {
return; return;
} }
session->state = BT_RFCOMM_STATE_CONNECTED; session->state = BT_RFCOMM_STATE_CONNECTED;
for (dlc = session->dlcs; dlc; dlc = dlc->_next) { for (dlc = session->dlcs; dlc; dlc = tmp) {
tmp = dlc->_next;
if (dlc->role == BT_RFCOMM_ROLE_INITIATOR && if (dlc->role == BT_RFCOMM_ROLE_INITIATOR &&
dlc->state == BT_RFCOMM_STATE_INIT) { dlc->state == BT_RFCOMM_STATE_INIT) {
rfcomm_dlc_start(dlc); if (rfcomm_dlc_start(dlc) < 0) {
rfcomm_dlc_drop(dlc);
}
} }
} }
} else { } else {
@ -1058,6 +1075,10 @@ static void rfcomm_encrypt_change(struct bt_l2cap_chan *chan,
if (dlc->role == BT_RFCOMM_ROLE_ACCEPTOR) { if (dlc->role == BT_RFCOMM_ROLE_ACCEPTOR) {
rfcomm_send_ua(session, dlc->dlci); rfcomm_send_ua(session, dlc->dlci);
rfcomm_dlc_connected(dlc); rfcomm_dlc_connected(dlc);
} else {
dlc->mtu = min(dlc->mtu, session->mtu);
dlc->state = BT_RFCOMM_STATE_CONFIG;
rfcomm_send_pn(dlc, BT_RFCOMM_MSG_CMD_CR);
} }
} }
} }
@ -1141,6 +1162,7 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc,
break; break;
} }
chan = &session->br_chan.chan; chan = &session->br_chan.chan;
chan->required_sec_level = dlc->required_sec_level;
ret = bt_l2cap_chan_connect(conn, chan, BT_L2CAP_PSM_RFCOMM); ret = bt_l2cap_chan_connect(conn, chan, BT_L2CAP_PSM_RFCOMM);
if (ret < 0) { if (ret < 0) {
session->state = BT_RFCOMM_STATE_IDLE; session->state = BT_RFCOMM_STATE_IDLE;
@ -1151,7 +1173,10 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc,
case BT_RFCOMM_STATE_CONNECTING: case BT_RFCOMM_STATE_CONNECTING:
break; break;
case BT_RFCOMM_STATE_CONNECTED: case BT_RFCOMM_STATE_CONNECTED:
rfcomm_dlc_start(dlc); ret = rfcomm_dlc_start(dlc);
if (ret < 0) {
goto fail;
}
break; break;
default: default:
BT_ERR("Invalid session state %d", session->state); BT_ERR("Invalid session state %d", session->state);