<p>Harald Welte has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/13310">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add _buf() functions to bypass static string buffers<br><br>We have a number of static buffers in use in libosmo*.  This means<br>the related functions are not usable in a thread-safe way.  While<br>we so far don't have many multi-threaded programs in the osmocom<br>universe, the static buffers also prevent us from calling the same<br>e.g. string-ify function twice within a single printf() call.<br><br>Let's make sure there's an alternative function in all those cases,<br>where the user can pass in a caller-allocated buffer + size, and make<br>the 'classic' function with the static buffer a wrapper around that<br>_buf() variant.<br><br>Change-Id: Ibf85f79e93244f53b2684ff6f1095c5b41203e05<br>---<br>M include/osmocom/core/msgb.h<br>M include/osmocom/core/utils.h<br>M include/osmocom/gprs/gprs_ns.h<br>M include/osmocom/gsm/abis_nm.h<br>M include/osmocom/gsm/apn.h<br>M include/osmocom/gsm/gsm0808_utils.h<br>M include/osmocom/gsm/gsm23003.h<br>M include/osmocom/gsm/gsm48.h<br>M include/osmocom/gsm/gsm_utils.h<br>M include/osmocom/gsm/protocol/gsm_04_08.h<br>M include/osmocom/gsm/rsl.h<br>M include/osmocom/sim/sim.h<br>M src/gb/gprs_ns.c<br>M src/gb/libosmogb.map<br>M src/gsm/abis_nm.c<br>M src/gsm/apn.c<br>M src/gsm/gsm0808_utils.c<br>M src/gsm/gsm23003.c<br>M src/gsm/gsm48.c<br>M src/gsm/gsm_utils.c<br>M src/gsm/libosmogsm.map<br>M src/gsm/rsl.c<br>M src/msgb.c<br>M src/sim/core.c<br>M src/utils.c<br>25 files changed, 360 insertions(+), 116 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/10/13310/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h</span><br><span>index f006b34..4299fb8 100644</span><br><span>--- a/include/osmocom/core/msgb.h</span><br><span>+++ b/include/osmocom/core/msgb.h</span><br><span>@@ -67,6 +67,7 @@</span><br><span> extern void msgb_reset(struct msgb *m);</span><br><span> uint16_t msgb_length(const struct msgb *msg);</span><br><span> extern const char *msgb_hexdump(const struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+char *msgb_hexdump_buf(char *buf, size_t buf_len, const struct msgb *msg);</span><br><span> extern int msgb_resize_area(struct msgb *msg, uint8_t *area,</span><br><span>         int old_size, int new_size);</span><br><span> extern struct msgb *msgb_copy(const struct msgb *msg, const char *name);</span><br><span>diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h</span><br><span>index 16159d3..22b2ca5 100644</span><br><span>--- a/include/osmocom/core/utils.h</span><br><span>+++ b/include/osmocom/core/utils.h</span><br><span>@@ -53,6 +53,7 @@</span><br><span> </span><br><span> int osmo_hexparse(const char *str, uint8_t *b, int max_len);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len);</span><br><span> char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);</span><br><span> char *osmo_hexdump(const unsigned char *buf, int len);</span><br><span> char *osmo_hexdump_nospc(const unsigned char *buf, int len);</span><br><span>diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h</span><br><span>index c62ef98..ed155ff 100644</span><br><span>--- a/include/osmocom/gprs/gprs_ns.h</span><br><span>+++ b/include/osmocom/gprs/gprs_ns.h</span><br><span>@@ -211,6 +211,8 @@</span><br><span> </span><br><span> /* Resturn peer info as string (NOTE: the buffer is allocated statically) */</span><br><span> const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+/* Return peer info in user-supplied buffer */</span><br><span style="color: hsl(120, 100%, 40%);">+char *gprs_ns_ll_str_buf(char *buf, size_t buf_len, const struct gprs_nsvc *nsvc);</span><br><span> </span><br><span> /* Copy the link layer info from other into nsvc */</span><br><span> void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other);</span><br><span>diff --git a/include/osmocom/gsm/abis_nm.h b/include/osmocom/gsm/abis_nm.h</span><br><span>index 823b5a4..788727c 100644</span><br><span>--- a/include/osmocom/gsm/abis_nm.h</span><br><span>+++ b/include/osmocom/gsm/abis_nm.h</span><br><span>@@ -42,6 +42,7 @@</span><br><span> extern const struct tlv_definition abis_nm_att_tlvdef_ipa;</span><br><span> </span><br><span> const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh);</span><br><span style="color: hsl(120, 100%, 40%);">+char *abis_nm_dump_foh_buf(char *buf, size_t buf_len, const struct abis_om_fom_hdr *foh);</span><br><span> </span><br><span> /*! write a human-readable OML header to the debug log</span><br><span>  *  \param[in] ss Logging sub-system</span><br><span>diff --git a/include/osmocom/gsm/apn.h b/include/osmocom/gsm/apn.h</span><br><span>index 288b229..7899bb2 100644</span><br><span>--- a/include/osmocom/gsm/apn.h</span><br><span>+++ b/include/osmocom/gsm/apn.h</span><br><span>@@ -11,11 +11,14 @@</span><br><span> #define APN_MAXLEN  100</span><br><span> </span><br><span> char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify_buf(char *buf, size_t buf_len, unsigned int mcc, unsigned int mnc, const char *ni);</span><br><span> </span><br><span> /* Compose a string of the form '<ni>.mnc001.mcc002.gprs\0', returned in a</span><br><span>  * static buffer. */</span><br><span> char *osmo_apn_qualify_from_imsi(const char *imsi,</span><br><span>                              const char *ni, int have_3dig_mnc);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify_from_imsi_buf(char *buf, size_t buf_len, const char *imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const char *ni, int have_3dig_mnc);</span><br><span> </span><br><span> int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char *str);</span><br><span> char *osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t apn_enc_len);</span><br><span>diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h</span><br><span>index dedb029..e246967 100644</span><br><span>--- a/include/osmocom/gsm/gsm0808_utils.h</span><br><span>+++ b/include/osmocom/gsm/gsm0808_utils.h</span><br><span>@@ -69,7 +69,9 @@</span><br><span> };</span><br><span> </span><br><span> char *osmo_lcls_dump(const struct osmo_lcls *lcls);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_lcls_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls);</span><br><span> char *osmo_gcr_dump(const struct osmo_lcls *lcls);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gcr_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls);</span><br><span> </span><br><span> extern const struct value_string gsm0808_cell_id_discr_names[];</span><br><span> static inline const char *gsm0808_cell_id_discr_name(enum CELL_IDENT id_discr)</span><br><span>@@ -251,5 +253,6 @@</span><br><span> }</span><br><span> </span><br><span> const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct);</span><br><span style="color: hsl(120, 100%, 40%);">+char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct);</span><br><span> </span><br><span> /*! @} */</span><br><span>diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h</span><br><span>index cf622ce..88c4f3c 100644</span><br><span>--- a/include/osmocom/gsm/gsm23003.h</span><br><span>+++ b/include/osmocom/gsm/gsm23003.h</span><br><span>@@ -105,13 +105,19 @@</span><br><span> bool osmo_imei_str_valid(const char *imei, bool with_15th_digit);</span><br><span> </span><br><span> const char *osmo_mcc_name(uint16_t mcc);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mcc_name_buf(char *buf, size_t buf_len, uint16_t mcc);</span><br><span> const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mnc_name_buf(char *buf, size_t buf_len, uint16_t mnc, bool mnc_3_digits);</span><br><span> const char *osmo_plmn_name(const struct osmo_plmn_id *plmn);</span><br><span> const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_plmn_name_buf(char *buf, size_t buf_len, const struct osmo_plmn_id *plmn);</span><br><span> const char *osmo_lai_name(const struct osmo_location_area_id *lai);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai);</span><br><span> const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi);</span><br><span> const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi);</span><br><span> const char *osmo_gummei_name(const struct osmo_gummei *gummei);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei);</span><br><span> </span><br><span> void osmo_plmn_to_bcd(uint8_t *bcd_dst, const struct osmo_plmn_id *plmn);</span><br><span> void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn);</span><br><span>diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h</span><br><span>index 7e0e5c4..81b2bf0 100644</span><br><span>--- a/include/osmocom/gsm/gsm48.h</span><br><span>+++ b/include/osmocom/gsm/gsm48.h</span><br><span>@@ -35,6 +35,7 @@</span><br><span> const char *gsm48_rr_msg_name(uint8_t msgtype);</span><br><span> const char *rr_cause_name(uint8_t cause);</span><br><span> const char *osmo_rai_name(const struct gprs_ra_id *rai);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_rai_name_buf(char *buf, size_t buf_len, const struct gprs_ra_id *rai);</span><br><span> </span><br><span> int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,</span><br><span>                      uint16_t *mnc, uint16_t *lac)</span><br><span>@@ -55,6 +56,7 @@</span><br><span>                       const uint8_t *mi, const int mi_len);</span><br><span> const char *gsm48_mi_type_name(uint8_t mi);</span><br><span> const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mi_name_buf(char *buf, size_t buf_len, const uint8_t *mi, uint8_t mi_len);</span><br><span> </span><br><span> /* Parse Routeing Area Identifier */</span><br><span> void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);</span><br><span>diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h</span><br><span>index 7d0beca..7de0623 100644</span><br><span>--- a/include/osmocom/gsm/gsm_utils.h</span><br><span>+++ b/include/osmocom/gsm/gsm_utils.h</span><br><span>@@ -181,6 +181,7 @@</span><br><span> </span><br><span> /* Returns static buffer with string representation of a GSM Time */</span><br><span> char *osmo_dump_gsmtime(const struct gsm_time *tm);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm);</span><br><span> </span><br><span> /* GSM TS 03.03 Chapter 2.6 */</span><br><span> enum gprs_tlli_type {</span><br><span>diff --git a/include/osmocom/gsm/protocol/gsm_04_08.h b/include/osmocom/gsm/protocol/gsm_04_08.h</span><br><span>index c052e4c..c97df16 100644</span><br><span>--- a/include/osmocom/gsm/protocol/gsm_04_08.h</span><br><span>+++ b/include/osmocom/gsm/protocol/gsm_04_08.h</span><br><span>@@ -70,6 +70,7 @@</span><br><span> bool osmo_gsm48_classmark2_is_r99(const struct gsm48_classmark2 *cm2, uint8_t cm2_len);</span><br><span> int osmo_gsm48_classmark_supports_a5(const struct osmo_gsm48_classmark *cm, uint8_t a5);</span><br><span> const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gsm48_classmark_a5_name_buf(char *buf, size_t buf_len, const struct osmo_gsm48_classmark *cm);</span><br><span> void osmo_gsm48_classmark_update(struct osmo_gsm48_classmark *dst, const struct osmo_gsm48_classmark *src);</span><br><span> </span><br><span> /* Chapter 10.5.2.1b.3 */</span><br><span>@@ -1643,6 +1644,7 @@</span><br><span> extern const struct value_string gsm48_mm_msgtype_names[];</span><br><span> extern const struct value_string gsm48_cc_msgtype_names[];</span><br><span> const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+char *gsm48_pdisc_msgtype_name_buf(char *buf, size_t buf_len, uint8_t pdisc, uint8_t msg_type);</span><br><span> </span><br><span> /* FIXME: Table 10.4 / 10.4a (GPRS) */</span><br><span> </span><br><span>diff --git a/include/osmocom/gsm/rsl.h b/include/osmocom/gsm/rsl.h</span><br><span>index be0fa79..4a1da3a 100644</span><br><span>--- a/include/osmocom/gsm/rsl.h</span><br><span>+++ b/include/osmocom/gsm/rsl.h</span><br><span>@@ -30,6 +30,7 @@</span><br><span> /* decode channel number as per Section 9.3.1 */</span><br><span> int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot);</span><br><span> /* Turns channel number into a string */</span><br><span style="color: hsl(120, 100%, 40%);">+char *rsl_chan_nr_str_buf(char *buf, size_t buf_len, uint8_t chan_nr);</span><br><span> const char *rsl_chan_nr_str(uint8_t chan_nr);</span><br><span> </span><br><span> </span><br><span>diff --git a/include/osmocom/sim/sim.h b/include/osmocom/sim/sim.h</span><br><span>index 680cad1..0490dcd 100644</span><br><span>--- a/include/osmocom/sim/sim.h</span><br><span>+++ b/include/osmocom/sim/sim.h</span><br><span>@@ -296,6 +296,7 @@</span><br><span>                                    uint16_t sw_in);</span><br><span> </span><br><span> struct osim_card_hdl;</span><br><span style="color: hsl(120, 100%, 40%);">+char *osim_print_sw_buf(char *buf, size_t buf_len, const struct osim_card_hdl *ch, uint16_t sw_in);</span><br><span> char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in);</span><br><span> </span><br><span> extern const struct tlv_definition ts102221_fcp_tlv_def;</span><br><span>diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c</span><br><span>index 8c3b0fa..ea889ef 100644</span><br><span>--- a/src/gb/gprs_ns.c</span><br><span>+++ b/src/gb/gprs_ns.c</span><br><span>@@ -1525,17 +1525,15 @@</span><br><span>    return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+char *gprs_ns_ll_str_buf(char *buf, size_t buf_len, const struct gprs_nsvc *nsvc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     static char buf[80];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         switch(nsvc->ll) {</span><br><span>        case GPRS_NS_LL_UDP:</span><br><span style="color: hsl(0, 100%, 40%);">-            snprintf(buf, sizeof(buf), "%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(buf, buf_len, "%s:%u",</span><br><span>                     inet_ntoa(nsvc->ip.bts_addr.sin_addr), osmo_ntohs(nsvc->ip.bts_addr.sin_port));</span><br><span>               break;</span><br><span>       case GPRS_NS_LL_FR_GRE:</span><br><span style="color: hsl(0, 100%, 40%);">-         snprintf(buf, sizeof(buf), "%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(buf, buf_len, "%s:%u",</span><br><span>                     inet_ntoa(nsvc->frgre.bts_addr.sin_addr), osmo_ntohs(nsvc->frgre.bts_addr.sin_port));</span><br><span>                 break;</span><br><span>       default:</span><br><span>@@ -1543,11 +1541,17 @@</span><br><span>           break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   buf[sizeof(buf) - 1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  buf[buf_len - 1] = '\0';</span><br><span> </span><br><span>         return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static char buf[80];</span><br><span style="color: hsl(120, 100%, 40%);">+  return gprs_ns_ll_str_buf(buf, sizeof(buf), nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other)</span><br><span> {</span><br><span>        nsvc->ll = other->ll;</span><br><span>diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map</span><br><span>index 2ad3ff7..21929da 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -64,6 +64,7 @@</span><br><span> gprs_ns_tx_unblock;</span><br><span> gprs_ns_vty_init;</span><br><span> gprs_ns_ll_str;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns_ll_str_buf;</span><br><span> gprs_ns_ll_copy;</span><br><span> gprs_ns_ll_clear;</span><br><span> gprs_ns_msgb_alloc;</span><br><span>diff --git a/src/gsm/abis_nm.c b/src/gsm/abis_nm.c</span><br><span>index 49d05ba..e25fdd0 100644</span><br><span>--- a/src/gsm/abis_nm.c</span><br><span>+++ b/src/gsm/abis_nm.c</span><br><span>@@ -928,14 +928,19 @@</span><br><span>    return GSM_PCHAN_NONE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh)</span><br><span style="color: hsl(120, 100%, 40%);">+char *abis_nm_dump_foh_buf(char *buf, size_t buf_len, const struct abis_om_fom_hdr *foh)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   static char foh_buf[128];</span><br><span style="color: hsl(0, 100%, 40%);">-       snprintf(foh_buf, sizeof(foh_buf), "OC=%s(%02x) INST=(%02x,%02x,%02x)",</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(buf, buf_len, "OC=%s(%02x) INST=(%02x,%02x,%02x)",</span><br><span>                get_value_string(abis_nm_obj_class_names, foh->obj_class),</span><br><span>                foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,</span><br><span>                 foh->obj_inst.ts_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-        return foh_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+       return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  static char foh_buf[128];</span><br><span style="color: hsl(120, 100%, 40%);">+     return abis_nm_dump_foh_buf(foh_buf, sizeof(foh_buf), foh);</span><br><span> }</span><br><span> </span><br><span> /* this is just for compatibility reasons, it is now a macro */</span><br><span>diff --git a/src/gsm/apn.c b/src/gsm/apn.c</span><br><span>index 2674663..4ab370c 100644</span><br><span>--- a/src/gsm/apn.c</span><br><span>+++ b/src/gsm/apn.c</span><br><span>@@ -32,17 +32,22 @@</span><br><span> </span><br><span> static char apn_strbuf[APN_MAXLEN+1];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify_buf(char *buf, size_t buf_len, unsigned int mcc, unsigned int mnc, const char *ni)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       snprintf(apn_strbuf, sizeof(apn_strbuf)-1, APN_GPRS_FMT,</span><br><span style="color: hsl(0, 100%, 40%);">-                ni, mnc, mcc);</span><br><span style="color: hsl(0, 100%, 40%);">-  apn_strbuf[sizeof(apn_strbuf)-1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+      snprintf(buf, buf_len-1, APN_GPRS_FMT, ni, mnc, mcc);</span><br><span style="color: hsl(120, 100%, 40%);">+ buf[buf_len-1] = '\0';</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      return apn_strbuf;</span><br><span style="color: hsl(120, 100%, 40%);">+    return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_apn_qualify_from_imsi(const char *imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                           const char *ni, int have_3dig_mnc)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return osmo_apn_qualify_buf(apn_strbuf, sizeof(apn_strbuf), mcc, mnc, ni);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify_from_imsi_buf(char *buf, size_t buf_len, const char *imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const char *ni, int have_3dig_mnc)</span><br><span> {</span><br><span>         char cbuf[3+1], nbuf[3+1];</span><br><span> </span><br><span>@@ -56,7 +61,13 @@</span><br><span>          strncpy(nbuf, imsi+3, 2);</span><br><span>            nbuf[2] = '\0';</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-       return osmo_apn_qualify(atoi(cbuf), atoi(nbuf), ni);</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_apn_qualify_buf(buf, buf_len, atoi(cbuf), atoi(nbuf), ni);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_apn_qualify_from_imsi(const char *imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                const char *ni, int have_3dig_mnc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return osmo_apn_qualify_from_imsi_buf(apn_strbuf, sizeof(apn_strbuf), imsi, ni, have_3dig_mnc);</span><br><span> }</span><br><span> </span><br><span> /**</span><br><span>diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c</span><br><span>index e0cdaaf..52e4674 100644</span><br><span>--- a/src/gsm/gsm0808_utils.c</span><br><span>+++ b/src/gsm/gsm0808_utils.c</span><br><span>@@ -595,11 +595,13 @@</span><br><span> static char dbuf[256];</span><br><span> </span><br><span> /*! Dump LCLS parameters (GCR excluded) into string for printing.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] buf caller-allocated output string buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf_len size of buf in bytes</span><br><span>  *  \param[in] lcls pointer to the struct to print.</span><br><span>  *  \returns string representation of LCLS or NULL on error. */</span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_lcls_dump(const struct osmo_lcls *lcls)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_lcls_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_strbuf s = { .buf = dbuf, .len = 256 };</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_strbuf s = { .buf = buf, .len = buf_len };</span><br><span> </span><br><span>   if (!lcls)</span><br><span>           return NULL;</span><br><span>@@ -612,12 +614,22 @@</span><br><span>         return dbuf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Dump LCLS parameters (GCR excluded) into static string buffer for printing.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] lcls pointer to the struct to print.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns string representation of LCLS in static buffer or NULL on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_lcls_dump(const struct osmo_lcls *lcls)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_lcls_dump_buf(dbuf, sizeof(dbuf), lcls);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Dump GCR struct into string for printing.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] buf caller-allocated output string buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf_len size of buf in bytes</span><br><span>  *  \param[in] lcls pointer to the struct to print.</span><br><span>  *  \returns string representation of GCR or NULL on error. */</span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_gcr_dump(const struct osmo_lcls *lcls)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gcr_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct osmo_strbuf s = { .buf = dbuf, .len = 256 };</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_strbuf s = { .buf = buf, .len = buf_len };</span><br><span> </span><br><span>   if (!lcls)</span><br><span>           return NULL;</span><br><span>@@ -631,6 +643,15 @@</span><br><span>  return dbuf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Dump GCR struct into static string buffer for printing.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] lcls pointer to the struct to print.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns string representation of GCR in static buffer or NULL on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gcr_dump(const struct osmo_lcls *lcls)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return osmo_gcr_dump_buf(dbuf, sizeof(dbuf), lcls);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Encode TS 08.08 Encryption Information IE</span><br><span>  *  \param[out] msg Message Buffer to which IE is to be appended</span><br><span>  *  \param[in] ei Encryption Information to be encoded</span><br><span>@@ -1838,13 +1859,18 @@</span><br><span> #undef APPEND_STR</span><br><span> #undef APPEND_CELL_ID_U</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct)</span><br><span style="color: hsl(120, 100%, 40%);">+char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- static char buf[128];</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(buf, sizeof(buf), "ch_indctr=0x%x ch_rate_type=0x%x perm_spch=%s",</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(buf, buf_len, "ch_indctr=0x%x ch_rate_type=0x%x perm_spch=%s",</span><br><span>             ct->ch_indctr, ct->ch_rate_type,</span><br><span>               osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span>      return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static char buf[128];</span><br><span style="color: hsl(120, 100%, 40%);">+ return gsm0808_channel_type_name_buf(buf, sizeof(buf), ct);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! @} */</span><br><span>diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c</span><br><span>index 720c09b..b189cce 100644</span><br><span>--- a/src/gsm/gsm23003.c</span><br><span>+++ b/src/gsm/gsm23003.c</span><br><span>@@ -90,13 +90,37 @@</span><br><span> }</span><br><span> </span><br><span> /*! Return MCC string as standardized 3-digit with leading zeros.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] mcc  MCC value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string in user-supplied output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mcc_name_buf(char *buf, size_t buf_len, uint16_t mcc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(buf, buf_len, "%03u", mcc);</span><br><span style="color: hsl(120, 100%, 40%);">+        return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MCC string as standardized 3-digit with leading zeros.</span><br><span>  * \param[in] mcc  MCC value.</span><br><span>  * \returns string in static buffer.</span><br><span>  */</span><br><span> const char *osmo_mcc_name(uint16_t mcc)</span><br><span> {</span><br><span>  static char buf[8];</span><br><span style="color: hsl(0, 100%, 40%);">-     snprintf(buf, sizeof(buf), "%03u", mcc);</span><br><span style="color: hsl(120, 100%, 40%);">+    return osmo_mcc_name_buf(buf, sizeof(buf), mcc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MNC string as standardized 2- or 3-digit with leading zeros.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] mnc  MNC value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] mnc_3_digits  True if an MNC should fill three digits, only has an effect if MNC < 100.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mnc_name_buf(char *buf, size_t buf_len, uint16_t mnc, bool mnc_3_digits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(buf, buf_len, "%0*u", mnc_3_digits ? 3 : 2, mnc);</span><br><span>         return buf;</span><br><span> }</span><br><span> </span><br><span>@@ -108,14 +132,21 @@</span><br><span> const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits)</span><br><span> {</span><br><span>      static char buf[8];</span><br><span style="color: hsl(0, 100%, 40%);">-     snprintf(buf, sizeof(buf), "%0*u", mnc_3_digits ? 3 : 2, mnc);</span><br><span style="color: hsl(0, 100%, 40%);">-        return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_mnc_name_buf(buf, sizeof(buf), mnc, mnc_3_digits);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static inline void plmn_name(char *buf, size_t buflen, const struct osmo_plmn_id *plmn)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] plmn  MCC-MNC value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_plmn_name_buf(char *buf, size_t buf_len, const struct osmo_plmn_id *plmn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(buf, buflen, "%s-%s", osmo_mcc_name(plmn->mcc),</span><br><span style="color: hsl(0, 100%, 40%);">-            osmo_mnc_name(plmn->mnc, plmn->mnc_3_digits));</span><br><span style="color: hsl(120, 100%, 40%);">+ char mcc[8], mnc[8];</span><br><span style="color: hsl(120, 100%, 40%);">+  snprintf(buf, buf_len, "%s-%s", osmo_mcc_name_buf(mcc, sizeof(mcc), plmn->mcc),</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_mnc_name_buf(mnc, sizeof(mnc), plmn->mnc, plmn->mnc_3_digits));</span><br><span style="color: hsl(120, 100%, 40%);">+   return buf;</span><br><span> }</span><br><span> </span><br><span> /*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.</span><br><span>@@ -125,10 +156,10 @@</span><br><span> const char *osmo_plmn_name(const struct osmo_plmn_id *plmn)</span><br><span> {</span><br><span>     static char buf[16];</span><br><span style="color: hsl(0, 100%, 40%);">-    plmn_name(buf, sizeof(buf), plmn);</span><br><span style="color: hsl(0, 100%, 40%);">-      return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_plmn_name_buf(buf, sizeof(buf), plmn);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Same as osmo_plmn_name(), but returning in a different static buffer.</span><br><span>  * \param[in] plmn  MCC-MNC value.</span><br><span>  * \returns string in static buffer.</span><br><span>@@ -136,7 +167,19 @@</span><br><span> const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn)</span><br><span> {</span><br><span>         static char buf[16];</span><br><span style="color: hsl(0, 100%, 40%);">-    plmn_name(buf, sizeof(buf), plmn);</span><br><span style="color: hsl(120, 100%, 40%);">+    return osmo_plmn_name_buf(buf, sizeof(buf), plmn);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MCC-MNC-LAC as string, in caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] lai  LAI to encode, the rac member is ignored.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char plmn[16];</span><br><span style="color: hsl(120, 100%, 40%);">+        snprintf(buf, buf_len, "%s-%u", osmo_plmn_name_buf(plmn, sizeof(plmn), &lai->plmn), lai->lac);</span><br><span>   return buf;</span><br><span> }</span><br><span> </span><br><span>@@ -147,13 +190,18 @@</span><br><span> const char *osmo_lai_name(const struct osmo_location_area_id *lai)</span><br><span> {</span><br><span>      static char buf[32];</span><br><span style="color: hsl(0, 100%, 40%);">-    snprintf(buf, sizeof(buf), "%s-%u", osmo_plmn_name(&lai->plmn), lai->lac);</span><br><span style="color: hsl(0, 100%, 40%);">-  return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_lai_name_buf(buf, sizeof(buf), lai);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const char *_cgi_name(const struct osmo_cell_global_id *cgi, char *buf, size_t buflen)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MCC-MNC-LAC-CI as string, in caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] cgi  CGI to encode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(buf, buflen, "%s-%u", osmo_lai_name(&cgi->lai), cgi->cell_identity);</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(buf, buf_len, "%s-%u", osmo_lai_name(&cgi->lai), cgi->cell_identity);</span><br><span>   return buf;</span><br><span> }</span><br><span> </span><br><span>@@ -164,7 +212,7 @@</span><br><span> const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi)</span><br><span> {</span><br><span>  static char buf[32];</span><br><span style="color: hsl(0, 100%, 40%);">-    return _cgi_name(cgi, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_cgi_name_buf(buf, sizeof(buf), cgi);</span><br><span> }</span><br><span> </span><br><span> /*! Same as osmo_cgi_name(), but uses a different static buffer.</span><br><span>@@ -175,7 +223,7 @@</span><br><span> const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi)</span><br><span> {</span><br><span>        static char buf[32];</span><br><span style="color: hsl(0, 100%, 40%);">-    return _cgi_name(cgi, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_cgi_name_buf(buf, sizeof(buf), cgi);</span><br><span> }</span><br><span> </span><br><span> static void to_bcd(uint8_t *bcd, uint16_t val)</span><br><span>@@ -187,14 +235,31 @@</span><br><span>  bcd[0] = val % 10;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *osmo_gummei_name(const struct osmo_gummei *gummei)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return string representation of GUMMEI in caller-provided output buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf pointer to caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] gummei GUMMEI to be stringified</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     static char buf[32];</span><br><span style="color: hsl(0, 100%, 40%);">-    snprintf(buf, sizeof(buf), "%s-%04x-%02x", osmo_plmn_name(&gummei->plmn),</span><br><span style="color: hsl(120, 100%, 40%);">+    char plmn[16];</span><br><span style="color: hsl(120, 100%, 40%);">+        snprintf(buf, buf_len, "%s-%04x-%02x", osmo_plmn_name_buf(plmn, sizeof(plmn), &gummei->plmn),</span><br><span>                gummei->mme.group_id, gummei->mme.code);</span><br><span>      return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return string representation of GUMMEI in static output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] gummei GUMMEI to be stringified</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns pointer to static output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_gummei_name(const struct osmo_gummei *gummei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  static char buf[32];</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_gummei_name_buf(buf, sizeof(buf), gummei);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Convert MCC + MNC to BCD representation</span><br><span>  * \param[out] bcd_dst caller-allocated memory for output</span><br><span>  * \param[in] mcc Mobile Country Code</span><br><span>diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c</span><br><span>index 5dc30ad..a45d67b 100644</span><br><span>--- a/src/gsm/gsm48.c</span><br><span>+++ b/src/gsm/gsm48.c</span><br><span>@@ -182,6 +182,20 @@</span><br><span>    return get_value_string(rr_cause_names, cause);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return MCC-MNC-LAC-RAC as string, in a caller-provided output buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rai  RAI to encode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_rai_name_buf(char *buf, size_t buf_len, const struct gprs_ra_id *rai)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       snprintf(buf, buf_len, "%s-%s-%u-%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_mcc_name(rai->mcc), osmo_mnc_name(rai->mnc, rai->mnc_3_digits), rai->lac,</span><br><span style="color: hsl(120, 100%, 40%);">+            rai->rac);</span><br><span style="color: hsl(120, 100%, 40%);">+        return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Return MCC-MNC-LAC-RAC as string, in a static buffer.</span><br><span>  * \param[in] rai  RAI to encode.</span><br><span>  * \returns Static string buffer.</span><br><span>@@ -189,10 +203,7 @@</span><br><span> const char *osmo_rai_name(const struct gprs_ra_id *rai)</span><br><span> {</span><br><span>       static char buf[32];</span><br><span style="color: hsl(0, 100%, 40%);">-    snprintf(buf, sizeof(buf), "%s-%s-%u-%u",</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_mcc_name(rai->mcc), osmo_mnc_name(rai->mnc, rai->mnc_3_digits), rai->lac,</span><br><span style="color: hsl(0, 100%, 40%);">-              rai->rac);</span><br><span style="color: hsl(0, 100%, 40%);">-  return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_rai_name_buf(buf, sizeof(buf), rai);</span><br><span> }</span><br><span> </span><br><span> /* FIXME: convert to value_string */</span><br><span>@@ -433,14 +444,15 @@</span><br><span>    return get_value_string(mi_type_names, mi);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Return a human readable representation of a Mobile Identity in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a human readable representation of a Mobile Identity in caller-provided buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span>  * \param[in] mi  Mobile Identity buffer containing 3GPP TS 04.08 style MI type and data.</span><br><span>  * \param[in] mi_len  Length of mi.</span><br><span style="color: hsl(0, 100%, 40%);">- * \return A string like "IMSI-1234567", "TMSI-0x1234ABCD" or "unknown", "TMSI-invalid"...</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return buf</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_mi_name_buf(char *buf, size_t buf_len, const uint8_t *mi, uint8_t mi_len)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      static char mi_name[10 + GSM48_MI_SIZE + 1];</span><br><span>         uint8_t mi_type;</span><br><span>     uint32_t tmsi;</span><br><span>       char mi_string[GSM48_MI_SIZE];</span><br><span>@@ -452,8 +464,8 @@</span><br><span>                 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */</span><br><span>                 if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {</span><br><span>                        tmsi = osmo_load32be(&mi[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-                       snprintf(mi_name, sizeof(mi_name), "TMSI-0x%08" PRIX32, tmsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                        return mi_name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       snprintf(buf, buf_len, "TMSI-0x%08" PRIX32, tmsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return buf;</span><br><span>          }</span><br><span>            return "TMSI-invalid";</span><br><span> </span><br><span>@@ -461,14 +473,25 @@</span><br><span>         case GSM_MI_TYPE_IMEI:</span><br><span>       case GSM_MI_TYPE_IMEISV:</span><br><span>             osmo_bcd2str(mi_string, sizeof(mi_string), mi, 1, (mi_len * 2) - (mi[0] & GSM_MI_ODD ? 0 : 1), true);</span><br><span style="color: hsl(0, 100%, 40%);">-               snprintf(mi_name, sizeof(mi_name), "%s-%s", gsm48_mi_type_name(mi_type), mi_string);</span><br><span style="color: hsl(0, 100%, 40%);">-          return mi_name;</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(buf, buf_len, "%s-%s", gsm48_mi_type_name(mi_type), mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+            return buf;</span><br><span> </span><br><span>      default:</span><br><span>             return "unknown";</span><br><span>  }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a human readable representation of a Mobile Identity in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] mi  Mobile Identity buffer containing 3GPP TS 04.08 style MI type and data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] mi_len  Length of mi.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return A string like "IMSI-1234567", "TMSI-0x1234ABCD" or "unknown", "TMSI-invalid"...</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        static char mi_name[10 + GSM48_MI_SIZE + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_mi_name_buf(mi_name, sizeof(mi_name), mi, mi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Checks is particular message is cipherable in A/Gb mode according to</span><br><span>  *         3GPP TS 24.008 Â§ 4.7.1.2</span><br><span>  *  \param[in] hdr Message header</span><br><span>@@ -1050,16 +1073,17 @@</span><br><span>       { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Compose a string naming the message type for given protocol.</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Compose a string naming the message type for given protocol, in a caller-provided buffer.</span><br><span>  * If the message type string is known, return the message type name, otherwise</span><br><span>  * return "<protocol discriminator name>:<message type in hex>".</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allcated output string buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len size of buf in bytes</span><br><span>  * \param[in] pdisc protocol discriminator like GSM48_PDISC_MM</span><br><span>  * \param[in] msg_type message type like GSM48_MT_MM_LOC_UPD_REQUEST</span><br><span style="color: hsl(0, 100%, 40%);">- * \returns statically allocated string or string constant.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type)</span><br><span style="color: hsl(120, 100%, 40%);">+char *gsm48_pdisc_msgtype_name_buf(char *buf, size_t buf_len, uint8_t pdisc, uint8_t msg_type)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   static char namebuf[64];</span><br><span>     const struct value_string *msgt_names;</span><br><span> </span><br><span>   switch (pdisc) {</span><br><span>@@ -1081,11 +1105,23 @@</span><br><span>   }</span><br><span> </span><br><span>        if (msgt_names)</span><br><span style="color: hsl(0, 100%, 40%);">-         return get_value_string(msgt_names, msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, buf_len, "%s", get_value_string(msgt_names, msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(buf, buf_len, "%s:0x%02x", gsm48_pdisc_name(pdisc), msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+     return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      snprintf(namebuf, sizeof(namebuf), "%s:0x%02x",</span><br><span style="color: hsl(0, 100%, 40%);">-                gsm48_pdisc_name(pdisc), msg_type);</span><br><span style="color: hsl(0, 100%, 40%);">-    return namebuf;</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Compose a string naming the message type for given protocol, in a static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If the message type string is known, return the message type name, otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ * return "<protocol discriminator name>:<message type in hex>".</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] pdisc protocol discriminator like GSM48_PDISC_MM</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg_type message type like GSM48_MT_MM_LOC_UPD_REQUEST</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns statically allocated string or string constant.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      static char namebuf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+      return gsm48_pdisc_msgtype_name_buf(namebuf, sizeof(namebuf), pdisc, msg_type);</span><br><span> }</span><br><span> </span><br><span> const struct value_string gsm48_reject_value_names[] = {</span><br><span>@@ -1187,9 +1223,8 @@</span><br><span>  * \param[in] cm  Classmarks.</span><br><span>  * \returns A statically allocated string like "cm1{a5/1=supported} cm2{0x23= A5/2 A5/3} no-cm3"</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_gsm48_classmark_a5_name_buf(char *buf, size_t buf_len, const struct osmo_gsm48_classmark *cm)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        static char buf[128];</span><br><span>        char cm1[42] = "no-cm1";</span><br><span>   char cm2[42] = " no-cm2";</span><br><span>  char cm3[42] = " no-cm3";</span><br><span>@@ -1212,10 +1247,21 @@</span><br><span>                         cm->classmark3[0] & (1 << 2) ? " A5/6" : "",</span><br><span>                        cm->classmark3[0] & (1 << 3) ? " A5/7" : "");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     snprintf(buf, sizeof(buf), "%s%s%s", cm1, cm2, cm3);</span><br><span style="color: hsl(120, 100%, 40%);">+        snprintf(buf, buf_len, "%s%s%s", cm1, cm2, cm3);</span><br><span>   return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a string representation of A5 cipher algorithms indicated by Classmark 1, 2 and 3.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] cm  Classmarks.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A statically allocated string like "cm1{a5/1=supported} cm2{0x23= A5/2 A5/3} no-cm3"</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       static char buf[128];</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_gsm48_classmark_a5_name_buf(buf, sizeof(buf), cm);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Overwrite dst with the Classmark information present in src.</span><br><span>  * Add an new Classmark and overwrite in dst what src has to offer, but where src has no Classmark information, leave</span><br><span>  * dst unchanged. (For Classmark 2 and 3, dst will exactly match any non-zero Classmark length from src, hence may end</span><br><span>diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c</span><br><span>index c9c15d5..f34d9ea 100644</span><br><span>--- a/src/gsm/gsm_utils.c</span><br><span>+++ b/src/gsm/gsm_utils.c</span><br><span>@@ -886,16 +886,21 @@</span><br><span>        return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_dump_gsmtime(const struct gsm_time *tm)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       static char buf[64];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    snprintf(buf, sizeof(buf), "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,</span><br><span style="color: hsl(120, 100%, 40%);">+        snprintf(buf, buf_len, "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,</span><br><span>            tm->fn, tm->t1, tm->t2, tm->t3, (uint8_t)tm->fn%52);</span><br><span>         buf[sizeof(buf)-1] = '\0';</span><br><span>   return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_dump_gsmtime(const struct gsm_time *tm)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   static char buf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_dump_gsmtime_buf(buf, sizeof(buf), tm);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! append range1024 encoded data to bit vector</span><br><span>  *  \param[out] bv Caller-provided output bit-vector</span><br><span>  *  \param[in] r Input Range1024 sructure */</span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index 3fadc5a..a69fb60 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -9,6 +9,7 @@</span><br><span> abis_nm_chcomb4pchan;</span><br><span> abis_nm_debugp_foh;</span><br><span> abis_nm_dump_foh;</span><br><span style="color: hsl(120, 100%, 40%);">+abis_nm_dump_foh_buf;</span><br><span> abis_nm_event_type_name;</span><br><span> abis_nm_nack_cause_name;</span><br><span> abis_nm_nack_name;</span><br><span>@@ -225,6 +226,7 @@</span><br><span> gsm0808_permitted_speech_names;</span><br><span> gsm0808_chosen_enc_alg_names;</span><br><span> gsm0808_channel_type_name;</span><br><span style="color: hsl(120, 100%, 40%);">+gsm0808_channel_type_name_buf;</span><br><span> gsm0808_lcls_config_names;</span><br><span> gsm0808_lcls_control_names;</span><br><span> gsm0808_lcls_status_names;</span><br><span>@@ -250,7 +252,9 @@</span><br><span> osmo_dec_gcr;</span><br><span> osmo_gcr_eq;</span><br><span> osmo_gcr_dump;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_gcr_dump_buf;</span><br><span> osmo_lcls_dump;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_lcls_dump_buf;</span><br><span> </span><br><span> gsm0858_rsl_ul_meas_enc;</span><br><span> </span><br><span>@@ -345,6 +349,7 @@</span><br><span> gsm48_dtx_mode;</span><br><span> gsm48_mi_type_name;</span><br><span> osmo_mi_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_mi_name_buf;</span><br><span> gsm48_mcc_mnc_to_bcd;</span><br><span> gsm48_mcc_mnc_from_bcd;</span><br><span> gsm48_generate_lai2;</span><br><span>@@ -354,14 +359,21 @@</span><br><span> osmo_plmn_to_bcd;</span><br><span> osmo_plmn_from_bcd;</span><br><span> osmo_mcc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_mcc_name_buf;</span><br><span> osmo_mnc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_mnc_name_buf;</span><br><span> osmo_plmn_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_plmn_name_buf;</span><br><span> osmo_plmn_name2;</span><br><span> osmo_lai_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_lai_name_buf;</span><br><span> osmo_rai_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_rai_name_buf;</span><br><span> osmo_cgi_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_cgi_name_buf;</span><br><span> osmo_cgi_name2;</span><br><span> osmo_gummei_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_gummei_name_buf;</span><br><span> osmo_mnc_from_str;</span><br><span> osmo_mnc_cmp;</span><br><span> osmo_plmn_cmp;</span><br><span>@@ -378,6 +390,7 @@</span><br><span> gsm48_cc_msgtype_names;</span><br><span> gsm48_cc_cause_names;</span><br><span> gsm48_pdisc_msgtype_name;</span><br><span style="color: hsl(120, 100%, 40%);">+gsm48_pdisc_msgtype_name_buf;</span><br><span> gsm48_reject_value_names;</span><br><span> </span><br><span> gsm_7bit_decode;</span><br><span>@@ -403,6 +416,7 @@</span><br><span> gsm_get_octet_len;</span><br><span> gsm_gsmtime2fn;</span><br><span> osmo_dump_gsmtime;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_dump_gsmtime_buf;</span><br><span> </span><br><span> gsm_milenage;</span><br><span> gsm_septet_encode;</span><br><span>@@ -472,6 +486,7 @@</span><br><span> rsl_ccch_conf_to_bs_cc_chans;</span><br><span> rsl_ccch_conf_to_bs_ccch_sdcch_comb;</span><br><span> rsl_chan_nr_str;</span><br><span style="color: hsl(120, 100%, 40%);">+rsl_chan_nr_str_buf;</span><br><span> rsl_dec_chan_nr;</span><br><span> rsl_enc_chan_nr;</span><br><span> rsl_err_name;</span><br><span>@@ -533,7 +548,9 @@</span><br><span> ipa_send;</span><br><span> </span><br><span> osmo_apn_qualify;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_apn_qualify_buf;</span><br><span> osmo_apn_qualify_from_imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_apn_qualify_from_imsi_buf;</span><br><span> osmo_apn_to_str;</span><br><span> osmo_apn_from_str;</span><br><span> </span><br><span>@@ -592,6 +609,7 @@</span><br><span> osmo_gsm48_classmark2_is_r99;</span><br><span> osmo_gsm48_classmark_supports_a5;</span><br><span> osmo_gsm48_classmark_a5_name;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_gsm48_classmark_a5_name_buf;</span><br><span> osmo_gsm48_classmark_update;</span><br><span> </span><br><span> local: *;</span><br><span>diff --git a/src/gsm/rsl.c b/src/gsm/rsl.c</span><br><span>index e610ebf..7bc6002 100644</span><br><span>--- a/src/gsm/rsl.c</span><br><span>+++ b/src/gsm/rsl.c</span><br><span>@@ -215,33 +215,47 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Get human-readable string for RSL channel number */</span><br><span style="color: hsl(0, 100%, 40%);">-const char *rsl_chan_nr_str(uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Get human-readable string for RSL channel number, in caller-provided buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] buf caller-provided output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf_len size of buf in bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] chan_nr channel number to be stringified</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns buf with string</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *rsl_chan_nr_str_buf(char *buf, size_t buf_len, uint8_t chan_nr)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- static char str[20];</span><br><span>         int ts = chan_nr & 7;</span><br><span>    uint8_t cbits = chan_nr >> 3;</span><br><span> </span><br><span>      if (cbits == 0x01)</span><br><span style="color: hsl(0, 100%, 40%);">-              sprintf(str, "TCH/F on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(buf, buf_len, "TCH/F on TS%d", ts);</span><br><span>       else if ((cbits & 0x1e) == 0x02)</span><br><span style="color: hsl(0, 100%, 40%);">-            sprintf(str, "TCH/H(%u) on TS%d", cbits & 0x01, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+            snprintf(buf, buf_len, "TCH/H(%u) on TS%d", cbits & 0x01, ts);</span><br><span>         else if ((cbits & 0x1c) == 0x04)</span><br><span style="color: hsl(0, 100%, 40%);">-            sprintf(str, "SDCCH/4(%u) on TS%d", cbits & 0x03, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(buf, buf_len, "SDCCH/4(%u) on TS%d", cbits & 0x03, ts);</span><br><span>       else if ((cbits & 0x18) == 0x08)</span><br><span style="color: hsl(0, 100%, 40%);">-            sprintf(str, "SDCCH/8(%u) on TS%d", cbits & 0x07, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(buf, buf_len, "SDCCH/8(%u) on TS%d", cbits & 0x07, ts);</span><br><span>       else if (cbits == 0x10)</span><br><span style="color: hsl(0, 100%, 40%);">-         sprintf(str, "BCCH on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(buf, buf_len, "BCCH on TS%d", ts);</span><br><span>        else if (cbits == 0x11)</span><br><span style="color: hsl(0, 100%, 40%);">-         sprintf(str, "RACH on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(buf, buf_len, "RACH on TS%d", ts);</span><br><span>        else if (cbits == 0x12)</span><br><span style="color: hsl(0, 100%, 40%);">-         sprintf(str, "PCH/AGCH on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(buf, buf_len, "PCH/AGCH on TS%d", ts);</span><br><span>    else if (cbits == 0x18)</span><br><span style="color: hsl(0, 100%, 40%);">-         sprintf(str, "PDCH on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(buf, buf_len, "PDCH on TS%d", ts);</span><br><span>        else</span><br><span style="color: hsl(0, 100%, 40%);">-            sprintf(str, "UNKNOWN on TS%d", ts);</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, buf_len, "UNKNOWN on TS%d", ts);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        return str;</span><br><span style="color: hsl(120, 100%, 40%);">+        return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Get human-readable string for RSL channel number, in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] chan_nr channel number to be stringified</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns buf with string</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *rsl_chan_nr_str(uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       static char str[20];</span><br><span style="color: hsl(120, 100%, 40%);">+  return rsl_chan_nr_str_buf(str, sizeof(str), chan_nr);</span><br><span> }</span><br><span> </span><br><span> static const struct value_string rsl_err_vals[] = {</span><br><span>diff --git a/src/msgb.c b/src/msgb.c</span><br><span>index 3902f6e..b7596f6 100644</span><br><span>--- a/src/msgb.c</span><br><span>+++ b/src/msgb.c</span><br><span>@@ -392,13 +392,14 @@</span><br><span> }</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Return a (static) buffer containing a hexdump of the msg</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] msg message buffer</span><br><span style="color: hsl(0, 100%, 40%);">- * \returns a pointer to a static char array</span><br><span style="color: hsl(120, 100%, 40%);">+/*! fill user-provided buffer with hexdump of the msg</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-allocated buffer for output string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf_len length of buf</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg message buffer to be dumped</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-const char *msgb_hexdump(const struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+char *msgb_hexdump_buf(char *buf, size_t buf_len, const struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       static char buf[4100];</span><br><span>       int buf_offs = 0;</span><br><span>    int nchars;</span><br><span>  const unsigned char *start = msg->data;</span><br><span>@@ -421,32 +422,32 @@</span><br><span>           if (lxhs[i] > msg->tail)</span><br><span>                       continue;</span><br><span>            if (lxhs[i] < msg->data || lxhs[i] > msg->tail) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+                     nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                                          "(L%d=data%+" PRIdPTR ") ",</span><br><span>                                      i+1, lxhs[i] - msg->data);</span><br><span>                      buf_offs += nchars;</span><br><span>                  continue;</span><br><span>            }</span><br><span>            if (lxhs[i] < start) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+                     nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                                          "(L%d%+" PRIdPTR ") ", i+1,</span><br><span>                                      start - lxhs[i]);</span><br><span>                  buf_offs += nchars;</span><br><span>                  continue;</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+             nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                                  "%s[L%d]> ",</span><br><span>                            osmo_hexdump(start, lxhs[i] - start),</span><br><span>                                i+1);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (nchars < 0 || nchars + buf_offs >= sizeof(buf))</span><br><span style="color: hsl(120, 100%, 40%);">+             if (nchars < 0 || nchars + buf_offs >= buf_len)</span><br><span>                        return "ERROR";</span><br><span> </span><br><span>                buf_offs += nchars;</span><br><span>          start = lxhs[i];</span><br><span>     }</span><br><span style="color: hsl(0, 100%, 40%);">-       nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+     nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                          "%s", osmo_hexdump(start, msg->tail - start));</span><br><span style="color: hsl(0, 100%, 40%);">-   if (nchars < 0 || nchars + buf_offs >= sizeof(buf))</span><br><span style="color: hsl(120, 100%, 40%);">+     if (nchars < 0 || nchars + buf_offs >= buf_len)</span><br><span>                return "ERROR";</span><br><span> </span><br><span>        buf_offs += nchars;</span><br><span>@@ -456,17 +457,17 @@</span><br><span>                  continue;</span><br><span> </span><br><span>                if (lxhs[i] < msg->head || lxhs[i] > msg->head + msg->data_len) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+                     nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                                          "(L%d out of range) ", i+1);</span><br><span>             } else if (lxhs[i] <= msg->data + msg->data_len &&</span><br><span>                     lxhs[i] > msg->tail) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,</span><br><span style="color: hsl(120, 100%, 40%);">+                     nchars = snprintf(buf + buf_offs, buf_len - buf_offs,</span><br><span>                                          "(L%d=tail%+" PRIdPTR ") ",</span><br><span>                                      i+1, lxhs[i] - msg->tail);</span><br><span>              } else</span><br><span>                       continue;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (nchars < 0 || nchars + buf_offs >= sizeof(buf))</span><br><span style="color: hsl(120, 100%, 40%);">+             if (nchars < 0 || nchars + buf_offs >= buf_len)</span><br><span>                        return "ERROR";</span><br><span>            buf_offs += nchars;</span><br><span>  }</span><br><span>@@ -474,6 +475,15 @@</span><br><span>     return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a (static) buffer containing a hexdump of the msg</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg message buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns a pointer to a static char array</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *msgb_hexdump(const struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  static char buf[4100];</span><br><span style="color: hsl(120, 100%, 40%);">+        return msgb_hexdump_buf(buf, sizeof(buf), msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> /*! Print a string to the end of message buffer.</span><br><span>  * \param[in] msg message buffer</span><br><span>diff --git a/src/sim/core.c b/src/sim/core.c</span><br><span>index a78cecc..998e836 100644</span><br><span>--- a/src/sim/core.c</span><br><span>+++ b/src/sim/core.c</span><br><span>@@ -267,10 +267,8 @@</span><br><span>   return msg;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* FIXME: do we want to mark this as __thread? */</span><br><span style="color: hsl(0, 100%, 40%);">-static char sw_print_buf[256];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osim_print_sw_buf(char *buf, size_t buf_len, const struct osim_card_hdl *ch, uint16_t sw_in)</span><br><span> {</span><br><span>  const struct osim_card_sw *csw;</span><br><span> </span><br><span>@@ -283,25 +281,29 @@</span><br><span> </span><br><span>      switch (csw->type) {</span><br><span>      case SW_TYPE_STR:</span><br><span style="color: hsl(0, 100%, 40%);">-               snprintf(sw_print_buf, sizeof(sw_print_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                     "%04x (%s)", sw_in, csw->u.str);</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, buf_len, "%04x (%s)", sw_in, csw->u.str);</span><br><span>                 break;</span><br><span>       default:</span><br><span>             goto ret_def;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   sw_print_buf[sizeof(sw_print_buf)-1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  buf[buf_len-1] = '\0';</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      return sw_print_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  return buf;</span><br><span> </span><br><span> ret_def:</span><br><span style="color: hsl(0, 100%, 40%);">-     snprintf(sw_print_buf, sizeof(sw_print_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-             "%04x (Unknown)", sw_in);</span><br><span style="color: hsl(0, 100%, 40%);">-    sw_print_buf[sizeof(sw_print_buf)-1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  snprintf(buf, buf_len, "%04x (Unknown)", sw_in);</span><br><span style="color: hsl(120, 100%, 40%);">+    buf[buf_len-1] = '\0';</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      return sw_print_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  return buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: do we want to mark this as __thread? */</span><br><span style="color: hsl(120, 100%, 40%);">+     static char sw_print_buf[256];</span><br><span style="color: hsl(120, 100%, 40%);">+        return osim_print_sw_buf(sw_print_buf, sizeof(sw_print_buf), ch, sw_in);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> const struct osim_card_sw *osim_find_sw(const struct osim_card_profile *cp,</span><br><span>                                       uint16_t sw_in)</span><br><span>diff --git a/src/utils.c b/src/utils.c</span><br><span>index 2d5bcb0..ec22cee 100644</span><br><span>--- a/src/utils.c</span><br><span>+++ b/src/utils.c</span><br><span>@@ -273,17 +273,20 @@</span><br><span>     return out_buf;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Convert a sequence of unpacked bits to ASCII string</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert a sequence of unpacked bits to ASCII string, in user-supplied buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf caller-provided output string buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf_len size of buf in bytes</span><br><span>  * \param[in] bits A sequence of unpacked bits</span><br><span>  * \param[in] len Length of bits</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string representation in static buffer.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len)</span><br><span> {</span><br><span>       int i;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      if (len > sizeof(hexd_buff)-1)</span><br><span style="color: hsl(0, 100%, 40%);">-               len = sizeof(hexd_buff)-1;</span><br><span style="color: hsl(0, 100%, 40%);">-      memset(hexd_buff, 0, sizeof(hexd_buff));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (len > buf_len-1)</span><br><span style="color: hsl(120, 100%, 40%);">+               len = buf_len-1;</span><br><span style="color: hsl(120, 100%, 40%);">+      memset(buf, 0, buf_len);</span><br><span> </span><br><span>         for (i = 0; i < len; i++) {</span><br><span>               char outch;</span><br><span>@@ -301,10 +304,20 @@</span><br><span>                  outch = 'E';</span><br><span>                         break;</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-               hexd_buff[i] = outch;</span><br><span style="color: hsl(120, 100%, 40%);">+         buf[i] = outch;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-       hexd_buff[sizeof(hexd_buff)-1] = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     return hexd_buff;</span><br><span style="color: hsl(120, 100%, 40%);">+     buf[buf_len-1] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert a sequence of unpacked bits to ASCII string, in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bits A sequence of unpacked bits</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len Length of bits</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string representation in static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_ubit_dump(hexd_buff, sizeof(hexd_buff), bits, len);</span><br><span> }</span><br><span> </span><br><span> /*! Convert binary sequence to hexadecimal ASCII string</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13310">change 13310</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13310"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ibf85f79e93244f53b2684ff6f1095c5b41203e05 </div>
<div style="display:none"> Gerrit-Change-Number: 13310 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>