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 */
26 static struct os_mbuf *
ble_hs_mbuf_gen_pkt(uint16_t leading_space)27 ble_hs_mbuf_gen_pkt(uint16_t leading_space)
28 {
29 struct os_mbuf *om;
30 int rc;
31
32 om = os_msys_get_pkthdr(0, 0);
33 if (om == NULL) {
34 return NULL;
35 }
36
37 if (om->om_omp->omp_databuf_len < leading_space) {
38 rc = os_mbuf_free_chain(om);
39 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
40 return NULL;
41 }
42
43 om->om_data += leading_space;
44
45 return om;
46 }
47
48 /**
49 * Allocates an mbuf with no leading space.
50 *
51 * @return An empty mbuf on success; null on memory
52 * exhaustion.
53 */
54 struct os_mbuf *
ble_hs_mbuf_bare_pkt(void)55 ble_hs_mbuf_bare_pkt(void)
56 {
57 return ble_hs_mbuf_gen_pkt(0);
58 }
59
60 /**
61 * Allocates an mbuf suitable for an HCI ACL data packet.
62 *
63 * @return An empty mbuf on success; null on memory
64 * exhaustion.
65 */
66 struct os_mbuf *
ble_hs_mbuf_acl_pkt(void)67 ble_hs_mbuf_acl_pkt(void)
68 {
69 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ);
70 }
71
72 /**
73 * Allocates an mbuf suitable for an L2CAP data packet. The resulting packet
74 * has sufficient leading space for:
75 * o ACL data header
76 * o L2CAP B-frame header
77 *
78 * @return An empty mbuf on success; null on memory
79 * exhaustion.
80 */
81 struct os_mbuf *
ble_hs_mbuf_l2cap_pkt(void)82 ble_hs_mbuf_l2cap_pkt(void)
83 {
84 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + BLE_L2CAP_HDR_SZ);
85 }
86
87 struct os_mbuf *
ble_hs_mbuf_att_pkt(void)88 ble_hs_mbuf_att_pkt(void)
89 {
90 /* Prepare write request and response are the larget ATT commands which
91 * contain attribute data.
92 */
93 return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ +
94 BLE_L2CAP_HDR_SZ +
95 BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
96 }
97
98 struct os_mbuf *
ble_hs_mbuf_from_flat(const void * buf,uint16_t len)99 ble_hs_mbuf_from_flat(const void *buf, uint16_t len)
100 {
101 struct os_mbuf *om;
102 int rc;
103
104 om = ble_hs_mbuf_att_pkt();
105 if (om == NULL) {
106 return NULL;
107 }
108
109 rc = os_mbuf_copyinto(om, 0, buf, len);
110 if (rc != 0) {
111 os_mbuf_free_chain(om);
112 return NULL;
113 }
114
115 return om;
116 }
117
118 int
ble_hs_mbuf_to_flat(const struct os_mbuf * om,void * flat,uint16_t max_len,uint16_t * out_copy_len)119 ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
120 uint16_t *out_copy_len)
121 {
122 uint16_t copy_len;
123 int rc;
124
125 if (OS_MBUF_PKTLEN(om) <= max_len) {
126 copy_len = OS_MBUF_PKTLEN(om);
127 } else {
128 copy_len = max_len;
129 }
130
131 rc = os_mbuf_copydata(om, 0, copy_len, flat);
132 if (rc != 0) {
133 return BLE_HS_EUNKNOWN;
134 }
135
136 if (copy_len > max_len) {
137 rc = BLE_HS_EMSGSIZE;
138 } else {
139 rc = 0;
140 }
141
142 if (out_copy_len != NULL) {
143 *out_copy_len = copy_len;
144 }
145 return rc;
146 }
147
148 int
ble_hs_mbuf_pullup_base(struct os_mbuf ** om,int base_len)149 ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len)
150 {
151 if (OS_MBUF_PKTLEN(*om) < base_len) {
152 return BLE_HS_EBADDATA;
153 }
154
155 *om = os_mbuf_pullup(*om, base_len);
156 if (*om == NULL) {
157 return BLE_HS_ENOMEM;
158 }
159
160 return 0;
161 }
162