1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "host/ble_hs.h"
21 #include "ble_hs_priv.h"
22
23 /**
24 * Allocates an mbuf for use by the nimble host.
25 */
ble_hs_mbuf_gen_pkt(uint16_t leading_space)26 static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space)
27 {
28 struct os_mbuf *om;
29 om = os_msys_get_pkthdr(0, 0);
30 if (om == NULL) {
31 return NULL;
32 }
33
34 if (om->om_omp->omp_databuf_len < leading_space) {
35 int rc = os_mbuf_free_chain(om);
36 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
37 return NULL;
38 }
39
40 om->om_data += leading_space;
41 return om;
42 }
43
44 /**
45 * Allocates an mbuf with no leading space.
46 *
47 * @return An empty mbuf on success; null on memory
48 * exhaustion.
49 */
ble_hs_mbuf_bare_pkt(void)50 struct os_mbuf *ble_hs_mbuf_bare_pkt(void)
51 {
52 return ble_hs_mbuf_gen_pkt(0);
53 }
54
55 /**
56 * Allocates an mbuf suitable for an HCI ACL data packet.
57 *
58 * @return An empty mbuf on success; null on memory
59 * exhaustion.
60 */
ble_hs_mbuf_acl_pkt(void)61 struct os_mbuf *ble_hs_mbuf_acl_pkt(void)
62 {
63 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ);
64 }
65
66 /**
67 * Allocates an mbuf suitable for an L2CAP data packet. The resulting packet
68 * has sufficient leading space for:
69 * o ACL data header
70 * o L2CAP B-frame header
71 *
72 * @return An empty mbuf on success; null on memory
73 * exhaustion.
74 */
ble_hs_mbuf_l2cap_pkt(void)75 struct os_mbuf *ble_hs_mbuf_l2cap_pkt(void)
76 {
77 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + BLE_L2CAP_HDR_SZ);
78 }
79
ble_hs_mbuf_att_pkt(void)80 struct os_mbuf *ble_hs_mbuf_att_pkt(void)
81 {
82 /* Prepare write request and response are the larget ATT commands which
83 * contain attribute data.
84 */
85 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ +
86 BLE_L2CAP_HDR_SZ +
87 BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
88 }
89
ble_hs_mbuf_from_flat(const void * buf,uint16_t len)90 struct os_mbuf *ble_hs_mbuf_from_flat(const void *buf, uint16_t len)
91 {
92 struct os_mbuf *om;
93 int rc;
94 om = ble_hs_mbuf_att_pkt();
95 if (om == NULL) {
96 return NULL;
97 }
98
99 rc = os_mbuf_copyinto(om, 0, buf, len);
100 if (rc != 0) {
101 os_mbuf_free_chain(om);
102 return NULL;
103 }
104
105 return om;
106 }
107
ble_hs_mbuf_to_flat(const struct os_mbuf * om,void * flat,uint16_t max_len,uint16_t * out_copy_len)108 int ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
109 uint16_t *out_copy_len)
110 {
111 uint16_t copy_len;
112 int rc;
113
114 if (OS_MBUF_PKTLEN(om) <= max_len) {
115 copy_len = OS_MBUF_PKTLEN(om);
116 } else {
117 copy_len = max_len;
118 }
119
120 rc = os_mbuf_copydata(om, 0, copy_len, flat);
121 if (rc != 0) {
122 return BLE_HS_EUNKNOWN;
123 }
124
125 if (copy_len > max_len) {
126 rc = BLE_HS_EMSGSIZE;
127 } else {
128 rc = 0;
129 }
130
131 if (out_copy_len != NULL) {
132 *out_copy_len = copy_len;
133 }
134
135 return rc;
136 }
137
ble_hs_mbuf_pullup_base(struct os_mbuf ** om,int base_len)138 int ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len)
139 {
140 if (OS_MBUF_PKTLEN(*om) < base_len) {
141 return BLE_HS_EBADDATA;
142 }
143
144 *om = os_mbuf_pullup(*om, base_len);
145 if (*om == NULL) {
146 return BLE_HS_ENOMEM;
147 }
148
149 return 0;
150 }