static uint8_t att_signed_write_cmd(struct bt_att *att, struct net_buf *buf) { struct bt_conn *conn = att->chan.conn; struct bt_att_signed_write_cmd *req; uint16_t handle; int err; req = (void *)buf->data; handle = sys_le16_to_cpu(req->handle); BT_DBG("handle 0x%04x", handle); /* Verifying data requires full buffer including attribute header */ net_buf_push(buf, sizeof(struct bt_att_hdr)); err = bt_smp_sign_verify(conn, buf); if (err) { BT_ERR("Error verifying data"); /* No response for this command */ return 0; } net_buf_pull(buf, sizeof(struct bt_att_hdr)); net_buf_pull(buf, sizeof(*req)); return att_write_rsp(conn, 0, 0, handle, 0, buf->data, buf->len - sizeof(struct bt_att_signature)); }
static void deserialize_struct(struct net_buf *buf, const uint8_t **struct_ptr, uint8_t *struct_length) { *struct_length = net_buf_pull_u8(buf); *struct_ptr = buf->data; net_buf_pull(buf, *struct_length); }
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) { struct bt_l2cap_hdr *hdr = (void *)buf->data; struct bt_l2cap_chan *chan; uint16_t cid; if (IS_ENABLED(CONFIG_BLUETOOTH_BREDR) && conn->type == BT_CONN_TYPE_BR) { bt_l2cap_br_recv(conn, buf); return; } if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP PDU received"); net_buf_unref(buf); return; } cid = sys_le16_to_cpu(hdr->cid); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Packet for CID %u len %u", cid, buf->len); chan = bt_l2cap_le_lookup_rx_cid(conn, cid); if (!chan) { BT_WARN("Ignoring data for unknown CID 0x%04x", cid); net_buf_unref(buf); return; } l2cap_chan_recv(chan, buf); net_buf_unref(buf); }
struct net_buf * ieee802154_create_mac_cmd_frame(struct net_if *iface, enum ieee802154_cfi type, struct ieee802154_frame_params *params) { struct ieee802154_context *ctx = net_if_l2_data(iface); struct ieee802154_fcf_seq *fs; struct net_buf *buf, *frag; uint8_t *p_buf; buf = net_nbuf_get_reserve_tx(0); if (!buf) { return NULL; } frag = net_nbuf_get_reserve_data(0); if (!frag) { goto error; } net_buf_frag_add(buf, frag); p_buf = net_nbuf_ll(buf); fs = generate_fcf_grounds(&p_buf, false); fs->fc.frame_type = IEEE802154_FRAME_TYPE_MAC_COMMAND; fs->sequence = ctx->sequence; if (!cfi_to_fs_settings(type, fs, params)) { goto error; } p_buf = generate_addressing_fields(iface, fs, params, p_buf); /* Let's insert the cfi */ ((struct ieee802154_command *)p_buf)->cfi = type; /* In MAC command, we consider ll header being the mhr. * Rest will be the MAC command itself. This will proove * to be easy to handle afterwards to point directly to MAC * command space, in order to fill-in its content. */ net_nbuf_set_ll_reserve(buf, p_buf - net_nbuf_ll(buf)); net_buf_pull(frag, net_nbuf_ll_reserve(buf)); /* Thus setting the right MAC command length * Now up to the caller to fill-in this space relevantly. * See ieee802154_mac_command() helper. */ net_nbuf_set_len(frag, mac_command_length(type)); dbg_print_fs(fs); return buf; error: net_nbuf_unref(buf); return NULL; }
void on_nble_gap_adv_report_evt(const struct nble_gap_adv_report_evt *evt, const uint8_t *buf, uint8_t len) { #if TODO_IMPLEMENT_CONNECTION uint8_t num_reports = buf->data[0]; struct bt_hci_ev_le_advertising_info *info; BT_DBG("Adv number of reports %u", num_reports); info = net_buf_pull(buf, sizeof(num_reports)); while (num_reports--) { int8_t rssi = info->data[info->length]; const bt_addr_le_t *addr; BT_DBG("%s event %u, len %u, rssi %d dBm", bt_addr_le_str(&info->addr), info->evt_type, info->length, rssi); addr = find_id_addr(&info->addr); #endif BT_DBG("nble gap: event:%u, len %u", evt->adv_type, len); if (scan_dev_found_cb) { scan_dev_found_cb(&evt->addr, evt->rssi, evt->adv_type, buf, len); } #if TODO_IMPLEMENT_CONNECTION #if defined(CONFIG_BLUETOOTH_CONN) check_pending_conn(addr, &info->addr, info->evt_type); #endif /* CONFIG_BLUETOOTH_CONN */ /* Get next report iteration by moving pointer to right offset * in buf according to spec 4.2, Vol 2, Part E, 7.7.65.2. */ info = net_buf_pull(buf, sizeof(*info) + info->length + sizeof(rssi)); } #endif }
static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch, struct net_buf *buf, size_t sdu_hdr_len) { struct net_buf *seg; uint16_t headroom; uint16_t len; /* Segment if data (+ data headroom) is bigger than MPS */ if (buf->len + sdu_hdr_len > ch->tx.mps) { goto segment; } /* Segment if there is no space in the user_data */ if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) { BT_WARN("Too small buffer user_data_size %u", buf->pool->user_data_size); goto segment; } headroom = sizeof(struct bt_hci_acl_hdr) + sizeof(struct bt_l2cap_hdr) + sdu_hdr_len; /* Check if original buffer has enough headroom and don't have any * fragments. */ if (net_buf_headroom(buf) >= headroom && !buf->frags) { if (sdu_hdr_len) { /* Push SDU length if set */ net_buf_push_le16(buf, net_buf_frags_len(buf)); } return net_buf_ref(buf); } segment: seg = bt_l2cap_create_pdu(&le_data_pool, 0); if (sdu_hdr_len) { net_buf_add_le16(seg, net_buf_frags_len(buf)); } /* Don't send more that TX MPS including SDU length */ len = min(net_buf_tailroom(seg), ch->tx.mps - sdu_hdr_len); /* Limit if original buffer is smaller than the segment */ len = min(buf->len, len); net_buf_add_mem(seg, buf->data, len); net_buf_pull(buf, len); BT_DBG("ch %p seg %p len %u", ch, seg, seg->len); return seg; }
static uint8_t att_read_group_req(struct bt_att *att, struct net_buf *buf) { struct bt_conn *conn = att->chan.conn; struct bt_att_read_group_req *req; uint16_t start_handle, end_handle, err_handle; union { struct bt_uuid uuid; struct bt_uuid_16 u16; struct bt_uuid_128 u128; } u; /* Type can only be UUID16 or UUID128 */ if (buf->len != sizeof(*req) + 2 && buf->len != sizeof(*req) + 16) { return BT_ATT_ERR_INVALID_PDU; } req = (void *)buf->data; start_handle = sys_le16_to_cpu(req->start_handle); end_handle = sys_le16_to_cpu(req->end_handle); net_buf_pull(buf, sizeof(*req)); if (!uuid_create(&u.uuid, buf)) { return BT_ATT_ERR_UNLIKELY; } BT_DBG("start_handle 0x%04x end_handle 0x%04x type %s", start_handle, end_handle, bt_uuid_str(&u.uuid)); if (!range_is_valid(start_handle, end_handle, &err_handle)) { send_err_rsp(conn, BT_ATT_OP_READ_GROUP_REQ, err_handle, BT_ATT_ERR_INVALID_HANDLE); return 0; } /* Core v4.2, Vol 3, sec 2.5.3 Attribute Grouping: * Not all of the grouping attributes can be used in the ATT * Read By Group Type Request. The «Primary Service» and «Secondary * Service» grouping types may be used in the Read By Group Type * Request. The «Characteristic» grouping type shall not be used in * the ATT Read By Group Type Request. */ if (bt_uuid_cmp(&u.uuid, BT_UUID_GATT_PRIMARY) && bt_uuid_cmp(&u.uuid, BT_UUID_GATT_SECONDARY)) { send_err_rsp(conn, BT_ATT_OP_READ_GROUP_REQ, start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE); return 0; } return att_read_group_rsp(att, &u.uuid, start_handle, end_handle); }
static inline void process_tx(void) { int bytes; if (!tx.buf) { tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); if (!tx.buf) { BT_ERR("TX interrupt but no pending buffer!"); uart_irq_tx_disable(h4_dev); return; } } if (!tx.type) { switch (bt_buf_get_type(tx.buf)) { case BT_BUF_ACL_OUT: tx.type = H4_ACL; break; case BT_BUF_CMD: tx.type = H4_CMD; break; default: BT_ERR("Unknown buffer type"); goto done; } bytes = uart_fifo_fill(h4_dev, &tx.type, 1); if (bytes != 1) { BT_WARN("Unable to send H:4 type"); tx.type = H4_NONE; return; } } bytes = uart_fifo_fill(h4_dev, tx.buf->data, tx.buf->len); net_buf_pull(tx.buf, bytes); if (tx.buf->len) { return; } done: tx.type = H4_NONE; net_buf_unref(tx.buf); tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); if (!tx.buf) { uart_irq_tx_disable(h4_dev); } }
static uint8_t att_write_req(struct bt_att *att, struct net_buf *buf) { struct bt_conn *conn = att->chan.conn; struct bt_att_write_req *req; uint16_t handle; req = (void *)buf->data; handle = sys_le16_to_cpu(req->handle); net_buf_pull(buf, sizeof(*req)); BT_DBG("handle 0x%04x", handle); return att_write_rsp(conn, BT_ATT_OP_WRITE_REQ, BT_ATT_OP_WRITE_RSP, handle, 0, buf->data, buf->len); }
static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan, struct net_buf *buf) { struct net_buf *frag; uint16_t len; BT_DBG("chan %p len %u sdu %zu", chan, buf->len, net_buf_frags_len(chan->_sdu)); if (net_buf_frags_len(chan->_sdu) + buf->len > chan->_sdu_len) { BT_ERR("SDU length mismatch"); bt_l2cap_chan_disconnect(&chan->chan); return; } /* Jump to last fragment */ frag = net_buf_frag_last(chan->_sdu); while (buf->len) { /* Check if there is any space left in the current fragment */ if (!net_buf_tailroom(frag)) { frag = l2cap_alloc_frag(chan); if (!frag) { BT_ERR("Unable to store SDU"); bt_l2cap_chan_disconnect(&chan->chan); return; } } len = min(net_buf_tailroom(frag), buf->len); net_buf_add_mem(frag, buf->data, len); net_buf_pull(buf, len); BT_DBG("frag %p len %u", frag, frag->len); } if (net_buf_frags_len(chan->_sdu) == chan->_sdu_len) { /* Receiving complete SDU, notify channel and reset SDU buf */ chan->chan.ops->recv(&chan->chan, chan->_sdu); net_buf_unref(chan->_sdu); chan->_sdu = NULL; chan->_sdu_len = 0; } l2cap_chan_update_credits(chan); }
static void bt_att_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) { struct bt_att *att = CONTAINER_OF(chan, struct bt_att, chan); struct bt_att_hdr *hdr = (void *)buf->data; uint8_t err = BT_ATT_ERR_NOT_SUPPORTED; size_t i; BT_ASSERT(att); if (buf->len < sizeof(*hdr)) { BT_ERR("Too small ATT PDU received"); return; } BT_DBG("Received ATT code 0x%02x len %u", hdr->code, buf->len); net_buf_pull(buf, sizeof(*hdr)); for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (hdr->code != handlers[i].op) { continue; } if (buf->len < handlers[i].expect_len) { BT_ERR("Invalid len %u for code 0x%02x", buf->len, hdr->code); err = BT_ATT_ERR_INVALID_PDU; break; } err = handlers[i].func(att, buf); break; } /* Commands don't have response */ if ((hdr->code & BT_ATT_OP_CMD_FLAG)) { return; } if (err) { BT_DBG("ATT error 0x%02x", err); send_err_rsp(chan->conn, hdr->code, 0, err); } }
static void deserialize_buf(struct net_buf *buf, const uint8_t **buf_ptr, uint16_t *buf_len) { uint8_t b; /* Get the current byte */ b = net_buf_pull_u8(buf); *buf_len = b & 0x7F; if (b & 0x80) { /* Get the current byte */ b = net_buf_pull_u8(buf); *buf_len += (uint16_t)b << 7; } /* Return the values */ *buf_ptr = buf->data; net_buf_pull(buf, *buf_len); }
static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf) { struct net_buf *frag; uint16_t frag_len; frag = bt_conn_create_pdu(&frag_buf, 0); if (conn->state != BT_CONN_CONNECTED) { net_buf_unref(frag); return NULL; } frag_len = min(conn_mtu(conn), net_buf_tailroom(frag)); memcpy(net_buf_add(frag, frag_len), buf->data, frag_len); net_buf_pull(buf, frag_len); return frag; }
static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pkt) { struct ieee802154_mpdu mpdu; if (!ieee802154_validate_frame(net_pkt_ll(pkt), net_pkt_get_len(pkt), &mpdu)) { return NET_DROP; } if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) { return ieee802154_handle_beacon(iface, &mpdu); } if (ieee802154_is_scanning(iface)) { return NET_DROP; } if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) { return ieee802154_handle_mac_command(iface, &mpdu); } /* At this point the frame has to be a DATA one */ ieee802154_acknowledge(iface, &mpdu); net_pkt_set_ll_reserve(pkt, mpdu.payload - (void *)net_pkt_ll(pkt)); net_buf_pull(pkt->frags, net_pkt_ll_reserve(pkt)); set_pkt_ll_addr(net_pkt_ll_src(pkt), mpdu.mhr.fs->fc.pan_id_comp, mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr); set_pkt_ll_addr(net_pkt_ll_dst(pkt), false, mpdu.mhr.fs->fc.dst_addr_mode, mpdu.mhr.dst_addr); if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) { return NET_DROP; } pkt_hexdump(pkt, true); return ieee802154_manage_recv_packet(iface, pkt); }
static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch, struct net_buf *buf, size_t sdu_hdr_len) { struct net_buf *seg; uint16_t headroom; uint16_t len; /* Segment if data (+ data headroom) is bigger than MPS */ if (buf->len + sdu_hdr_len > ch->tx.mps) { goto segment; } headroom = sizeof(struct bt_hci_acl_hdr) + sizeof(struct bt_l2cap_hdr) + sdu_hdr_len; /* Check if original buffer has enough headroom */ if (net_buf_headroom(buf) >= headroom) { if (sdu_hdr_len) { /* Push SDU length if set */ net_buf_push_le16(buf, buf->len); } return net_buf_ref(buf); } segment: seg = bt_l2cap_create_pdu(&le_data); if (!seg) { return NULL; } if (sdu_hdr_len) { net_buf_add_le16(seg, buf->len); } len = min(min(buf->len, L2CAP_LE_MIN_MTU - sdu_hdr_len), ch->tx.mps); memcpy(net_buf_add(seg, len), buf->data, len); net_buf_pull(buf, len); BT_DBG("ch %p seg %p len %u", ch, seg, seg->len); return seg; }
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) { struct bt_l2cap_hdr *hdr = (void *)buf->data; struct bt_l2cap_chan *chan; uint16_t cid; if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP PDU received"); net_buf_unref(buf); return; } cid = sys_le16_to_cpu(hdr->cid); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Packet for CID %u len %u", cid, buf->len); switch (conn->type) { case BT_CONN_TYPE_LE: chan = bt_l2cap_le_lookup_rx_cid(conn, cid); break; #if defined(CONFIG_BLUETOOTH_BREDR) case BT_CONN_TYPE_BR: chan = bt_l2cap_br_lookup_rx_cid(conn, cid); break; #endif /* CONFIG_BLUETOOTH_BREDR */ default: chan = NULL; break; } if (!chan) { BT_WARN("Ignoring data for unknown CID 0x%04x", cid); net_buf_unref(buf); return; } l2cap_chan_recv(chan, buf); net_buf_unref(buf); }
static struct net_pkt *build_reply_pkt(const char *name, struct net_context *context, struct net_pkt *pkt) { struct net_pkt *reply_pkt; struct net_buf *tmp; int header_len, recv_len, reply_len; printk("%s received %d bytes", name, net_pkt_appdatalen(pkt)); reply_pkt = net_pkt_get_tx(context, K_FOREVER); recv_len = net_pkt_get_len(pkt); tmp = pkt->frags; /* Remove frag link so original pkt can be unrefed */ pkt->frags = NULL; /* First fragment will contain IP header so move the data * down in order to get rid of it. */ header_len = net_pkt_appdata(pkt) - tmp->data; /* After this pull, the tmp->data points directly to application * data. */ net_buf_pull(tmp, header_len); /* Add the entire chain into reply */ net_pkt_frag_add(reply_pkt, tmp); reply_len = net_pkt_get_len(reply_pkt); printk("Received %d bytes, sending %d bytes", recv_len - header_len, reply_len); return reply_pkt; }
static uint8_t att_read_type_req(struct bt_att *att, struct net_buf *buf) { struct bt_conn *conn = att->chan.conn; struct bt_att_read_type_req *req; uint16_t start_handle, end_handle, err_handle; union { struct bt_uuid uuid; struct bt_uuid_16 u16; struct bt_uuid_128 u128; } u; /* Type can only be UUID16 or UUID128 */ if (buf->len != sizeof(*req) + 2 && buf->len != sizeof(*req) + 16) { return BT_ATT_ERR_INVALID_PDU; } req = (void *)buf->data; start_handle = sys_le16_to_cpu(req->start_handle); end_handle = sys_le16_to_cpu(req->end_handle); net_buf_pull(buf, sizeof(*req)); if (!uuid_create(&u.uuid, buf)) { return BT_ATT_ERR_UNLIKELY; } BT_DBG("start_handle 0x%04x end_handle 0x%04x type %s", start_handle, end_handle, bt_uuid_str(&u.uuid)); if (!range_is_valid(start_handle, end_handle, &err_handle)) { send_err_rsp(conn, BT_ATT_OP_READ_TYPE_REQ, err_handle, BT_ATT_ERR_INVALID_HANDLE); return 0; } return att_read_type_rsp(att, &u.uuid, start_handle, end_handle); }
static uint8_t att_find_type_req(struct bt_att *att, struct net_buf *buf) { struct bt_conn *conn = att->chan.conn; struct bt_att_find_type_req *req; uint16_t start_handle, end_handle, err_handle, type; uint8_t *value; req = (void *)buf->data; start_handle = sys_le16_to_cpu(req->start_handle); end_handle = sys_le16_to_cpu(req->end_handle); type = sys_le16_to_cpu(req->type); value = net_buf_pull(buf, sizeof(*req)); BT_DBG("start_handle 0x%04x end_handle 0x%04x type %u", start_handle, end_handle, type); if (!range_is_valid(start_handle, end_handle, &err_handle)) { send_err_rsp(conn, BT_ATT_OP_FIND_TYPE_REQ, err_handle, BT_ATT_ERR_INVALID_HANDLE); return 0; } /* The Attribute Protocol Find By Type Value Request shall be used with * the Attribute Type parameter set to the UUID for «Primary Service» * and the Attribute Value set to the 16-bit Bluetooth UUID or 128-bit * UUID for the specific primary service. */ if (type != BT_UUID_GATT_PRIMARY_VAL) { send_err_rsp(conn, BT_ATT_OP_FIND_TYPE_REQ, start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); return 0; } return att_find_type_rsp(att, start_handle, end_handle, value, buf->len); }
static void deserialize_ptr(struct net_buf *buf, uintptr_t *priv) { memcpy(priv, buf->data, sizeof(*priv)); net_buf_pull(buf, sizeof(*priv)); }
struct net_pkt * ieee802154_create_mac_cmd_frame(struct ieee802154_context *ctx, enum ieee802154_cfi type, struct ieee802154_frame_params *params) { struct ieee802154_fcf_seq *fs; struct net_pkt *pkt; struct net_buf *frag; u8_t *p_buf; pkt = net_pkt_get_reserve_tx(0, K_FOREVER); if (!pkt) { return NULL; } frag = net_pkt_get_frag(pkt, K_FOREVER); if (!frag) { goto error; } net_pkt_frag_add(pkt, frag); p_buf = net_pkt_ll(pkt); fs = generate_fcf_grounds(&p_buf, type == IEEE802154_CFI_BEACON_REQUEST ? false : ctx->ack_requested); fs->fc.frame_type = IEEE802154_FRAME_TYPE_MAC_COMMAND; fs->sequence = ctx->sequence; if (!cfi_to_fs_settings(type, fs, params)) { goto error; } p_buf = generate_addressing_fields(ctx, fs, params, p_buf); /* Let's insert the cfi */ ((struct ieee802154_command *)p_buf)->cfi = type; /* In MAC command, we consider ll header being the mhr. * Rest will be the MAC command itself. This will proove * to be easy to handle afterwards to point directly to MAC * command space, in order to fill-in its content. */ net_pkt_set_ll_reserve(pkt, p_buf - net_pkt_ll(pkt)); net_buf_pull(frag, net_pkt_ll_reserve(pkt)); /* Thus setting the right MAC command length * Now up to the caller to fill-in this space relevantly. * See ieee802154_mac_command() helper. */ frag->len = mac_command_length(type); dbg_print_fs(fs); return pkt; error: net_pkt_unref(pkt); return NULL; }
void rpc_deserialize(struct net_buf *buf) { uint8_t fn_index; uint8_t sig_type; sig_type = buf->data[0]; fn_index = buf->data[1]; net_buf_pull(buf, 2); switch (sig_type) { case SIG_TYPE_NONE: if (fn_index < ARRAY_SIZE(m_fct_none)) { BT_DBG("%s", debug_func_none[fn_index]); deserialize_none(fn_index, buf); } break; case SIG_TYPE_S: if (fn_index < ARRAY_SIZE(m_fct_s)) { BT_DBG("%s", debug_func_s[fn_index]); deserialize_s(fn_index, buf); } break; case SIG_TYPE_P: if (fn_index < ARRAY_SIZE(m_fct_p)) { BT_DBG("%s", debug_func_p[fn_index]); deserialize_p(fn_index, buf); } break; case SIG_TYPE_S_B: if (fn_index < ARRAY_SIZE(m_fct_s_b)) { BT_DBG("%s", debug_func_s_b[fn_index]); deserialize_s_b(fn_index, buf); } break; case SIG_TYPE_B_B_P: if (fn_index < ARRAY_SIZE(m_fct_b_b_p)) { BT_DBG("%s", debug_func_b_b_p[fn_index]); deserialize_b_b_p(fn_index, buf); } break; case SIG_TYPE_S_P: if (fn_index < ARRAY_SIZE(m_fct_s_p)) { BT_DBG("%s", debug_func_s_p[fn_index]); deserialize_s_p(fn_index, buf); } break; case SIG_TYPE_S_B_P: if (fn_index < ARRAY_SIZE(m_fct_s_b_p)) { BT_DBG("%s", debug_func_s_b_p[fn_index]); deserialize_s_b_p(fn_index, buf); } break; case SIG_TYPE_S_B_B_P: if (fn_index < ARRAY_SIZE(m_fct_s_b_b_p)) { BT_DBG("%s", debug_func_s_b_b_p[fn_index]); deserialize_s_b_b_p(fn_index, buf); } break; default: panic(-1); break; } }
int ssl_rx(void *context, unsigned char *buf, size_t size) { struct http_client_ctx *ctx = context; struct rx_fifo_block *rx_data; u16_t read_bytes; u8_t *ptr; int pos; int len; int ret = 0; if (!ctx->https.mbedtls.ssl_ctx.frag) { rx_data = k_fifo_get(&ctx->https.mbedtls.ssl_ctx.rx_fifo, K_FOREVER); if (!rx_data || !rx_data->pkt) { NET_DBG("Closing %p connection", ctx); if (rx_data) { k_mem_pool_free(&rx_data->block); } return MBEDTLS_ERR_SSL_CONN_EOF; } ctx->https.mbedtls.ssl_ctx.rx_pkt = rx_data->pkt; k_mem_pool_free(&rx_data->block); read_bytes = net_pkt_appdatalen( ctx->https.mbedtls.ssl_ctx.rx_pkt); ctx->https.mbedtls.ssl_ctx.remaining = read_bytes; ctx->https.mbedtls.ssl_ctx.frag = ctx->https.mbedtls.ssl_ctx.rx_pkt->frags; ptr = net_pkt_appdata(ctx->https.mbedtls.ssl_ctx.rx_pkt); len = ptr - ctx->https.mbedtls.ssl_ctx.frag->data; if (len > ctx->https.mbedtls.ssl_ctx.frag->size) { NET_ERR("Buf overflow (%d > %u)", len, ctx->https.mbedtls.ssl_ctx.frag->size); return -EINVAL; } /* This will get rid of IP header */ net_buf_pull(ctx->https.mbedtls.ssl_ctx.frag, len); } else { read_bytes = ctx->https.mbedtls.ssl_ctx.remaining; ptr = ctx->https.mbedtls.ssl_ctx.frag->data; } len = ctx->https.mbedtls.ssl_ctx.frag->len; pos = 0; if (read_bytes > size) { while (ctx->https.mbedtls.ssl_ctx.frag) { read_bytes = len < (size - pos) ? len : (size - pos); #if RX_EXTRA_DEBUG == 1 NET_DBG("Copying %d bytes", read_bytes); #endif memcpy(buf + pos, ptr, read_bytes); pos += read_bytes; if (pos < size) { ctx->https.mbedtls.ssl_ctx.frag = ctx->https.mbedtls.ssl_ctx.frag->frags; ptr = ctx->https.mbedtls.ssl_ctx.frag->data; len = ctx->https.mbedtls.ssl_ctx.frag->len; } else { if (read_bytes == len) { ctx->https.mbedtls.ssl_ctx.frag = ctx->https.mbedtls.ssl_ctx.frag->frags; } else { net_buf_pull( ctx->https.mbedtls.ssl_ctx.frag, read_bytes); } ctx->https.mbedtls.ssl_ctx.remaining -= size; return size; } } } else { while (ctx->https.mbedtls.ssl_ctx.frag) { #if RX_EXTRA_DEBUG == 1 NET_DBG("Copying all %d bytes", len); #endif memcpy(buf + pos, ptr, len); pos += len; ctx->https.mbedtls.ssl_ctx.frag = ctx->https.mbedtls.ssl_ctx.frag->frags; if (!ctx->https.mbedtls.ssl_ctx.frag) { break; } ptr = ctx->https.mbedtls.ssl_ctx.frag->data; len = ctx->https.mbedtls.ssl_ctx.frag->len; } net_pkt_unref(ctx->https.mbedtls.ssl_ctx.rx_pkt); ctx->https.mbedtls.ssl_ctx.rx_pkt = NULL; ctx->https.mbedtls.ssl_ctx.frag = NULL; ctx->https.mbedtls.ssl_ctx.remaining = 0; if (read_bytes != pos) { return -EIO; } ret = read_bytes; } return ret; }
static void l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) { struct bt_l2cap *l2cap = CONTAINER_OF(chan, struct bt_l2cap, chan); struct bt_l2cap_sig_hdr *hdr = (void *)buf->data; uint16_t len; if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP signaling PDU"); return; } len = sys_le16_to_cpu(hdr->len); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Signaling code 0x%02x ident %u len %u", hdr->code, hdr->ident, len); if (buf->len != len) { BT_ERR("L2CAP length mismatch (%u != %u)", buf->len, len); return; } if (!hdr->ident) { BT_ERR("Invalid ident value in L2CAP PDU"); return; } switch (hdr->code) { case BT_L2CAP_CONN_PARAM_RSP: le_conn_param_rsp(l2cap, buf); break; #if defined(CONFIG_BLUETOOTH_CENTRAL) case BT_L2CAP_CONN_PARAM_REQ: le_conn_param_update_req(l2cap, hdr->ident, buf); break; #endif /* CONFIG_BLUETOOTH_CENTRAL */ #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL) case BT_L2CAP_LE_CONN_REQ: le_conn_req(l2cap, hdr->ident, buf); break; case BT_L2CAP_LE_CONN_RSP: le_conn_rsp(l2cap, hdr->ident, buf); break; case BT_L2CAP_DISCONN_REQ: le_disconn_req(l2cap, hdr->ident, buf); break; case BT_L2CAP_DISCONN_RSP: le_disconn_rsp(l2cap, hdr->ident, buf); break; case BT_L2CAP_LE_CREDITS: le_credits(l2cap, hdr->ident, buf); break; case BT_L2CAP_CMD_REJECT: reject_cmd(l2cap, hdr->ident, buf); break; #else case BT_L2CAP_CMD_REJECT: /* Ignored */ break; #endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */ default: BT_WARN("Unknown L2CAP PDU code 0x%02x", hdr->code); l2cap_send_reject(chan->conn, hdr->ident, BT_L2CAP_REJ_NOT_UNDERSTOOD, NULL, 0); break; } }
static void http_receive_cb(struct http_client_ctx *ctx, struct net_pkt *pkt) { size_t start = ctx->rsp.data_len; size_t len = 0; struct net_buf *frag; int header_len; if (!pkt) { return; } /* Get rid of possible IP headers in the first fragment. */ frag = pkt->frags; header_len = net_pkt_appdata(pkt) - frag->data; NET_DBG("Received %d bytes data", net_pkt_appdatalen(pkt)); /* After this pull, the frag->data points directly to application data. */ net_buf_pull(frag, header_len); while (frag) { /* If this fragment cannot be copied to result buf, * then parse what we have which will cause the callback to be * called in function on_body(), and continue copying. */ if (ctx->rsp.data_len + frag->len > ctx->rsp.response_buf_len) { /* If the caller has not supplied a callback, then * we cannot really continue if the response buffer * overflows. Set the data_len to mark how many bytes * should be needed in the response_buf. */ if (!ctx->rsp.cb) { ctx->rsp.data_len = net_pkt_get_len(pkt); goto out; } http_parser_execute(&ctx->parser, &ctx->settings, ctx->rsp.response_buf + start, len); ctx->rsp.data_len = 0; len = 0; start = 0; } memcpy(ctx->rsp.response_buf + ctx->rsp.data_len, frag->data, frag->len); ctx->rsp.data_len += frag->len; len += frag->len; frag = frag->frags; } out: /* The parser's error can be catched outside, reading the * http_errno struct member */ http_parser_execute(&ctx->parser, &ctx->settings, ctx->rsp.response_buf + start, len); net_pkt_unref(pkt); }
static struct net_pkt *build_reply_pkt(const char *name, struct net_context *context, struct net_pkt *pkt) { struct net_pkt *reply_pkt; struct net_buf *frag, *tmp; int header_len, recv_len, reply_len; NET_INFO("%s received %d bytes", name, net_pkt_appdatalen(pkt)); if (net_pkt_appdatalen(pkt) == 0) { return NULL; } reply_pkt = net_pkt_get_tx(context, K_FOREVER); NET_ASSERT(reply_pkt); recv_len = net_pkt_get_len(pkt); tmp = pkt->frags; /* First fragment will contain IP header so move the data * down in order to get rid of it. */ header_len = net_pkt_appdata(pkt) - tmp->data; NET_ASSERT(header_len < CONFIG_NET_BUF_DATA_SIZE); /* After this pull, the tmp->data points directly to application * data. */ net_buf_pull(tmp, header_len); while (tmp) { frag = net_pkt_get_data(context, K_FOREVER); if (!net_buf_headroom(tmp)) { /* If there is no link layer headers in the * received fragment, then get rid of that also * in the sending fragment. We end up here * if MTU is larger than fragment size, this * is typical for ethernet. */ net_buf_push(frag, net_buf_headroom(frag)); frag->len = 0; /* to make fragment empty */ /* Make sure to set the reserve so that * in sending side we add the link layer * header if needed. */ net_pkt_set_ll_reserve(reply_pkt, 0); } NET_ASSERT(net_buf_tailroom(frag) >= tmp->len); memcpy(net_buf_add(frag, tmp->len), tmp->data, tmp->len); net_pkt_frag_add(reply_pkt, frag); tmp = net_pkt_frag_del(pkt, NULL, tmp); } reply_len = net_pkt_get_len(reply_pkt); NET_ASSERT_INFO((recv_len - header_len) == reply_len, "Received %d bytes, sending %d bytes", recv_len - header_len, reply_len); return reply_pkt; }