diff --git a/src/host/layer23/include/osmocom/bb/common/l1ctl.h b/src/host/layer23/include/osmocom/bb/common/l1ctl.h index 5b20506ff..25bc6e8e3 100644 --- a/src/host/layer23/include/osmocom/bb/common/l1ctl.h +++ b/src/host/layer23/include/osmocom/bb/common/l1ctl.h @@ -75,4 +75,16 @@ int l1ctl_ph_prim_cb(struct osmo_prim_hdr *oph, void *ctx); /* Transmit L1CTL_NEIGH_PM_REQ */ int l1ctl_tx_neigh_pm_req(struct osmocom_ms *ms, int num, uint16_t *arfcn); +/* Transmit L1CTL_GPRS_UL_BLOCK_REQ */ +int l1ctl_tx_gprs_ul_block_req(struct osmocom_ms *ms, uint32_t fn, uint8_t tn, + const uint8_t *data, size_t data_len); + +/* Transmit L1CTL_GPRS_UL_TBF_CFG_REQ */ +int l1ctl_tx_gprs_ul_tbf_cfg_req(struct osmocom_ms *ms, uint8_t tbf_ref, + uint8_t slotmask); + +/* Transmit L1CTL_GPRS_DL_TBF_CFG_REQ */ +int l1ctl_tx_gprs_dl_tbf_cfg_req(struct osmocom_ms *ms, uint8_t tbf_ref, + uint8_t slotmask, uint8_t dl_tfi); + #endif diff --git a/src/host/layer23/include/osmocom/bb/common/ms.h b/src/host/layer23/include/osmocom/bb/common/ms.h index 30bb5146d..e4888a755 100644 --- a/src/host/layer23/include/osmocom/bb/common/ms.h +++ b/src/host/layer23/include/osmocom/bb/common/ms.h @@ -36,6 +36,7 @@ struct osmosap_entity { struct osmol1_entity { int (*l1_traffic_ind)(struct osmocom_ms *ms, struct msgb *msg); + int (*l1_gprs_dl_block_ind)(struct osmocom_ms *ms, struct msgb *msg); }; struct osmomncc_entity { diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c index 34051fdbb..8e55b7b5b 100644 --- a/src/host/layer23/src/common/l1ctl.c +++ b/src/host/layer23/src/common/l1ctl.c @@ -978,6 +978,107 @@ static int rx_l1_neigh_pm_ind(struct osmocom_ms *ms, struct msgb *msg) return 0; } +/* Receive L1CTL_GPRS_DL_BLOCK_IND */ +static int rx_l1_gprs_dl_block_ind(struct osmocom_ms *ms, struct msgb *msg) +{ + const struct l1ctl_gprs_dl_block_ind *ind = (void *)msg->l1h; + + if (msgb_l1len(msg) < sizeof(*ind)) { + LOGP(DL1C, LOGL_ERROR, + "Rx malformed GPRS DL BLOCK.ind (len=%u < %zu)\n", + msgb_l1len(msg), sizeof(*ind)); + return -EINVAL; + } + if (OSMO_UNLIKELY(ind->hdr.tn >= 8)) { + LOGP(DL1C, LOGL_ERROR, + "Rx malformed GPRS DL BLOCK.ind (tn=%u)\n", + ind->hdr.tn); + return -EINVAL; + } + + msg->l2h = (void *)&ind->data[0]; + + DEBUGP(DL1C, "Rx GPRS DL block (fn=%u, tn=%u, len=%u): %s\n", + ntohl(ind->hdr.fn), ind->hdr.tn, msgb_l2len(msg), msgb_hexdump_l2(msg)); + + /* distribute or drop */ + if (ms->l1_entity.l1_gprs_dl_block_ind) + return ms->l1_entity.l1_gprs_dl_block_ind(ms, msg); + + msgb_free(msg); + return 0; +} + +/* Transmit L1CTL_GPRS_UL_BLOCK_REQ */ +int l1ctl_tx_gprs_ul_block_req(struct osmocom_ms *ms, uint32_t fn, uint8_t tn, + const uint8_t *data, size_t data_len) +{ + struct l1ctl_gprs_ul_block_req *req; + struct msgb *msg; + + msg = osmo_l1_alloc(L1CTL_GPRS_UL_BLOCK_REQ); + if (!msg) + return -ENOMEM; + + req = (void *)msgb_put(msg, sizeof(*req)); + req->hdr.fn = htonl(fn); + req->hdr.tn = tn; + if (data_len > 0) + memcpy(msgb_put(msg, data_len), data, data_len); + + DEBUGP(DL1C, "Tx GPRS UL block (fn=%u, tn=%u, len=%zu): %s\n", + fn, tn, data_len, osmo_hexdump(data, data_len)); + + return osmo_send_l1(ms, msg); +} + +/* Transmit L1CTL_GPRS_UL_TBF_CFG_REQ */ +int l1ctl_tx_gprs_ul_tbf_cfg_req(struct osmocom_ms *ms, uint8_t tbf_ref, + uint8_t slotmask) +{ + struct l1ctl_gprs_ul_tbf_cfg_req *req; + struct msgb *msg; + + msg = osmo_l1_alloc(L1CTL_GPRS_UL_TBF_CFG_REQ); + if (!msg) + return -ENOMEM; + + req = (void *)msgb_put(msg, sizeof(*req)); + *req = (struct l1ctl_gprs_ul_tbf_cfg_req) { + .tbf_ref = tbf_ref, + .slotmask = slotmask, + }; + + DEBUGP(DL1C, "Tx GPRS UL TBF CFG (tbf_ref=%u, slotmask=0x%02x)\n", + tbf_ref, slotmask); + + return osmo_send_l1(ms, msg); +} + +/* Transmit L1CTL_GPRS_DL_TBF_CFG_REQ */ +int l1ctl_tx_gprs_dl_tbf_cfg_req(struct osmocom_ms *ms, uint8_t tbf_ref, + uint8_t slotmask, uint8_t dl_tfi) +{ + struct l1ctl_gprs_dl_tbf_cfg_req *req; + struct msgb *msg; + + msg = osmo_l1_alloc(L1CTL_GPRS_DL_TBF_CFG_REQ); + if (!msg) + return -ENOMEM; + + req = (void *)msgb_put(msg, sizeof(*req)); + *req = (struct l1ctl_gprs_dl_tbf_cfg_req) { + .tbf_ref = tbf_ref, + .slotmask = slotmask, + .dl_tfi = dl_tfi, + }; + + DEBUGP(DL1C, "Tx GPRS DL TBF CFG (tbf_ref=%u, slotmask=0x%02x, dl_tfi=%u)\n", + tbf_ref, slotmask, dl_tfi); + + return osmo_send_l1(ms, msg); +} + /* Receive incoming data from L1 using L1CTL format */ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) { @@ -1046,6 +1147,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) case L1CTL_TRAFFIC_CONF: msgb_free(msg); break; + case L1CTL_GPRS_DL_BLOCK_IND: + rc = rx_l1_gprs_dl_block_ind(ms, msg); + break; default: LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", hdr->msg_type); msgb_free(msg);