@@ -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,74 @@ 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+ BLE_LL_ASSERT (mux -> sdu_q_len > 0 );
232+
233+ /* Remove the SDU from the queue, as we are about to free some buffers from a chain.
234+ * Otherwise, it will result in invalid head pointed by sdu_q entry.
235+ */
236+ OS_ENTER_CRITICAL (sr );
237+ STAILQ_REMOVE_HEAD (& mux -> sdu_q , omp_next );
238+ mux -> sdu_q_len -- ;
239+ OS_EXIT_CRITICAL (sr );
240+
217241 om = OS_MBUF_PKTHDR_TO_MBUF (pkthdr );
218242
219- while ( om && num_pdu > 0 ) {
220- rem_len = om -> om_len ;
221- hdr_len = sc ? 2 /* Segmentation Header */
222- : 5 /* Segmentation Header + TimeOffset */ ;
243+ /* Iterate over all buffers in the SDU chain. */
244+ while ( num_pdu > 0 && OS_MBUF_PKTLEN ( om ) > 0 ) {
245+ hdr_len = mux -> sc ? 2 /* Segmentation Header */
246+ : 5 /* Segmentation Header + TimeOffset */ ;
223247
224- if ( mux -> max_pdu <= hdr_len + pdu_offset ) {
225- /* Advance to next PDU */
226- pdu_offset = 0 ;
248+ /* If the next SDU fragment header size exceeds remaining space in the PDU, advance to next PDU. */
249+ if ( mux -> max_pdu <= hdr_len + pdu_len ) {
250+ pdu_len = 0 ;
227251 num_pdu -- ;
228252 continue ;
229253 }
230254
231- frag_len = min (rem_len , mux -> max_pdu - hdr_len - pdu_offset );
255+ /* "Put" the header in the PDU. */
256+ pdu_len += hdr_len ;
257+
258+ /* SDU fragment length that can be fit in the PDU. */
259+ frag_len = min (OS_MBUF_PKTLEN (om ), mux -> max_pdu - pdu_len );
232260
233- pdu_offset += hdr_len + frag_len ;
261+ /* Increase PDU length by the length of the SDU fragment. */
262+ pdu_len += frag_len ;
234263
235264 os_mbuf_adj (om , frag_len );
236265
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 ;
266+ /* If the SDU fragment does not fit in the PDU, set the SC flag. */
267+ if (OS_MBUF_PKTLEN (om ) > frag_len ) {
268+ mux -> sc = 1 ;
242269 } else {
243- sc = 1 ;
270+ mux -> sc = 0 ;
244271 }
245272 }
246273
274+ om = ble_ll_isoal_sdu_trim (om , & pkt_freed );
275+ if (OS_MBUF_PKTLEN (om ) > 0 ) {
276+ /* If there is still data in the SDU chain, place the SDU back in the queue. */
277+ OS_ENTER_CRITICAL (sr );
278+ STAILQ_INSERT_HEAD (& mux -> sdu_q , pkthdr , omp_next );
279+ mux -> sdu_q_len ++ ;
280+ OS_EXIT_CRITICAL (sr );
281+ } else {
282+ /* If there are no more data in the SDU chain, free the SDU chain. */
283+ os_mbuf_free_chain (om );
284+ num_sdu -- ;
285+ }
286+
247287 if (num_pdu == 0 ) {
248288 break ;
249289 }
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 );
259290 }
260291
261292 mux -> sdu_in_event = 0 ;
262- mux -> sc = sc ;
263293
264294 return pkt_freed ;
265295}
0 commit comments