static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; int len, err = 0; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); switch (optname) { case BT_SECURITY: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } memset(&sec, 0, sizeof(sec)); sec.level = l2cap_pi(sk)->sec_level; if (sk->sk_state == BT_CONNECTED) { sec.key_size = l2cap_pi(sk)->conn->hcon->enc_key_size; sec.level = l2cap_pi(sk)->conn->hcon->sec_level; } len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) err = -EFAULT; break; case BT_DEFER_SETUP: if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { err = -EINVAL; break; } if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) err = -EFAULT; break; case BT_POWER: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } pwr.force_active = l2cap_pi(sk)->force_active; len = min_t(unsigned int, len, sizeof(pwr)); if (copy_to_user(optval, (char *) &pwr, len)) err = -EFAULT; break; case BT_AMP_POLICY: if (put_user(l2cap_pi(sk)->amp_pref, (u32 __user *) optval)) err = -EFAULT; break; case BT_LE_PARAMS: if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { err = -EINVAL; break; } if (copy_to_user(optval, (char *) &bt_sk(sk)->le_params, sizeof(bt_sk(sk)->le_params))) err = -EFAULT; break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; BT_DBG("%s", hdev->name); hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { if (ev->link_type != SCO_LINK) goto unlock; conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr); if (!conn) goto unlock; conn->type = SCO_LINK; } if (!ev->status) { conn->handle = __le16_to_cpu(ev->handle); if (conn->type == ACL_LINK) { conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; } else conn->state = BT_CONNECTED; hci_conn_hold_device(conn); hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) conn->link_mode |= HCI_LM_AUTH; if (test_bit(HCI_ENCRYPT, &hdev->flags)) conn->link_mode |= HCI_LM_ENCRYPT; /* Get remote features */ if (conn->type == ACL_LINK) { struct hci_cp_read_remote_features cp; cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); } /* Set packet type for incoming connection */ if (!conn->out && hdev->hci_ver < 3) { struct hci_cp_change_conn_ptype cp; cp.handle = ev->handle; cp.pkt_type = cpu_to_le16(conn->pkt_type); hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp); } } else conn->state = BT_CLOSED; if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) { if (!ev->status) { if (lmp_esco_capable(hdev)) hci_setup_sync(sco, conn->handle); else hci_add_sco(sco, conn->handle); } else { hci_proto_connect_cfm(sco, ev->status); hci_conn_del(sco); } } } if (ev->status) { hci_proto_connect_cfm(conn, ev->status); hci_conn_del(conn); } else if (ev->link_type != ACL_LINK) hci_proto_connect_cfm(conn, ev->status); unlock: hci_dev_unlock(hdev); hci_conn_check_pending(hdev); }
static int bnep_net_set_mac_addr(struct net_device *dev, void *arg) { BT_DBG("%s", dev->name); return 0; }
static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); }
static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); }
static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); }
static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_cmd_status *ev = (void *) skb->data; __u16 opcode; skb_pull(skb, sizeof(*ev)); opcode = __le16_to_cpu(ev->opcode); switch (opcode) { case HCI_OP_INQUIRY: hci_cs_inquiry(hdev, ev->status); break; case HCI_OP_CREATE_CONN: hci_cs_create_conn(hdev, ev->status); break; case HCI_OP_ADD_SCO: hci_cs_add_sco(hdev, ev->status); break; case HCI_OP_AUTH_REQUESTED: hci_cs_auth_requested(hdev, ev->status); break; case HCI_OP_SET_CONN_ENCRYPT: hci_cs_set_conn_encrypt(hdev, ev->status); break; case HCI_OP_REMOTE_NAME_REQ: hci_cs_remote_name_req(hdev, ev->status); break; case HCI_OP_READ_REMOTE_FEATURES: hci_cs_read_remote_features(hdev, ev->status); break; case HCI_OP_READ_REMOTE_EXT_FEATURES: hci_cs_read_remote_ext_features(hdev, ev->status); break; case HCI_OP_SETUP_SYNC_CONN: hci_cs_setup_sync_conn(hdev, ev->status); break; case HCI_OP_SNIFF_MODE: hci_cs_sniff_mode(hdev, ev->status); break; case HCI_OP_EXIT_SNIFF_MODE: hci_cs_exit_sniff_mode(hdev, ev->status); break; default: BT_DBG("%s opcode 0x%x", hdev->name, opcode); break; } if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); } }
void on_nble_gap_connect_evt(const struct nble_gap_connect_evt *evt) { struct bt_conn *conn; /* Make lookup to check if there's a connection object in CONNECT state * associated with passed peer LE address. */ conn = bt_conn_lookup_state_le(&evt->peer_bda, BT_CONN_CONNECT); #if 0 /* Nordic has no connection error */ if (evt->status) { if (!conn) { return; } conn->err = BT_HCI_ERR_UNACCEPT_CONN_PARAMS; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); /* Drop the reference got by lookup call in CONNECT state. * We are now in DISCONNECTED state since no successful LE * link been made. */ bt_conn_unref(conn); return; } #endif /* * clear advertising even if we are not able to add connection object * to keep host in sync with controller state */ if (evt->role_slave == BT_CONN_ROLE_SLAVE) { atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); } if (!conn) { conn = bt_conn_add_le(&evt->peer_bda); } if (!conn) { BT_DBG("Unable to add new conn for handle %u", evt->conn_handle); return; } conn->handle = evt->conn_handle; bt_addr_le_copy(&conn->le.dst, &evt->peer_bda); conn->le.interval = evt->conn_values.interval; conn->le.latency = evt->conn_values.latency; conn->le.timeout = evt->conn_values.supervision_to; conn->role = evt->role_slave; #if 0 src.type = BT_ADDR_LE_PUBLIC; memcpy(src.val, bt_dev.bdaddr.val, sizeof(bt_dev.bdaddr.val)); /* use connection address (instead of identity address) as initiator * or responder address */ if (conn->role == BT_HCI_ROLE_MASTER) { bt_addr_le_copy(&conn->le.init_addr, &src); bt_addr_le_copy(&conn->le.resp_addr, &evt->peer_addr); } else { bt_addr_le_copy(&conn->le.init_addr, &evt->peer_addr); bt_addr_le_copy(&conn->le.resp_addr, &src); } #endif bt_conn_set_state(conn, BT_CONN_CONNECTED); /* Note: Connection update removed because Windows interop and BT spec recommendations */ bt_conn_unref(conn); #if 0 bt_le_scan_update(false); #endif }
void on_nble_up(void) { BT_DBG("%s", __FUNCTION__); if (bt_ready_cb) bt_ready_cb(bt_init()); }
void l2cap_sock_clear_timer(struct sock *sk) { BT_DBG("sock %p state %d", sk, sk->sk_state); sk_stop_timer(sk, &sk->sk_timer); }
static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; struct sk_buff_head seg_queue; int err; u8 amp_id; BT_DBG("sock %p, sk %p", sock, sk); err = sock_error(sk); if (err) return err; if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; lock_sock(sk); if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; goto done; } /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { skb = l2cap_create_connless_pdu(sk, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { l2cap_do_send(sk, skb); err = len; } goto done; } switch (pi->mode) { case L2CAP_MODE_BASIC: /* Check outgoing MTU */ if (len > pi->omtu) { err = -EMSGSIZE; goto done; } /* Create a basic PDU */ skb = l2cap_create_basic_pdu(sk, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } l2cap_do_send(sk, skb); err = len; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Check outgoing MTU */ if (len > pi->omtu) { err = -EMSGSIZE; goto done; } __skb_queue_head_init(&seg_queue); /* Do segmentation before calling in to the state machine, * since it's possible to block while waiting for memory * allocation. */ amp_id = pi->amp_id; err = l2cap_segment_sdu(sk, &seg_queue, msg, len, 0); /* The socket lock is released while segmenting, so check * that the socket is still connected */ if (sk->sk_state != BT_CONNECTED) { __skb_queue_purge(&seg_queue); err = -ENOTCONN; } if (err) { BT_DBG("Error %d, sk_sndbuf %d, sk_wmem_alloc %d", err, sk->sk_sndbuf, atomic_read(&sk->sk_wmem_alloc)); break; } if (pi->amp_id != amp_id) { /* Channel moved while unlocked. Resegment. */ err = l2cap_resegment_queue(sk, &seg_queue); if (err) break; } if (pi->mode != L2CAP_MODE_STREAMING) err = l2cap_ertm_tx(sk, 0, &seg_queue, L2CAP_ERTM_EVENT_DATA_REQUEST); else err = l2cap_strm_tx(sk, &seg_queue); if (!err) err = len; /* If the skbs were not queued for sending, they'll still be in * seg_queue and need to be purged. */ __skb_queue_purge(&seg_queue); break; default: BT_DBG("bad state %1.1x", pi->mode); err = -EBADFD; } done: release_sock(sk); return err; }
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; struct bt_le_params le_params; struct l2cap_conn *conn; int len, err = 0; u32 opt; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; lock_sock(sk); switch (optname) { case BT_SECURITY: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } sec.level = BT_SECURITY_LOW; len = min_t(unsigned int, sizeof(sec), optlen); if (copy_from_user((char *) &sec, optval, len)) { err = -EFAULT; break; } if (sec.level < BT_SECURITY_LOW || sec.level > BT_SECURITY_HIGH) { err = -EINVAL; break; } l2cap_pi(sk)->sec_level = sec.level; conn = l2cap_pi(sk)->conn; if (conn && l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) { if (!conn->hcon->out) { err = -EINVAL; break; } if (smp_conn_security(conn, sec.level)) break; err = 0; sk->sk_state = BT_CONFIG; } break; case BT_DEFER_SETUP: if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { err = -EINVAL; break; } if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } bt_sk(sk)->defer_setup = opt; break; case BT_POWER: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } pwr.force_active = 1; len = min_t(unsigned int, sizeof(pwr), optlen); if (copy_from_user((char *) &pwr, optval, len)) { err = -EFAULT; break; } l2cap_pi(sk)->force_active = pwr.force_active; break; case BT_AMP_POLICY: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } if ((opt > BT_AMP_POLICY_PREFER_AMP) || ((l2cap_pi(sk)->mode != L2CAP_MODE_ERTM) && (l2cap_pi(sk)->mode != L2CAP_MODE_STREAMING))) { err = -EINVAL; break; } l2cap_pi(sk)->amp_pref = (u8) opt; BT_DBG("BT_AMP_POLICY now %d", opt); if ((sk->sk_state == BT_CONNECTED) && (l2cap_pi(sk)->amp_move_role == L2CAP_AMP_MOVE_NONE)) l2cap_amp_move_init(sk); break; case BT_FLUSHABLE: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } l2cap_pi(sk)->flushable = opt; break; case BT_LE_PARAMS: if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { err = -EINVAL; break; } if (copy_from_user((char *) &le_params, optval, sizeof(struct bt_le_params))) { err = -EFAULT; break; } conn = l2cap_pi(sk)->conn; if (!conn || !conn->hcon || l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); break; } if (!conn->hcon->out || !l2cap_sock_le_conn_update_params_valid( &le_params)) { err = -EINVAL; break; } memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); hci_le_conn_update(conn->hcon, le_params.interval_min, le_params.interval_max, le_params.latency, le_params.supervision_timeout); break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
void l2cap_sock_set_timer(struct sock *sk, long timeout) { BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); }
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; int len, le_sock, err = 0; u32 opt; BT_DBG("sk %p", sk); lock_sock(sk); le_sock = l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA; switch (optname) { case L2CAP_OPTIONS: if (sk->sk_state == BT_CONNECTED && !le_sock) { err = -EINVAL; break; } opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = l2cap_pi(sk)->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { err = -EFAULT; break; } if ((opts.imtu || opts.omtu) && le_sock && (sk->sk_state == BT_CONNECTED)) { if (opts.imtu >= L2CAP_LE_DEFAULT_MTU) l2cap_pi(sk)->imtu = opts.imtu; if (opts.omtu >= L2CAP_LE_DEFAULT_MTU) l2cap_pi(sk)->omtu = opts.omtu; if (opts.imtu < L2CAP_LE_DEFAULT_MTU || opts.omtu < L2CAP_LE_DEFAULT_MTU) err = -EINVAL; break; } if (opts.txwin_size < 1 || opts.txwin_size > L2CAP_TX_WIN_MAX_EXTENDED) { err = -EINVAL; break; } l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_STREAMING: if (!disable_ertm) { /* No fallback to ERTM or Basic mode */ l2cap_pi(sk)->conf_state |= L2CAP_CONF_STATE2_DEVICE; break; } err = -EINVAL; break; case L2CAP_MODE_ERTM: if (!disable_ertm) break; /* fall through */ default: err = -EINVAL; break; } l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; l2cap_pi(sk)->fcs = opts.fcs; l2cap_pi(sk)->max_tx = opts.max_tx; l2cap_pi(sk)->tx_win = opts.txwin_size; l2cap_pi(sk)->flush_to = opts.flush_to; break; case L2CAP_LM: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } if (opt & L2CAP_LM_AUTH) l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); l2cap_pi(sk)->flushable = (opt & L2CAP_LM_FLUSHABLE); break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); hci_conn_check_pending(hdev); }
static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len) { BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len); if (hdr & 0x10) { BT_ERR("%s error in block", data->hdev->name); kfree_skb(data->reassembly); data->reassembly = NULL; return -EIO; } if (hdr & 0x04) { struct sk_buff *skb; unsigned char pkt_type; int pkt_len = 0; if (data->reassembly) { BT_ERR("%s unexpected start block", data->hdev->name); kfree_skb(data->reassembly); data->reassembly = NULL; } if (len < 1) { BT_ERR("%s no packet type found", data->hdev->name); return -EPROTO; } pkt_type = *buf++; len--; switch (pkt_type) { case HCI_EVENT_PKT: if (len >= HCI_EVENT_HDR_SIZE) { struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf; pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; } else { BT_ERR("%s event block is too short", data->hdev->name); return -EILSEQ; } break; case HCI_ACLDATA_PKT: if (len >= HCI_ACL_HDR_SIZE) { struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf; pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); } else { BT_ERR("%s data block is too short", data->hdev->name); return -EILSEQ; } break; case HCI_SCODATA_PKT: if (len >= HCI_SCO_HDR_SIZE) { struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf; pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; } else { BT_ERR("%s audio block is too short", data->hdev->name); return -EILSEQ; } break; } skb = bt_skb_alloc(pkt_len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for the packet", data->hdev->name); return -ENOMEM; } skb->dev = (void *) data->hdev; bt_cb(skb)->pkt_type = pkt_type; data->reassembly = skb; } else { if (!data->reassembly) { BT_ERR("%s unexpected continuation block", data->hdev->name); return -EIO; } } if (len > 0) memcpy(skb_put(data->reassembly, len), buf, len); if (hdr & 0x08) { hci_recv_frame(data->reassembly); data->reassembly = NULL; } return 0; }
static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); }
static void bfusb_rx_complete(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct bfusb_data *data = (struct bfusb_data *) skb->dev; unsigned char *buf = urb->transfer_buffer; int count = urb->actual_length; int err, hdr, len; BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len); read_lock(&data->lock); if (!test_bit(HCI_RUNNING, &data->hdev->flags)) goto unlock; if (urb->status || !count) goto resubmit; data->hdev->stat.byte_rx += count; skb_put(skb, count); while (count) { hdr = buf[0] | (buf[1] << 8); if (hdr & 0x4000) { len = 0; count -= 2; buf += 2; } else { len = (buf[2] == 0) ? 256 : buf[2]; count -= 3; buf += 3; } if (count < len) { BT_ERR("%s block extends over URB buffer ranges", data->hdev->name); } if ((hdr & 0xe1) == 0xc1) bfusb_recv_block(data, hdr, buf, len); count -= len; buf += len; } skb_unlink(skb, &data->pending_q); kfree_skb(skb); bfusb_rx_submit(data, urb); read_unlock(&data->lock); return; resubmit: urb->dev = data->udev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { BT_ERR("%s bulk resubmit failed urb %p err %d", data->hdev->name, urb, err); } unlock: read_unlock(&data->lock); }
static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_cmd_complete *ev = (void *) skb->data; __u16 opcode; skb_pull(skb, sizeof(*ev)); opcode = __le16_to_cpu(ev->opcode); switch (opcode) { case HCI_OP_INQUIRY_CANCEL: hci_cc_inquiry_cancel(hdev, skb); break; case HCI_OP_EXIT_PERIODIC_INQ: #ifdef CONFIG_BT_DEVICE if(hdev->inquiry_state){ hdev->inquiry_state = 0; tasklet_enable(&hdev->tx_task); } #endif hci_cc_exit_periodic_inq(hdev, skb); break; case HCI_OP_REMOTE_NAME_REQ_CANCEL: hci_cc_remote_name_req_cancel(hdev, skb); break; case HCI_OP_ROLE_DISCOVERY: hci_cc_role_discovery(hdev, skb); break; case HCI_OP_READ_LINK_POLICY: hci_cc_read_link_policy(hdev, skb); break; case HCI_OP_WRITE_LINK_POLICY: hci_cc_write_link_policy(hdev, skb); break; case HCI_OP_READ_DEF_LINK_POLICY: hci_cc_read_def_link_policy(hdev, skb); break; case HCI_OP_WRITE_DEF_LINK_POLICY: hci_cc_write_def_link_policy(hdev, skb); break; case HCI_OP_RESET: hci_cc_reset(hdev, skb); break; case HCI_OP_WRITE_LOCAL_NAME: hci_cc_write_local_name(hdev, skb); break; case HCI_OP_READ_LOCAL_NAME: hci_cc_read_local_name(hdev, skb); break; case HCI_OP_WRITE_AUTH_ENABLE: hci_cc_write_auth_enable(hdev, skb); break; case HCI_OP_WRITE_ENCRYPT_MODE: hci_cc_write_encrypt_mode(hdev, skb); break; case HCI_OP_WRITE_SCAN_ENABLE: hci_cc_write_scan_enable(hdev, skb); break; case HCI_OP_READ_CLASS_OF_DEV: hci_cc_read_class_of_dev(hdev, skb); break; case HCI_OP_WRITE_CLASS_OF_DEV: hci_cc_write_class_of_dev(hdev, skb); break; case HCI_OP_READ_VOICE_SETTING: hci_cc_read_voice_setting(hdev, skb); break; case HCI_OP_WRITE_VOICE_SETTING: hci_cc_write_voice_setting(hdev, skb); break; case HCI_OP_HOST_BUFFER_SIZE: hci_cc_host_buffer_size(hdev, skb); break; case HCI_OP_READ_SSP_MODE: hci_cc_read_ssp_mode(hdev, skb); break; case HCI_OP_WRITE_SSP_MODE: hci_cc_write_ssp_mode(hdev, skb); break; case HCI_OP_READ_LOCAL_VERSION: hci_cc_read_local_version(hdev, skb); break; case HCI_OP_READ_LOCAL_COMMANDS: hci_cc_read_local_commands(hdev, skb); break; case HCI_OP_READ_LOCAL_FEATURES: hci_cc_read_local_features(hdev, skb); break; case HCI_OP_READ_BUFFER_SIZE: hci_cc_read_buffer_size(hdev, skb); break; case HCI_OP_READ_BD_ADDR: hci_cc_read_bd_addr(hdev, skb); break; #ifdef CONFIG_BT_DEVICE case HCI_OP_INQUIRY: case 0x0403: if(!hdev->inquiry_state){ hdev->inquiry_state = 1; tasklet_disable(&hdev->tx_task); } break; #endif default: BT_DBG("%s opcode 0x%x", hdev->name, opcode); break; } if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); } }
static int bfusb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct bfusb_data *data; struct sk_buff *nskb; unsigned char buf[3]; int sent = 0, size, count; BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len); if (!hdev) { BT_ERR("Frame for unknown HCI device (hdev=NULL)"); return -ENODEV; } if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; data = hdev->driver_data; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; }; /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); count = skb->len; /* Max HCI frame size seems to be 1511 + 1 */ nskb = bt_skb_alloc(count + 32, GFP_ATOMIC); if (!nskb) { BT_ERR("Can't allocate memory for new packet"); return -ENOMEM; } nskb->dev = (void *) data; while (count) { size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); buf[1] = 0x00; buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; memcpy(skb_put(nskb, 3), buf, 3); skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size); sent += size; count -= size; } /* Don't send frame with multiple size of bulk max packet */ if ((nskb->len % data->bulk_pkt_size) == 0) { buf[0] = 0xdd; buf[1] = 0x00; memcpy(skb_put(nskb, 2), buf, 2); } read_lock(&data->lock); skb_queue_tail(&data->transmit_q, nskb); bfusb_tx_wakeup(data); read_unlock(&data->lock); kfree_skb(skb); return 0; }
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); }
static int bfusb_load_firmware(struct bfusb_data *data, const unsigned char *firmware, int count) { unsigned char *buf; int err, pipe, len, size, sent = 0; BT_DBG("bfusb %p udev %p", data, data->udev); BT_INFO("BlueFRITZ! USB loading firmware"); pipe = usb_sndctrlpipe(data->udev, 0); if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) { BT_ERR("Can't change to loading configuration"); return -EBUSY; } data->udev->toggle[0] = data->udev->toggle[1] = 0; buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); if (!buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; } pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep); while (count) { size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3); memcpy(buf, firmware + sent, size); err = usb_bulk_msg(data->udev, pipe, buf, size, &len, BFUSB_BLOCK_TIMEOUT); if (err || (len != size)) { BT_ERR("Error in firmware loading"); goto error; } sent += size; count -= size; } err = usb_bulk_msg(data->udev, pipe, NULL, 0, &len, BFUSB_BLOCK_TIMEOUT); if (err < 0) { BT_ERR("Error in null packet request"); goto error; } pipe = usb_sndctrlpipe(data->udev, 0); err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION, 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (err < 0) { BT_ERR("Can't change to running configuration"); goto error; } data->udev->toggle[0] = data->udev->toggle[1] = 0; BT_INFO("BlueFRITZ! USB device ready"); kfree(buf); return 0; error: kfree(buf); pipe = usb_sndctrlpipe(data->udev, 0); usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION, 0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); return err; }
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; __u8 event = hdr->evt; skb_pull(skb, HCI_EVENT_HDR_SIZE); switch (event) { case HCI_EV_INQUIRY_COMPLETE: #ifdef CONFIG_BT_DEVICE if(hdev->inquiry_state){ hdev->inquiry_state = 0; tasklet_enable(&hdev->tx_task); } #endif hci_inquiry_complete_evt(hdev, skb); break; case HCI_EV_INQUIRY_RESULT: hci_inquiry_result_evt(hdev, skb); break; case HCI_EV_CONN_COMPLETE: hci_conn_complete_evt(hdev, skb); break; case HCI_EV_CONN_REQUEST: hci_conn_request_evt(hdev, skb); break; case HCI_EV_DISCONN_COMPLETE: hci_disconn_complete_evt(hdev, skb); break; case HCI_EV_AUTH_COMPLETE: hci_auth_complete_evt(hdev, skb); break; case HCI_EV_REMOTE_NAME: hci_remote_name_evt(hdev, skb); break; case HCI_EV_ENCRYPT_CHANGE: hci_encrypt_change_evt(hdev, skb); break; case HCI_EV_CHANGE_LINK_KEY_COMPLETE: hci_change_link_key_complete_evt(hdev, skb); break; case HCI_EV_REMOTE_FEATURES: hci_remote_features_evt(hdev, skb); break; case HCI_EV_REMOTE_VERSION: hci_remote_version_evt(hdev, skb); break; case HCI_EV_QOS_SETUP_COMPLETE: hci_qos_setup_complete_evt(hdev, skb); break; case HCI_EV_CMD_COMPLETE: hci_cmd_complete_evt(hdev, skb); break; case HCI_EV_CMD_STATUS: hci_cmd_status_evt(hdev, skb); break; case HCI_EV_ROLE_CHANGE: hci_role_change_evt(hdev, skb); break; case HCI_EV_NUM_COMP_PKTS: hci_num_comp_pkts_evt(hdev, skb); break; case HCI_EV_MODE_CHANGE: hci_mode_change_evt(hdev, skb); break; case HCI_EV_PIN_CODE_REQ: hci_pin_code_request_evt(hdev, skb); break; case HCI_EV_LINK_KEY_REQ: hci_link_key_request_evt(hdev, skb); break; case HCI_EV_LINK_KEY_NOTIFY: hci_link_key_notify_evt(hdev, skb); break; case HCI_EV_CLOCK_OFFSET: hci_clock_offset_evt(hdev, skb); break; case HCI_EV_PKT_TYPE_CHANGE: hci_pkt_type_change_evt(hdev, skb); break; case HCI_EV_PSCAN_REP_MODE: hci_pscan_rep_mode_evt(hdev, skb); break; case HCI_EV_INQUIRY_RESULT_WITH_RSSI: hci_inquiry_result_with_rssi_evt(hdev, skb); break; case HCI_EV_REMOTE_EXT_FEATURES: hci_remote_ext_features_evt(hdev, skb); break; case HCI_EV_SYNC_CONN_COMPLETE: hci_sync_conn_complete_evt(hdev, skb); break; case HCI_EV_SYNC_CONN_CHANGED: hci_sync_conn_changed_evt(hdev, skb); break; case HCI_EV_SNIFF_SUBRATE: hci_sniff_subrate_evt(hdev, skb); break; case HCI_EV_EXTENDED_INQUIRY_RESULT: hci_extended_inquiry_result_evt(hdev, skb); break; case HCI_EV_IO_CAPA_REQUEST: hci_io_capa_request_evt(hdev, skb); break; case HCI_EV_SIMPLE_PAIR_COMPLETE: hci_simple_pair_complete_evt(hdev, skb); break; case HCI_EV_REMOTE_HOST_FEATURES: hci_remote_host_features_evt(hdev, skb); break; default: BT_DBG("%s event 0x%x", hdev->name, event); break; } kfree_skb(skb); hdev->stat.evt_rx++; }
static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { const struct firmware *firmware; struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_endpoint *bulk_out_ep; struct usb_host_endpoint *bulk_in_ep; struct hci_dev *hdev; struct bfusb_data *data; BT_DBG("intf %p id %p", intf, id); /* Check number of endpoints */ if (intf->cur_altsetting->desc.bNumEndpoints < 2) return -EIO; bulk_out_ep = &intf->cur_altsetting->endpoint[0]; bulk_in_ep = &intf->cur_altsetting->endpoint[1]; if (!bulk_out_ep || !bulk_in_ep) { BT_ERR("Bulk endpoints not found"); goto done; } /* Initialize control structure and load firmware */ data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL); if (!data) { BT_ERR("Can't allocate memory for control structure"); goto done; } data->udev = udev; data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress; data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress; data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize); rwlock_init(&data->lock); data->reassembly = NULL; skb_queue_head_init(&data->transmit_q); skb_queue_head_init(&data->pending_q); skb_queue_head_init(&data->completed_q); if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) { BT_ERR("Firmware request failed"); goto error; } BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) { BT_ERR("Firmware loading failed"); goto release; } release_firmware(firmware); /* Initialize and register HCI device */ hdev = hci_alloc_dev(); if (!hdev) { BT_ERR("Can't allocate HCI device"); goto error; } data->hdev = hdev; hdev->bus = HCI_USB; hdev->driver_data = data; SET_HCIDEV_DEV(hdev, &intf->dev); hdev->open = bfusb_open; hdev->close = bfusb_close; hdev->flush = bfusb_flush; hdev->send = bfusb_send_frame; hdev->destruct = bfusb_destruct; hdev->ioctl = bfusb_ioctl; if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); goto error; } usb_set_intfdata(intf, data); return 0; release: release_firmware(firmware); error: kfree(data); done: return -EIO; }
static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); }
static int btusb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btusb_data *data = hdev->driver_data; struct usb_ctrlrequest *dr; struct urb *urb; unsigned int pipe; int err; BT_DBG("%s", hdev->name); if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; dr = kmalloc(sizeof(*dr), GFP_ATOMIC); if (!dr) { usb_free_urb(urb); return -ENOMEM; } dr->bRequestType = data->cmdreq_type; dr->bRequest = 0; dr->wIndex = 0; dr->wValue = 0; dr->wLength = __cpu_to_le16(skb->len); pipe = usb_sndctrlpipe(data->udev, 0x00); usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, skb->data, skb->len, btusb_tx_complete, skb); hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 && hdev->conn_hash.le_num < 1)) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_tx_complete, skb); hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_isoc_tx_complete, skb, data->isoc_tx_ep->bInterval); urb->transfer_flags = URB_ISO_ASAP; __fill_isoc_descriptor(urb, skb->len, le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; goto skip_waking; default: return -EILSEQ; } err = inc_tx(data); if (err) { usb_anchor_urb(urb, &data->deferred); schedule_work(&data->waker); err = 0; goto done; } skip_waking: usb_anchor_urb(urb, &data->tx_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { BT_ERR("%s urb %p submission failed", hdev->name, urb); kfree(urb->setup_packet); usb_unanchor_urb(urb); } else { usb_mark_last_busy(data->udev); } usb_free_urb(urb); done: return err; }
static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; int mask = hdev->link_mode; BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr), ev->link_type); mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); if (mask & HCI_LM_ACCEPT) { /* Connection accepted */ struct inquiry_entry *ie; struct hci_conn *conn; hci_dev_lock(hdev); if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) memcpy(ie->data.dev_class, ev->dev_class, 3); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { /* pkt_type not yet used for incoming connections */ if (!(conn = hci_conn_add(hdev, ev->link_type, 0, &ev->bdaddr))) { BT_ERR("No memmory for new connection"); hci_dev_unlock(hdev); return; } } memcpy(conn->dev_class, ev->dev_class, 3); conn->state = BT_CONNECT; hci_dev_unlock(hdev); if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { struct hci_cp_accept_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) cp.role = 0x00; /* Become master */ else cp.role = 0x01; /* Remain slave */ hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); } else { struct hci_cp_accept_sync_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40); cp.max_latency = cpu_to_le16(0xffff); cp.content_format = cpu_to_le16(hdev->voice_setting); cp.retrans_effort = 0xff; hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), &cp); } } else { /* Connection rejected */ struct hci_cp_reject_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); cp.reason = 0x0f; hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp); } }
static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep_desc; struct btusb_data *data; struct hci_dev *hdev; int i, err; BT_DBG("intf %p id %p", intf, id); /* interface numbers are hardcoded in the spec */ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; if (!id->driver_info) { const struct usb_device_id *match; match = usb_match_id(intf, blacklist_table); if (match) id = match; } if (id->driver_info == BTUSB_IGNORE) return -ENODEV; if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER) return -ENODEV; if (ignore_csr && id->driver_info & BTUSB_CSR) return -ENODEV; if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) return -ENODEV; if (id->driver_info & BTUSB_ATH3012) { struct usb_device *udev = interface_to_usbdev(intf); /* Old firmware would otherwise let ath3k driver load * patch and sysconfig files */ if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001) return -ENODEV; } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { ep_desc = &intf->cur_altsetting->endpoint[i].desc; if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) { data->intr_ep = ep_desc; continue; } if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) { data->bulk_tx_ep = ep_desc; continue; } if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) { data->bulk_rx_ep = ep_desc; continue; } } if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { kfree(data); return -ENODEV; } data->cmdreq_type = USB_TYPE_CLASS; data->udev = interface_to_usbdev(intf); data->intf = intf; spin_lock_init(&data->lock); INIT_WORK(&data->work, btusb_work); INIT_WORK(&data->waker, btusb_waker); spin_lock_init(&data->txlock); init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); init_usb_anchor(&data->deferred); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); return -ENOMEM; } hdev->bus = HCI_USB; hdev->driver_data = data; data->hdev = hdev; SET_HCIDEV_DEV(hdev, &intf->dev); hdev->open = btusb_open; hdev->close = btusb_close; hdev->flush = btusb_flush; hdev->send = btusb_send_frame; hdev->destruct = btusb_destruct; hdev->notify = btusb_notify; hdev->owner = THIS_MODULE; /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); if (!reset) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); } if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; if (id->driver_info & BTUSB_DIGIANSWER) { data->cmdreq_type = USB_TYPE_VENDOR; set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); } if (id->driver_info & BTUSB_CSR) { struct usb_device *udev = data->udev; /* Old firmware would otherwise execute USB reset */ if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); } if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = data->udev; /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); data->isoc = NULL; } if (id->driver_info & BTUSB_BCM92035) { unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 }; struct sk_buff *skb; skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); if (skb) { memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); skb_queue_tail(&hdev->driver_init, skb); } } if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, data); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } } err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } usb_set_intfdata(intf, data); return 0; }
static void bnep_net_timeout(struct net_device *dev) { BT_DBG("net_timeout"); netif_wake_queue(dev); }
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; struct l2cap_conninfo cinfo; int len, err = 0; u32 opt; BT_DBG("sk %p", sk); if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); switch (optname) { case L2CAP_OPTIONS: memset(&opts, 0, sizeof(opts)); opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = l2cap_pi(sk)->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) err = -EFAULT; break; case L2CAP_LM: switch (l2cap_pi(sk)->sec_level) { case BT_SECURITY_LOW: opt = L2CAP_LM_AUTH; break; case BT_SECURITY_MEDIUM: opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; break; case BT_SECURITY_HIGH: opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; break; default: opt = 0; break; } if (l2cap_pi(sk)->role_switch) opt |= L2CAP_LM_MASTER; if (l2cap_pi(sk)->force_reliable) opt |= L2CAP_LM_RELIABLE; if (l2cap_pi(sk)->flushable) opt |= L2CAP_LM_FLUSHABLE; if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; break; case L2CAP_CONNINFO: if (sk->sk_state != BT_CONNECTED && !(sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup)) { err = -ENOTCONN; break; } cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) err = -EFAULT; break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }