@@ -174,20 +174,31 @@ ble_ll_isoal_mux_unframed_event_done(struct ble_ll_isoal_mux *mux)
174174 return pkt_freed ;
175175}
176176
177+ static struct os_mbuf *
178+ ble_ll_isoal_sdu_trim (struct os_mbuf * om , int * pkt_freed )
179+ {
180+ /* Count the number of packets that will be freed. */
181+ for (struct os_mbuf * mbuf = om ; mbuf ; mbuf = SLIST_NEXT (mbuf , om_next )) {
182+ if (mbuf -> om_len == 0 ) {
183+ (* pkt_freed )++ ;
184+ }
185+ }
186+
187+ return os_mbuf_trim_front (om );
188+ }
189+
177190static int
178191ble_ll_isoal_mux_framed_event_done (struct ble_ll_isoal_mux * mux )
179192{
180193 struct os_mbuf_pkthdr * pkthdr ;
194+ struct os_mbuf_pkthdr * pkthdr_temp ;
181195 struct os_mbuf * om ;
182- struct os_mbuf * om_next ;
183196 uint8_t num_sdu ;
184197 uint8_t num_pdu ;
185- uint8_t pdu_offset = 0 ;
198+ uint8_t pdu_len = 0 ;
186199 uint8_t frag_len = 0 ;
187- uint8_t rem_len = 0 ;
188200 uint8_t hdr_len = 0 ;
189201 int pkt_freed = 0 ;
190- bool sc = mux -> sc ;
191202 os_sr_t sr ;
192203
193204 num_sdu = mux -> sdu_in_event ;
@@ -211,55 +222,71 @@ ble_ll_isoal_mux_framed_event_done(struct ble_ll_isoal_mux *mux)
211222 }
212223#endif
213224
214- /* Drop num_pdu PDUs */
215- pkthdr = STAILQ_FIRST (& mux -> sdu_q );
216- while (pkthdr && num_sdu -- ) {
225+ /* Iterate over all queued SDUs. */
226+ STAILQ_FOREACH_SAFE (pkthdr , & mux -> sdu_q , omp_next , pkthdr_temp ) {
227+ if (num_sdu == 0 ) {
228+ break ;
229+ }
230+
231+ /* Remove the SDU from the queue, as we are about to free some buffers from a chain.
232+ * Otherwise, it will result in invalid head pointed by sdu_q entry.
233+ */
234+ OS_ENTER_CRITICAL (sr );
235+ STAILQ_REMOVE_HEAD (& mux -> sdu_q , omp_next );
236+ BLE_LL_ASSERT (mux -> sdu_q_len > 0 );
237+ mux -> sdu_q_len -- ;
238+ OS_EXIT_CRITICAL (sr );
239+
217240 om = OS_MBUF_PKTHDR_TO_MBUF (pkthdr );
218241
219- while ( om && num_pdu > 0 ) {
220- rem_len = om -> om_len ;
221- hdr_len = sc ? 2 /* Segmentation Header */
222- : 5 /* Segmentation Header + TimeOffset */ ;
242+ /* Iterate over all buffers in the SDU chain. */
243+ while ( num_pdu > 0 && OS_MBUF_PKTLEN ( om ) > 0 ) {
244+ hdr_len = mux -> sc ? 2 /* Segmentation Header */
245+ : 5 /* Segmentation Header + TimeOffset */ ;
223246
224- if ( mux -> max_pdu <= hdr_len + pdu_offset ) {
225- /* Advance to next PDU */
226- pdu_offset = 0 ;
247+ /* If the next SDU fragment header size exceeds remaining space in the PDU, advance to next PDU. */
248+ if ( mux -> max_pdu <= hdr_len + pdu_len ) {
249+ pdu_len = 0 ;
227250 num_pdu -- ;
228251 continue ;
229252 }
230253
231- frag_len = min (rem_len , mux -> max_pdu - hdr_len - pdu_offset );
254+ /* "Put" the header in the PDU. */
255+ pdu_len += hdr_len ;
256+
257+ /* SDU fragment length that can be fit in the PDU. */
258+ frag_len = min (OS_MBUF_PKTLEN (om ), mux -> max_pdu - pdu_len );
232259
233- pdu_offset += hdr_len + frag_len ;
260+ /* Increase PDU length by the length of the SDU fragment. */
261+ pdu_len += frag_len ;
234262
235263 os_mbuf_adj (om , frag_len );
236264
237- if (frag_len == rem_len ) {
238- om_next = SLIST_NEXT (om , om_next );
239- os_mbuf_free (om );
240- pkt_freed ++ ;
241- om = om_next ;
265+ /* If the SDU fragment does not fit in the PDU, set the SC flag. */
266+ if (OS_MBUF_PKTLEN (om ) > frag_len ) {
267+ mux -> sc = 1 ;
242268 } else {
243- sc = 1 ;
269+ mux -> sc = 0 ;
244270 }
245271 }
246272
273+ om = ble_ll_isoal_sdu_trim (om , & pkt_freed );
274+ if (OS_MBUF_PKTLEN (om ) > 0 ) {
275+ /* If there is still data in the SDU chain, place the SDU back in the queue. */
276+ STAILQ_INSERT_HEAD (& mux -> sdu_q , pkthdr , omp_next );
277+ mux -> sdu_q_len ++ ;
278+ } else {
279+ /* If there are no more data in the SDU chain, free the SDU chain. */
280+ os_mbuf_free_chain (om );
281+ num_sdu -- ;
282+ }
283+
247284 if (num_pdu == 0 ) {
248285 break ;
249286 }
250-
251- OS_ENTER_CRITICAL (sr );
252- STAILQ_REMOVE_HEAD (& mux -> sdu_q , omp_next );
253- BLE_LL_ASSERT (mux -> sdu_q_len > 0 );
254- mux -> sdu_q_len -- ;
255- OS_EXIT_CRITICAL (sr );
256-
257- sc = 0 ;
258- pkthdr = STAILQ_FIRST (& mux -> sdu_q );
259287 }
260288
261289 mux -> sdu_in_event = 0 ;
262- mux -> sc = sc ;
263290
264291 return pkt_freed ;
265292}
0 commit comments