@@ -68,48 +68,6 @@ static struct bt_mesh_adv *adv_alloc(int id)
68
68
return & adv_pool [id ].adv ;
69
69
}
70
70
71
- static void discard_buffer (void )
72
- {
73
- struct bt_mesh_friend * frnd = & bt_mesh .frnd [0 ];
74
- struct net_buf * buf ;
75
- int i ;
76
-
77
- /* Find the Friend context with the most queued buffers */
78
- for (i = 1 ; i < ARRAY_SIZE (bt_mesh .frnd ); i ++ ) {
79
- if (bt_mesh .frnd [i ].queue_size > frnd -> queue_size ) {
80
- frnd = & bt_mesh .frnd [i ];
81
- }
82
- }
83
-
84
- buf = net_buf_slist_get (& frnd -> queue );
85
- __ASSERT_NO_MSG (buf != NULL );
86
- BT_WARN ("Discarding buffer %p for LPN 0x%04x" , buf , frnd -> lpn );
87
- net_buf_unref (buf );
88
- }
89
-
90
- static struct net_buf * friend_buf_alloc (u16_t src )
91
- {
92
- struct net_buf * buf ;
93
-
94
- BT_DBG ("src 0x%04x" , src );
95
-
96
- do {
97
- buf = bt_mesh_adv_create_from_pool (& friend_buf_pool , adv_alloc ,
98
- BT_MESH_ADV_DATA ,
99
- FRIEND_XMIT , K_NO_WAIT );
100
- if (!buf ) {
101
- discard_buffer ();
102
- }
103
- } while (!buf );
104
-
105
- BT_MESH_ADV (buf )-> addr = src ;
106
- FRIEND_ADV (buf )-> seq_auth = TRANS_SEQ_AUTH_NVAL ;
107
-
108
- BT_DBG ("allocated buf %p" , buf );
109
-
110
- return buf ;
111
- }
112
-
113
71
static bool is_lpn_unicast (struct bt_mesh_friend * frnd , u16_t addr )
114
72
{
115
73
if (frnd -> lpn == BT_MESH_ADDR_UNASSIGNED ) {
@@ -149,6 +107,20 @@ struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr,
149
107
return NULL ;
150
108
}
151
109
110
+ static void purge_buffers (sys_slist_t * list )
111
+ {
112
+ while (!sys_slist_is_empty (list )) {
113
+ struct net_buf * buf ;
114
+
115
+ buf = (void * )sys_slist_get_not_empty (list );
116
+
117
+ buf -> frags = NULL ;
118
+ buf -> flags &= ~NET_BUF_FRAGS ;
119
+
120
+ net_buf_unref (buf );
121
+ }
122
+ }
123
+
152
124
/* Intentionally start a little bit late into the ReceiveWindow when
153
125
* it's large enough. This may improve reliability with some platforms,
154
126
* like the PTS, where the receiver might not have sufficiently compensated
@@ -183,16 +155,13 @@ static void friend_clear(struct bt_mesh_friend *frnd)
183
155
frnd -> last = NULL ;
184
156
}
185
157
186
- while (!sys_slist_is_empty (& frnd -> queue )) {
187
- net_buf_unref (net_buf_slist_get (& frnd -> queue ));
188
- }
158
+ purge_buffers (& frnd -> queue );
189
159
190
160
for (i = 0 ; i < ARRAY_SIZE (frnd -> seg ); i ++ ) {
191
161
struct bt_mesh_friend_seg * seg = & frnd -> seg [i ];
192
162
193
- while (!sys_slist_is_empty (& seg -> queue )) {
194
- net_buf_unref (net_buf_slist_get (& seg -> queue ));
195
- }
163
+ purge_buffers (& seg -> queue );
164
+ seg -> seg_count = 0U ;
196
165
}
197
166
198
167
frnd -> valid = 0U ;
@@ -334,7 +303,15 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd,
334
303
sub = bt_mesh_subnet_get (frnd -> net_idx );
335
304
__ASSERT_NO_MSG (sub != NULL );
336
305
337
- buf = friend_buf_alloc (info -> src );
306
+ buf = bt_mesh_adv_create_from_pool (& friend_buf_pool , adv_alloc ,
307
+ BT_MESH_ADV_DATA ,
308
+ FRIEND_XMIT , K_NO_WAIT );
309
+ if (!buf ) {
310
+ return NULL ;
311
+ }
312
+
313
+ BT_MESH_ADV (buf )-> addr = info -> src ;
314
+ FRIEND_ADV (buf )-> seq_auth = TRANS_SEQ_AUTH_NVAL ;
338
315
339
316
/* Friend Offer needs master security credentials */
340
317
if (info -> ctl && TRANS_CTL_OP (sdu -> data ) == TRANS_CTL_OP_FRIEND_OFFER ) {
@@ -895,7 +872,8 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf)
895
872
}
896
873
897
874
static struct bt_mesh_friend_seg * get_seg (struct bt_mesh_friend * frnd ,
898
- u16_t src , u64_t * seq_auth )
875
+ u16_t src , u64_t * seq_auth ,
876
+ u8_t seg_count )
899
877
{
900
878
struct bt_mesh_friend_seg * unassigned = NULL ;
901
879
int i ;
@@ -914,12 +892,16 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
914
892
}
915
893
}
916
894
895
+ if (unassigned ) {
896
+ unassigned -> seg_count = seg_count ;
897
+ }
898
+
917
899
return unassigned ;
918
900
}
919
901
920
902
static void enqueue_friend_pdu (struct bt_mesh_friend * frnd ,
921
903
enum bt_mesh_friend_pdu_type type ,
922
- struct net_buf * buf )
904
+ u8_t seg_count , struct net_buf * buf )
923
905
{
924
906
struct bt_mesh_friend_seg * seg ;
925
907
struct friend_adv * adv ;
@@ -936,7 +918,7 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
936
918
}
937
919
938
920
adv = FRIEND_ADV (buf );
939
- seg = get_seg (frnd , BT_MESH_ADV (buf )-> addr , & adv -> seq_auth );
921
+ seg = get_seg (frnd , BT_MESH_ADV (buf )-> addr , & adv -> seq_auth , seg_count );
940
922
if (!seg ) {
941
923
BT_ERR ("No free friend segment RX contexts for 0x%04x" ,
942
924
BT_MESH_ADV (buf )-> addr );
@@ -961,6 +943,10 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
961
943
}
962
944
963
945
sys_slist_merge_slist (& frnd -> queue , & seg -> queue );
946
+ seg -> seg_count = 0U ;
947
+ } else {
948
+ /* Mark the buffer as having more to come after it */
949
+ buf -> flags |= NET_BUF_FRAGS ;
964
950
}
965
951
}
966
952
@@ -1026,13 +1012,17 @@ static void friend_timeout(struct k_work *work)
1026
1012
return ;
1027
1013
}
1028
1014
1029
- frnd -> last = net_buf_slist_get (& frnd -> queue );
1015
+ frnd -> last = ( void * ) sys_slist_get (& frnd -> queue );
1030
1016
if (!frnd -> last ) {
1031
1017
BT_WARN ("Friendship not established with 0x%04x" , frnd -> lpn );
1032
1018
friend_clear (frnd );
1033
1019
return ;
1034
1020
}
1035
1021
1022
+ /* Clear the flag we use for segment tracking */
1023
+ frnd -> last -> flags &= ~NET_BUF_FRAGS ;
1024
+ frnd -> last -> frags = NULL ;
1025
+
1036
1026
BT_DBG ("Sending buf %p from Friend Queue of LPN 0x%04x" ,
1037
1027
frnd -> last , frnd -> lpn );
1038
1028
frnd -> queue_size -- ;
@@ -1095,7 +1085,8 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
1095
1085
static void friend_lpn_enqueue_rx (struct bt_mesh_friend * frnd ,
1096
1086
struct bt_mesh_net_rx * rx ,
1097
1087
enum bt_mesh_friend_pdu_type type ,
1098
- u64_t * seq_auth , struct net_buf_simple * sbuf )
1088
+ u64_t * seq_auth , u8_t seg_count ,
1089
+ struct net_buf_simple * sbuf )
1099
1090
{
1100
1091
struct friend_pdu_info info ;
1101
1092
struct net_buf * buf ;
@@ -1133,7 +1124,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
1133
1124
FRIEND_ADV (buf )-> seq_auth = * seq_auth ;
1134
1125
}
1135
1126
1136
- enqueue_friend_pdu (frnd , type , buf );
1127
+ enqueue_friend_pdu (frnd , type , seg_count , buf );
1137
1128
1138
1129
BT_DBG ("Queued message for LPN 0x%04x, queue_size %u" ,
1139
1130
frnd -> lpn , frnd -> queue_size );
@@ -1142,7 +1133,8 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
1142
1133
static void friend_lpn_enqueue_tx (struct bt_mesh_friend * frnd ,
1143
1134
struct bt_mesh_net_tx * tx ,
1144
1135
enum bt_mesh_friend_pdu_type type ,
1145
- u64_t * seq_auth , struct net_buf_simple * sbuf )
1136
+ u64_t * seq_auth , u8_t seg_count ,
1137
+ struct net_buf_simple * sbuf )
1146
1138
{
1147
1139
struct friend_pdu_info info ;
1148
1140
struct net_buf * buf ;
@@ -1177,7 +1169,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
1177
1169
FRIEND_ADV (buf )-> seq_auth = * seq_auth ;
1178
1170
}
1179
1171
1180
- enqueue_friend_pdu (frnd , type , buf );
1172
+ enqueue_friend_pdu (frnd , type , seg_count , buf );
1181
1173
1182
1174
BT_DBG ("Queued message for LPN 0x%04x" , frnd -> lpn );
1183
1175
}
@@ -1227,9 +1219,118 @@ bool bt_mesh_friend_match(u16_t net_idx, u16_t addr)
1227
1219
return false;
1228
1220
}
1229
1221
1222
+ static bool friend_queue_has_space (struct bt_mesh_friend * frnd , u16_t addr ,
1223
+ u64_t * seq_auth , u8_t seg_count )
1224
+ {
1225
+ u32_t total = 0 ;
1226
+ int i ;
1227
+
1228
+ for (i = 0 ; i < ARRAY_SIZE (frnd -> seg ); i ++ ) {
1229
+ struct bt_mesh_friend_seg * seg = & frnd -> seg [i ];
1230
+
1231
+ if (seq_auth ) {
1232
+ struct net_buf * buf ;
1233
+
1234
+ /* If there's a segment queue for this message then the
1235
+ * space verification has already happened.
1236
+ */
1237
+ buf = (void * )sys_slist_peek_head (& seg -> queue );
1238
+ if (buf && BT_MESH_ADV (buf )-> addr == addr &&
1239
+ FRIEND_ADV (buf )-> seq_auth == * seq_auth ) {
1240
+ return true;
1241
+ }
1242
+ }
1243
+
1244
+ total += seg -> seg_count ;
1245
+ }
1246
+
1247
+ /* If currently pending segments combined with this segmented message
1248
+ * are more than the Friend Queue Size, then there's no space. This
1249
+ * is because we don't have a mechanism of aborting already pending
1250
+ * segmented messages to free up buffers.
1251
+ */
1252
+ return (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - total ) > seg_count ;
1253
+ }
1254
+
1255
+ bool bt_mesh_friend_queue_has_space (u16_t net_idx , u16_t src , u16_t dst ,
1256
+ u64_t * seq_auth , u8_t seg_count )
1257
+ {
1258
+ bool someone_has_space = false, friend_match = false;
1259
+ int i ;
1260
+
1261
+ if (seg_count > CONFIG_BT_MESH_FRIEND_QUEUE_SIZE ) {
1262
+ return false;
1263
+ }
1264
+
1265
+ for (i = 0 ; i < ARRAY_SIZE (bt_mesh .frnd ); i ++ ) {
1266
+ struct bt_mesh_friend * frnd = & bt_mesh .frnd [i ];
1267
+
1268
+ if (!friend_lpn_matches (frnd , net_idx , dst )) {
1269
+ continue ;
1270
+ }
1271
+
1272
+ friend_match = true;
1273
+
1274
+ if (friend_queue_has_space (frnd , src , seq_auth , seg_count )) {
1275
+ someone_has_space = true;
1276
+ }
1277
+ }
1278
+
1279
+ /* If there were no matched LPNs treat this as success, so the
1280
+ * transport layer can continue its work.
1281
+ */
1282
+ if (!friend_match ) {
1283
+ return true;
1284
+ }
1285
+
1286
+ /* From the transport layers perspective it's good enough that at
1287
+ * least one Friend Queue has space. If there were multiple Friend
1288
+ * matches then the destination must be a group address, in which
1289
+ * case e.g. segment acks are not sent.
1290
+ */
1291
+ return someone_has_space ;
1292
+ }
1293
+
1294
+ static bool friend_queue_prepare_space (struct bt_mesh_friend * frnd , u16_t addr ,
1295
+ u64_t * seq_auth , u8_t seg_count )
1296
+ {
1297
+ bool pending_segments ;
1298
+ u8_t avail_space ;
1299
+
1300
+ if (!friend_queue_has_space (frnd , addr , seq_auth , seg_count )) {
1301
+ return false;
1302
+ }
1303
+
1304
+ avail_space = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - frnd -> queue_size ;
1305
+ pending_segments = false;
1306
+
1307
+ while (pending_segments || avail_space < seg_count ) {
1308
+ struct net_buf * buf = (void * )sys_slist_get (& frnd -> queue );
1309
+
1310
+ if (!buf ) {
1311
+ BT_ERR ("Unable to free up enough buffers" );
1312
+ return false;
1313
+ }
1314
+
1315
+ frnd -> queue_size -- ;
1316
+ avail_space ++ ;
1317
+
1318
+ pending_segments = (buf -> flags & NET_BUF_FRAGS );
1319
+
1320
+ /* Make sure old slist entry state doesn't remain */
1321
+ buf -> frags = NULL ;
1322
+ buf -> flags &= ~NET_BUF_FRAGS ;
1323
+
1324
+ net_buf_unref (buf );
1325
+ }
1326
+
1327
+ return true;
1328
+ }
1329
+
1230
1330
void bt_mesh_friend_enqueue_rx (struct bt_mesh_net_rx * rx ,
1231
1331
enum bt_mesh_friend_pdu_type type ,
1232
- u64_t * seq_auth , struct net_buf_simple * sbuf )
1332
+ u64_t * seq_auth , u8_t seg_count ,
1333
+ struct net_buf_simple * sbuf )
1233
1334
{
1234
1335
int i ;
1235
1336
@@ -1246,16 +1347,25 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
1246
1347
for (i = 0 ; i < ARRAY_SIZE (bt_mesh .frnd ); i ++ ) {
1247
1348
struct bt_mesh_friend * frnd = & bt_mesh .frnd [i ];
1248
1349
1249
- if (friend_lpn_matches (frnd , rx -> sub -> net_idx ,
1250
- rx -> ctx .recv_dst )) {
1251
- friend_lpn_enqueue_rx ( frnd , rx , type , seq_auth , sbuf ) ;
1350
+ if (! friend_lpn_matches (frnd , rx -> sub -> net_idx ,
1351
+ rx -> ctx .recv_dst )) {
1352
+ continue ;
1252
1353
}
1354
+
1355
+ if (!friend_queue_prepare_space (frnd , rx -> ctx .addr , seq_auth ,
1356
+ seg_count )) {
1357
+ continue ;
1358
+ }
1359
+
1360
+ friend_lpn_enqueue_rx (frnd , rx , type , seq_auth , seg_count ,
1361
+ sbuf );
1253
1362
}
1254
1363
}
1255
1364
1256
1365
bool bt_mesh_friend_enqueue_tx (struct bt_mesh_net_tx * tx ,
1257
1366
enum bt_mesh_friend_pdu_type type ,
1258
- u64_t * seq_auth , struct net_buf_simple * sbuf )
1367
+ u64_t * seq_auth , u8_t seg_count ,
1368
+ struct net_buf_simple * sbuf )
1259
1369
{
1260
1370
bool matched = false;
1261
1371
int i ;
@@ -1271,10 +1381,19 @@ bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
1271
1381
for (i = 0 ; i < ARRAY_SIZE (bt_mesh .frnd ); i ++ ) {
1272
1382
struct bt_mesh_friend * frnd = & bt_mesh .frnd [i ];
1273
1383
1274
- if (friend_lpn_matches (frnd , tx -> sub -> net_idx , tx -> ctx -> addr )) {
1275
- friend_lpn_enqueue_tx (frnd , tx , type , seq_auth , sbuf );
1276
- matched = true;
1384
+ if (!friend_lpn_matches (frnd , tx -> sub -> net_idx ,
1385
+ tx -> ctx -> addr )) {
1386
+ continue ;
1387
+ }
1388
+
1389
+ if (!friend_queue_prepare_space (frnd , tx -> src , seq_auth ,
1390
+ seg_count )) {
1391
+ continue ;
1277
1392
}
1393
+
1394
+ friend_lpn_enqueue_tx (frnd , tx , type , seq_auth , seg_count ,
1395
+ sbuf );
1396
+ matched = true;
1278
1397
}
1279
1398
1280
1399
return matched ;
@@ -1314,9 +1433,8 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
1314
1433
1315
1434
BT_WARN ("Clearing incomplete segments for 0x%04x" , src );
1316
1435
1317
- while (!sys_slist_is_empty (& seg -> queue )) {
1318
- net_buf_unref (net_buf_slist_get (& seg -> queue ));
1319
- }
1436
+ purge_buffers (& seg -> queue );
1437
+ seg -> seg_count = 0U ;
1320
1438
}
1321
1439
}
1322
1440
}
0 commit comments