static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_request *req, struct msgb *input) { struct msgb *msg, *copy; struct ipac_msgt_sccp_state *state; struct bsc_nat_ussd_con *ussd; uint16_t lac, ci; if (!con->bsc->nat->ussd_con) return -1; msg = msgb_alloc_headroom(4096, 128, "forward ussd"); if (!msg) { LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); return -1; } copy = msgb_alloc_headroom(4096, 128, "forward bts"); if (!copy) { LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); msgb_free(msg); return -1; } copy->l2h = msgb_put(copy, msgb_l2len(input)); memcpy(copy->l2h, input->l2h, msgb_l2len(input)); msg->l2h = msgb_put(msg, 1); msg->l2h[0] = IPAC_MSGT_SCCP_OLD; /* fill out the data */ state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state)); state->trans_id = req->transaction_id; state->invoke_id = req->invoke_id; memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref)); memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref)); memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi)); /* add additional tag/values */ lac = htons(con->lac); ci = htons(con->ci); msgb_tv_fixed_put(msg, USSD_LAC_IE, sizeof(lac), (const uint8_t *) &lac); msgb_tv_fixed_put(msg, USSD_CI_IE, sizeof(ci), (const uint8_t *) &ci); ussd = con->bsc->nat->ussd_con; bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS); bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); return 0; }
/* * handle incoming messages: * - this can be a command (four letters, space, transaction id) * - or a response (three numbers, space, transaction id) */ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg) { int code; struct msgb *resp = NULL; if (msgb_l2len(msg) < 4) { LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len); return NULL; } /* attempt to treat it as a response */ if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) { LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code); } else { int i, handled = 0; msg->l3h = &msg->l2h[4]; for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) { handled = 1; resp = mgcp_requests[i].handle_request(cfg, msg); break; } if (!handled) { LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]); } } return resp; }
void ipa_msg_push_header(struct msgb *msg, uint8_t proto) { struct ipaccess_head *hh; msg->l2h = msg->data; hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); hh->proto = proto; hh->len = htons(msgb_l2len(msg)); }
static int send(struct msgb *in_msg, struct lapdm_channel *chan) { struct osmo_phsap_prim pp; struct msgb *msg; int rc; msg = msgb_alloc_headroom(128, 64, "PH-DATA.ind"); osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_INDICATION, msg); /* copy over actual MAC block */ msg->l2h = msgb_put(msg, msgb_l2len(in_msg)); memcpy(msg->l2h, in_msg->l2h, msgb_l2len(in_msg)); /* LAPDm requires those... */ pp.u.data.chan_nr = 0; pp.u.data.link_id = 0; /* feed into the LAPDm code of libosmogsm */ rc = lapdm_phsap_up(&pp.oph, &chan->lapdm_dcch); ASSERT(rc == 0 || rc == -EBUSY); return 0; }
static struct msgb *create_mm_id_req(void) { struct msgb *msg; msg = msgb_from_array(mm, sizeof(mm)); msg->l2h = msg->data + 3; ASSERT(msgb_l2len(msg) == 12); msg->l3h = msg->l2h + 6; ASSERT(msgb_l3len(msg) == 6); return msg; }
static int loader_read_cb(struct osmo_fd *fd, unsigned int flags) { struct msgb *msg; uint16_t len; int rc; msg = msgb_alloc(MSGB_MAX, "loader"); if (!msg) { fprintf(stderr, "Failed to allocate msg.\n"); return -1; } rc = read(fd->fd, &len, sizeof(len)); if (rc < sizeof(len)) { fprintf(stderr, "Short read. Error.\n"); exit(2); } if (ntohs(len) > MSGB_MAX) { fprintf(stderr, "Length is too big: %u\n", ntohs(len)); msgb_free(msg); return -1; } /* blocking read for the poor... we can starve in here... */ msg->l2h = msgb_put(msg, ntohs(len)); rc = read(fd->fd, msg->l2h, msgb_l2len(msg)); if (rc != msgb_l2len(msg)) { fprintf(stderr, "Can not read data: rc: %d errno: %d\n", rc, errno); msgb_free(msg); return -1; } loader_handle_reply(msg); msgb_free(msg); return 0; }
static int ussd_read_cb(struct osmo_fd *bfd) { struct bsc_nat_ussd_con *conn = bfd->data; struct msgb *msg = NULL; struct ipaccess_head *hh; int ret; ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg); if (ret <= 0) { if (ret == -EAGAIN) return 0; LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); bsc_nat_ussd_destroy(conn); return -1; } LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); hh = (struct ipaccess_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { struct tlv_parsed tvp; int ret; ret = ipa_ccm_idtag_parse(&tvp, (unsigned char *) msg->l2h + 2, msgb_l2len(msg) - 2); if (ret < 0) { LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " "message with malformed TLVs\n"); msgb_free(msg); return ret; } if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) ussd_auth_con(&tvp, conn); } else if (msg->l2h[0] == IPAC_MSGT_PING) { LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n"); ussd_pong(conn); } else { LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]); } msgb_free(msg); } else if (hh->proto == IPAC_PROTO_SCCP) { forward_sccp(conn->nat, msg); } else { msgb_free(msg); } return 0; }
/** * \brief Verify the structure of the OML message and set l3h * * This function verifies that the data in \param in msg is a proper * OML message. This code assumes that msg->l2h points to the * beginning of the OML message. In the successful case the msg->l3h * will be set and will point to the FOM header. The value is undefined * in all other cases. * * \param msg The message to analyze starting from msg->l2h. * \return In case the structure is correct a positive number will be * returned and msg->l3h will point to the FOM. The number is a * classification of the vendor type of the message. */ int msg_verify_oml_structure(struct msgb *msg) { struct abis_om_hdr *omh; if (msgb_l2len(msg) < sizeof(*omh)) { LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", msgb_l2len(msg), sizeof(*omh)); return -1; } omh = (struct abis_om_hdr *) msg->l2h; if (omh->mdisc != ABIS_OM_MDISC_FOM && omh->mdisc != ABIS_OM_MDISC_MANUF) { LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n", omh->mdisc); return -1; } if (omh->placement != ABIS_OM_PLACEMENT_ONLY) { LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n", omh->placement, ABIS_OM_PLACEMENT_ONLY); return -1; } if (omh->sequence != 0) { LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n", omh->sequence); return -1; } if (omh->mdisc == ABIS_OM_MDISC_MANUF) return check_manuf(msg, omh, msgb_l2len(msg) - sizeof(*omh)); msg->l3h = omh->data; if (check_fom(omh, msgb_l3len(msg)) != 0) return -1; return OML_MSG_TYPE_ETSI; }
static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line) { unsigned int ts_nr = bfd->priv_nr; struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; struct e1inp_sign_link *sign_link; struct msgb *msg; int ret; bfd->when &= ~BSC_FD_WRITE; /* get the next msg for this timeslot */ msg = e1inp_tx_ts(e1i_ts, &sign_link); if (!msg) { /* no message after tx delay timer */ return 0; } switch (sign_link->type) { case E1INP_SIGN_OML: #ifdef HSL_SR_1_0 /* HSL uses 0x81 for FOM for some reason */ if (msg->data[0] == ABIS_OM_MDISC_FOM) msg->data[0] = ABIS_OM_MDISC_FOM | 0x01; #endif break; case E1INP_SIGN_RSL: break; default: msgb_free(msg); bfd->when |= BSC_FD_WRITE; /* come back for more msg */ return -EINVAL; } msg->l2h = msg->data; ipaccess_prepend_header(msg, sign_link->tei); DEBUGP(DLMI, "TX %u: %s\n", ts_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg))); ret = send(bfd->fd, msg->data, msg->len, 0); msgb_free(msg); /* set tx delay timer for next event */ e1i_ts->sign.tx_timer.cb = timeout_ts1_write; e1i_ts->sign.tx_timer.data = e1i_ts; /* Reducing this might break the nanoBTS 900 init. */ osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay); return ret; }
static int forward_ussd_simple(struct sccp_connections *con, struct msgb *input) { struct msgb *copy; struct bsc_nat_ussd_con *ussd; if (!con->bsc->nat->ussd_con) return -1; copy = msgb_alloc_headroom(4096, 128, "forward bts"); if (!copy) { LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); return -1; } /* copy the data into the copy */ copy->l2h = msgb_put(copy, msgb_l2len(input)); memcpy(copy->l2h, input->l2h, msgb_l2len(input)); /* send it out */ ussd = con->bsc->nat->ussd_con; bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); return 0; }
/* Append padding (if required) */ static void lapdm_pad_msgb(struct msgb *msg, uint8_t n201) { int pad_len = n201 - msgb_l2len(msg); uint8_t *data; if (pad_len < 0) { LOGP(DLLAPD, LOGL_ERROR, "cannot pad message that is already too big!\n"); return; } data = msgb_put(msg, pad_len); memset(data, 0x2B, pad_len); }
void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, void *rx_cbdata) { struct msgb *msg = dp->oph.msg; switch (dp->oph.primitive) { case PRIM_DL_EST: DEBUGP(DLAPDTEST, "DL_EST: sapi(%d) tei(%d)\n", sapi, tei); break; case PRIM_DL_REL: DEBUGP(DLAPDTEST, "DL_REL: sapi(%d) tei(%d)\n", sapi, tei); break; case PRIM_DL_DATA: case PRIM_DL_UNIT_DATA: if (dp->oph.operation == PRIM_OP_INDICATION) { struct msgb *nmsg; char *ptr; int x; msg->l2h = msg->l3h; DEBUGP(DLAPDTEST, "RX: %s sapi=%d tei=%d\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)), sapi, tei); LOGP(DLAPDTEST, LOGL_DEBUG, "forwarding message\n"); nmsg = msgb_alloc(1024, "LAPD/test"); if (nmsg == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot alloc msg\n"); return; } ptr = (char *)msgb_put(nmsg, sizeof(int)); x = *((int *)msg->data); memcpy(ptr, &x, sizeof(int)); /* send the message back to client over LAPD */ lapd_transmit(lapd, tei, sapi, msg); return; } break; case PRIM_MDL_ERROR: DEBUGP(DLMI, "MDL_EERROR: cause(%d)\n", dp->u.error_ind.cause); break; default: printf("ERROR: unknown prim\n"); break; } }
static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg) { struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data; struct l1ctl_info_ul_tbf *udt = (struct l1ctl_info_ul_tbf *) l1h->data; enum osmo_gprs_cs osmo_cs; int block_size; msg->l2h = udt->payload; LOGPMS(DL1P, LOGL_ERROR, ms, "Rx L1CTL_DATA_TBF_REQ (tbf_id=%d, data=%s)\n", udt->tbf_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg))); if (udt->tbf_nr != 0) { LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n"); return; } if (ms->state.state != MS_STATE_TBF) { LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_TBF_REQ in state != TBF\n"); return; } osmo_cs = get_l1ctl_cs_by_osmo(udt->coding_scheme); if (osmo_cs < 0) { LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_RBF_REQ with invalid CS\n"); return; } block_size = osmo_gprs_ul_block_size_bytes(osmo_cs); if (msgb_l2len(msg) < block_size) { int pad_len = block_size - msgb_l2len(msg); uint8_t *pad = msgb_put(msg, pad_len); memset(pad, GSM_MACBLOCK_PADDING, pad_len); } msgb_enqueue(&ms->state.tbf.ul.tx_queue, msg); }
int chan_conf(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_cchan_hdr *ch = msgb_l2(msg); struct gsm48_req_ref *ref = (struct gsm48_req_ref *) (ch->data + 1); if (msgb_l2len(msg) < sizeof(*ch) + sizeof(*ref)) { LOGP(DRR, LOGL_ERROR, "CHAN_CNF too slort\n"); return -EINVAL; } rach_ref.valid = 1; rach_ref.t1 = ref->t1; rach_ref.t2 = ref->t2; rach_ref.t3 = ref->t3_low | (ref->t3_high << 3); return 0; }
/* FIXME: read from a B channel TS */ static int handle_tsX_read(struct osmo_fd *bfd) { struct e1inp_line *line = bfd->data; unsigned int ts_nr = bfd->priv_nr; struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE, "mISDN TSx"); struct mISDNhead *hh; int ret; if (!msg) return -ENOMEM; hh = (struct mISDNhead *) msg->data; ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0); if (ret < 0) { fprintf(stderr, "recvfrom error %s\n", strerror(errno)); return ret; } msgb_put(msg, ret); if (hh->prim != PH_CONTROL_IND) DEBUGP(DLMIB, "<= BCHAN len = %d, prim(0x%x) id(0x%x): %s\n", ret, hh->prim, hh->id, get_value_string(prim_names, hh->prim)); switch (hh->prim) { case PH_DATA_IND: msg->l2h = msg->data + MISDN_HEADER_LEN; DEBUGP(DLMIB, "BCHAN RX: %s\n", osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN)); /* the number of bytes received indicates that data to send */ handle_tsX_write(bfd, msgb_l2len(msg)); return e1inp_rx_ts(e1i_ts, msg, 0, 0); case PH_ACTIVATE_IND: case PH_DATA_CNF: break; default: break; } /* FIXME: why do we free signalling msgs in the caller, and trau not? */ msgb_free(msg); return ret; }
static int read_call_agent(struct osmo_fd *fd, unsigned int what) { struct sockaddr_in addr; socklen_t slen = sizeof(addr); struct msgb *msg; struct msgb *resp; int i; msg = (struct msgb *) fd->data; /* read one less so we can use it as a \0 */ int rc = recvfrom(cfg->gw_fd.bfd.fd, msg->data, msg->data_len - 1, 0, (struct sockaddr *) &addr, &slen); if (rc < 0) { perror("Gateway failed to read"); return -1; } else if (slen > sizeof(addr)) { fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n", (size_t) slen, sizeof(addr)); return -1; } /* handle message now */ msg->l2h = msgb_put(msg, rc); resp = mgcp_handle_message(cfg, msg); msgb_reset(msg); if (resp) { sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr)); msgb_free(resp); } if (reset_endpoints) { LOGP(DMGCP, LOGL_NOTICE, "Asked to reset endpoints: %d/%d\n", reset_trunk->trunk_nr, reset_trunk->trunk_type); reset_endpoints = 0; /* is checking in_addr.s_addr == INADDR_LOOPBACK making it more secure? */ for (i = 1; i < reset_trunk->number_endpoints; ++i) mgcp_release_endp(&reset_trunk->endpoints[i]); } return 0; }
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap, bool use_cache) { struct lc15l1_hdl *fl1 = trx_lc15l1_hdl(trx); struct msgb *l1msg = l1p_msgb_alloc(); struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0; uint8_t chan_nr, link_id; int len; if (!msg) { LOGP(DL1C, LOGL_FATAL, "PH-DATA.req without msg. " "Please fix!\n"); abort(); } len = msgb_l2len(msg); chan_nr = l1sap->u.data.chan_nr; link_id = l1sap->u.data.link_id; u32Fn = l1sap->u.data.fn; u8Tn = L1SAP_CHAN2TS(chan_nr); subCh = 0x1f; lchan = get_lchan_by_chan_nr(trx, chan_nr); if (L1SAP_IS_LINK_SACCH(link_id)) { sapi = GsmL1_Sapi_Sacch; if (!L1SAP_IS_CHAN_TCHF(chan_nr)) subCh = l1sap_chan2ss(chan_nr); } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { if (ts_is_pdch(&trx->ts[u8Tn])) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); } else { sapi = GsmL1_Sapi_Pdtch; u8BlockNbr = L1SAP_FN2MACBLOCK(u32Fn); } } else { sapi = GsmL1_Sapi_FacchF; u8BlockNbr = (u32Fn % 13) >> 2; } } else if (L1SAP_IS_CHAN_TCHH(chan_nr)) {
static int ussd_read_cb(struct osmo_fd *bfd) { int error; struct bsc_nat_ussd_con *conn = bfd->data; struct msgb *msg = ipaccess_read_msg(bfd, &error); struct ipaccess_head *hh; if (!msg) { LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); bsc_nat_ussd_destroy(conn); return -1; } LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); hh = (struct ipaccess_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { struct tlv_parsed tvp; int ret; ret = ipaccess_idtag_parse(&tvp, (unsigned char *) msg->l2h + 2, msgb_l2len(msg) - 2); if (ret < 0) { LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " "message with malformed TLVs\n"); return ret; } if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) ussd_auth_con(&tvp, conn); } msgb_free(msg); } else if (hh->proto == IPAC_PROTO_SCCP) { forward_sccp(conn->nat, msg); } else { msgb_free(msg); } return 0; }
static int unit_data_ind(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; uint8_t ch_type, ch_subch, ch_ts; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); if (state != SCAN_STATE_READ && state != SCAN_STATE_RACH) { return -EINVAL; } rsl_dec_chan_nr(rllh->chan_nr, &ch_type, &ch_subch, &ch_ts); switch (ch_type) { case RSL_CHAN_PCH_AGCH: return pch_agch(ms, msg); case RSL_CHAN_BCCH: return bcch(ms, msg); #if 0 case RSL_CHAN_Bm_ACCHs: case RSL_CHAN_Lm_ACCHs: case RSL_CHAN_SDCCH4_ACCH: case RSL_CHAN_SDCCH8_ACCH: return rx_acch(ms, msg); #endif default: LOGP(DRSL, LOGL_NOTICE, "RSL with chan_nr 0x%02x unknown.\n", rllh->chan_nr); return -EINVAL; } }
static int rslms_rx_udata_ind(struct msgb *msg, struct osmocom_ms *ms) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; int rc = 0; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); if (rllh->chan_nr == RSL_CHAN_PCH_AGCH) { rc = gsm48_rx_ccch(msg, ms); } else if (rllh->chan_nr == RSL_CHAN_BCCH) { rc = gsm48_rx_bcch(msg, ms); } return rc; }
static int unit_data_ind(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; uint8_t ch_type, ch_subch, ch_ts; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); rsl_dec_chan_nr(rllh->chan_nr, &ch_type, &ch_subch, &ch_ts); switch (ch_type) { case RSL_CHAN_BCCH: return bcch(ms, msg); default: return 0; } }
static int handle_ts1_read(struct osmo_fd *bfd) { struct e1inp_line *line = bfd->data; unsigned int ts_nr = bfd->priv_nr; struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; struct e1inp_sign_link *link; struct ipaccess_head *hh; struct msgb *msg; int ret = 0, error; error = ipa_msg_recv(bfd->fd, &msg); if (error < 0) return error; else if (error == 0) { hsl_drop(e1i_ts->line, bfd); LOGP(DLINP, LOGL_NOTICE, "Sign link vanished, dead socket\n"); return error; } DEBUGP(DLMI, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg))); hh = (struct ipaccess_head *) msg->data; if (hh->proto == HSL_PROTO_DEBUG) { LOGP(DLINP, LOGL_NOTICE, "HSL debug: %s\n", msg->data + sizeof(*hh)); msgb_free(msg); return ret; } /* HSL proprietary RSL extension */ if (hh->proto == 0 && (msg->l2h[0] == 0x81 || msg->l2h[0] == 0x80)) { ret = process_hsl_rsl(msg, line, bfd); if (ret < 0) { hsl_drop(e1i_ts->line, bfd); return ret; } else if (ret == 1) return 0; /* else: continue... */ } #ifdef HSL_SR_1_0 /* HSL for whatever reason chose to use 0x81 instead of 0x80 for FOM */ if (hh->proto == 255 && msg->l2h[0] == (ABIS_OM_MDISC_FOM | 0x01)) msg->l2h[0] = ABIS_OM_MDISC_FOM; #endif link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0); if (!link) { LOGP(DLINP, LOGL_ERROR, "no matching signalling link for " "hh->proto=0x%02x\n", hh->proto); msgb_free(msg); return -EIO; } msg->dst = link; /* XXX: better use e1inp_ts_rx? */ if (!e1i_ts->line->ops->sign_link) { LOGP(DLINP, LOGL_ERROR, "Fix your application, " "no action set for signalling messages.\n"); return -ENOENT; } e1i_ts->line->ops->sign_link(msg); return ret; }
int oap_client_handle(struct oap_client_state *state, const struct msgb *msg_rx, struct msgb **msg_tx) { uint8_t *data = msgb_l2(msg_rx); size_t data_len = msgb_l2len(msg_rx); struct osmo_oap_message oap_msg = {0}; int rc = 0; *msg_tx = NULL; OSMO_ASSERT(data); rc = osmo_oap_decode(&oap_msg, data, data_len); if (rc < 0) { LOGP(DLOAP, LOGL_ERROR, "Decoding OAP message failed with error '%s' (%d)\n", get_value_string(gsm48_gmm_cause_names, -rc), -rc); return -10; } switch (state->state) { case OAP_UNINITIALIZED: LOGP(DLOAP, LOGL_ERROR, "Received OAP message %d, but the OAP client is" " not initialized\n", oap_msg.message_type); return -ENOTCONN; case OAP_DISABLED: LOGP(DLOAP, LOGL_ERROR, "Received OAP message %d, but the OAP client is" " disabled\n", oap_msg.message_type); return -ENOTCONN; default: break; } switch (oap_msg.message_type) { case OAP_MSGT_CHALLENGE_REQUEST: return handle_challenge(state, &oap_msg, msg_tx); case OAP_MSGT_REGISTER_RESULT: /* successfully registered */ state->state = OAP_REGISTERED; break; case OAP_MSGT_REGISTER_ERROR: LOGP(DLOAP, LOGL_ERROR, "OAP registration failed\n"); state->state = OAP_INITIALIZED; if (state->registration_failures < 3) { state->registration_failures ++; return oap_client_register(state, msg_tx); } return -11; case OAP_MSGT_REGISTER_REQUEST: case OAP_MSGT_CHALLENGE_RESULT: LOGP(DLOAP, LOGL_ERROR, "Received invalid OAP message type for OAP client side: %d\n", (int)oap_msg.message_type); return -12; default: LOGP(DLOAP, LOGL_ERROR, "Unknown OAP message type: %d\n", (int)oap_msg.message_type); return -13; } return 0; }
int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg) { struct tlv_parsed tlvp; uint8_t msg_type = *(msg->l2h); struct ipaccess_unit unit_data = {}; char *unitid; int len, rc; /* shared CCM handling on both server and client */ rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd); switch (rc) { case -1: /* error in IPA CCM processing */ goto err; case 1: /* IPA CCM message that was handled in _base */ return 0; case 0: /* IPA CCM message that we need to handle */ break; default: /* Error */ LOGIPA(conn, LOGL_ERROR, "Unexpected return from " "ipa_ccm_rcvmsg_base: %d\n", rc); goto err; } switch (msg_type) { case IPAC_MSGT_ID_RESP: rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1); if (rc < 0) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with " "malformed TLVs\n"); goto err; } if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without " "unit ID\n"); goto err; } len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT); if (len < 1) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short" "unit ID\n"); goto err; } unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT); unitid[len-1] = '\0'; ipa_parse_unitid(unitid, &unit_data); /* FIXME */ rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data); if (rc < 0) goto err; break; default: LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n"); break; } return 0; err: /* in case of any error, we close the connection */ ipa_server_conn_destroy(conn); return -1; }
int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg) { struct msgb *msg = tmp_msg ? *tmp_msg : NULL; struct ipaccess_head *hh; int len, ret; int needed; if (msg == NULL) { msg = ipa_msg_alloc(0); if (msg == NULL) { ret = -ENOMEM; goto discard_msg; } msg->l1h = msg->tail; } if (msg->l2h == NULL) { /* first read our 3-byte header */ needed = sizeof(*hh) - msg->len; ret = recv(fd, msg->tail, needed, 0); if (ret == 0) goto discard_msg; if (ret < 0) { if (errno == EAGAIN || errno == EINTR) ret = 0; else { ret = -errno; goto discard_msg; } } msgb_put(msg, ret); if (ret < needed) { if (msg->len == 0) { ret = -EAGAIN; goto discard_msg; } LOGP(DLINP, LOGL_INFO, "Received part of IPA message header (%d/%zu)\n", msg->len, sizeof(*hh)); if (!tmp_msg) { ret = -EIO; goto discard_msg; } *tmp_msg = msg; return -EAGAIN; } msg->l2h = msg->tail; } hh = (struct ipaccess_head *) msg->data; /* then read the length as specified in header */ len = ntohs(hh->len); if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) { LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, " "received %d bytes\n", len, msg->len); ret = -EIO; goto discard_msg; } needed = len - msgb_l2len(msg); if (needed > 0) { ret = recv(fd, msg->tail, needed, 0); if (ret == 0) goto discard_msg; if (ret < 0) { if (errno == EAGAIN || errno == EINTR) ret = 0; else { ret = -errno; goto discard_msg; } } msgb_put(msg, ret); if (ret < needed) { LOGP(DLINP, LOGL_INFO, "Received part of IPA message L2 data (%d/%d)\n", msgb_l2len(msg), len); if (!tmp_msg) { ret = -EIO; goto discard_msg; } *tmp_msg = msg; return -EAGAIN; } } ret = msgb_l2len(msg); if (ret == 0) { LOGP(DLINP, LOGL_INFO, "Discarding IPA message without payload\n"); ret = -EAGAIN; goto discard_msg; } if (tmp_msg) *tmp_msg = NULL; *rmsg = msg; return ret; discard_msg: if (tmp_msg) *tmp_msg = NULL; msgb_free(msg); return ret; }