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 int rcv_rll(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); int msg_type = rllh->c.msg_type; if (msg_type == RSL_MT_UNIT_DATA_IND) { unit_data_ind(ms, msg); } else LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n"); msgb_free(msg); 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; }
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; }
static int rcv_cch(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_cchan_hdr *ch = msgb_l2(msg); int msg_type = ch->c.msg_type; int rc; LOGP(DRSL, LOGL_INFO, "Received '%s' from layer1\n", rsl_msg_name(msg_type)); if (state == SCAN_STATE_RACH && msg_type == RSL_MT_CHAN_CONF) { rc = chan_conf(ms, msg); msgb_free(msg); return rc; } LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n"); msgb_free(msg); return 0; }
static int rcv_rsl(struct msgb *msg, struct lapdm_entity *le, void *l3ctx) { struct osmocom_ms *ms = l3ctx; struct abis_rsl_common_hdr *rslh = msgb_l2(msg); int rc = 0; switch (rslh->msg_discr & 0xfe) { case ABIS_RSL_MDISC_RLL: rc = rcv_rll(ms, msg); break; default: LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n", rslh->msg_discr); msgb_free(msg); rc = -EINVAL; break; } return rc; }
/* Take a B4 format message from L1 and create RSLms UNIT DATA IND */ static int send_rslms_rll_l3_ui(struct lapdm_msg_ctx *mctx, struct msgb *msg) { uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg); struct abis_rsl_rll_hdr *rllh; /* Add the RSL + RLL header */ msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); msgb_push(msg, 2 + 2); rsl_rll_push_hdr(msg, RSL_MT_UNIT_DATA_IND, mctx->chan_nr, mctx->link_id, 1); rllh = (struct abis_rsl_rll_hdr *)msgb_l2(msg); rllh->data[0] = RSL_IE_TIMING_ADVANCE; rllh->data[1] = mctx->ta_ind; rllh->data[2] = RSL_IE_MS_POWER; rllh->data[3] = mctx->tx_power_ind; return rslms_sendmsg(msg, mctx->dl->entity); }
/* input function that L2 calls when sending messages up to L3 */ static int layer3_from_layer2(struct msgb *msg, struct osmocom_ms *ms) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg); int rc = 0; switch (rslh->msg_discr & 0xfe) { case ABIS_RSL_MDISC_RLL: rc = rslms_rx_rll(msg, ms); break; default: /* FIXME: implement this */ LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n", rslh->msg_discr); msgb_free(msg); rc = -EINVAL; break; } 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); 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_rll(struct msgb *msg, struct osmocom_ms *ms) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); int rc = 0; switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: DEBUGP(DRSL, "RSLms DATA IND\n"); /* FIXME: implement this */ break; case RSL_MT_UNIT_DATA_IND: rc = rslms_rx_udata_ind(msg, ms); break; case RSL_MT_EST_IND: DEBUGP(DRSL, "RSLms EST IND\n"); /* FIXME: implement this */ break; case RSL_MT_EST_CONF: DEBUGP(DRSL, "RSLms EST CONF\n"); /* FIXME: implement this */ break; case RSL_MT_REL_CONF: DEBUGP(DRSL, "RSLms REL CONF\n"); /* FIXME: implement this */ break; case RSL_MT_ERROR_IND: DEBUGP(DRSL, "RSLms ERR IND\n"); /* FIXME: implement this */ break; default: LOGP(DRSL, LOGL_NOTICE, "unknown RSLms message type " "0x%02x\n", rllh->c.msg_type); rc = -EINVAL; break; } msgb_free(msg); 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 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; }
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; }
static int handle_ts1_read(struct osmo_fd *bfd) { struct e1inp_line *line = bfd->data; struct misdn_line *mline = line->driver_data; unsigned int ts_nr = bfd->priv_nr; struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; struct e1inp_sign_link *link; struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "mISDN TS1"); struct sockaddr_mISDN l2addr; struct mISDNhead *hh; socklen_t alen; int ret; if (!msg) return -ENOMEM; hh = (struct mISDNhead *) msg->data; alen = sizeof(l2addr); ret = recvfrom(bfd->fd, msg->data, 300, 0, (struct sockaddr *) &l2addr, &alen); if (ret < 0) { fprintf(stderr, "recvfrom error %s\n", strerror(errno)); msgb_free(msg); return ret; } if (alen != sizeof(l2addr)) { fprintf(stderr, "%s error len\n", __func__); msgb_free(msg); return -EINVAL; } msgb_put(msg, ret); DEBUGP(DLMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n", alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei); DEBUGP(DLMI, "<= 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 DL_INFORMATION_IND: /* mISDN tells us which channel number is allocated for this * tuple of (SAPI, TEI). */ DEBUGP(DLMI, "DL_INFORMATION_IND: use channel(%d) sapi(%d) tei(%d) for now\n", l2addr.channel, l2addr.sapi, l2addr.tei); link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi); if (!link) { DEBUGPC(DLMI, "mISDN message for unknown sign_link\n"); msgb_free(msg); return -EINVAL; } /* save the channel number in the driver private struct */ link->driver.misdn.channel = l2addr.channel; msgb_free(msg); break; case DL_ESTABLISH_IND: DEBUGP(DLMI, "DL_ESTABLISH_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); /* For some strange reason, sometimes the DL_INFORMATION_IND tells * us the wrong channel, and we only get the real channel number * during the DL_ESTABLISH_IND */ link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi); if (!link) { DEBUGPC(DLMI, "mISDN message for unknown sign_link\n"); msgb_free(msg); return -EINVAL; } /* save the channel number in the driver private struct */ link->driver.misdn.channel = l2addr.channel; ret = e1inp_event(e1i_ts, S_L_INP_TEI_UP, l2addr.tei, l2addr.sapi); msgb_free(msg); break; case DL_RELEASE_IND: DEBUGP(DLMI, "DL_RELEASE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); ret = e1inp_event(e1i_ts, S_L_INP_TEI_DN, l2addr.tei, l2addr.sapi); msgb_free(msg); break; case DL_DATA_IND: case DL_UNITDATA_IND: msg->l2h = msg->data + MISDN_HEADER_LEN; DEBUGP(DLMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN)); if (mline->use_userspace_lapd) { LOGP(DLMI, LOGL_ERROR, "DL_DATA_IND but userspace LAPD ?!?\n"); msgb_free(msg); return -EIO; } ret = e1inp_rx_ts(e1i_ts, msg, l2addr.tei, l2addr.sapi); break; case PH_ACTIVATE_IND: DEBUGP(DLMI, "PH_ACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); msgb_free(msg); break; case PH_DEACTIVATE_IND: DEBUGP(DLMI, "PH_DEACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); msgb_free(msg); break; case PH_DATA_IND: if (!mline->use_userspace_lapd) { LOGP(DLMI, LOGL_ERROR, "PH_DATA_IND but kernel LAPD ?!?\n"); return -EIO; } /* remove the Misdn Header */ msgb_pull(msg, MISDN_HEADER_LEN); /* hand into the LAPD code */ DEBUGP(DLMI, "RX: %s\n", osmo_hexdump(msg->data, msg->len)); ret = e1inp_rx_ts_lapd(e1i_ts, msg); break; default: msgb_free(msg); break; } return ret; }
static int handle_ts1_read(struct bsc_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 msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "mISDN TS1"); struct sockaddr_mISDN l2addr; struct mISDNhead *hh; socklen_t alen; int ret; if (!msg) return -ENOMEM; hh = (struct mISDNhead *) msg->data; alen = sizeof(l2addr); ret = recvfrom(bfd->fd, msg->data, 300, 0, (struct sockaddr *) &l2addr, &alen); if (ret < 0) { fprintf(stderr, "recvfrom error %s\n", strerror(errno)); return ret; } if (alen != sizeof(l2addr)) { fprintf(stderr, "%s error len\n", __func__); return -EINVAL; } msgb_put(msg, ret); DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n", alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei); DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x): %s\n", ret, hh->prim, hh->id, get_prim_name(hh->prim)); switch (hh->prim) { case DL_INFORMATION_IND: /* mISDN tells us which channel number is allocated for this * tuple of (SAPI, TEI). */ DEBUGP(DMI, "DL_INFORMATION_IND: use channel(%d) sapi(%d) tei(%d) for now\n", l2addr.channel, l2addr.sapi, l2addr.tei); link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi); if (!link) { DEBUGPC(DMI, "mISDN message for unknown sign_link\n"); msgb_free(msg); return -EINVAL; } /* save the channel number in the driver private struct */ link->driver.misdn.channel = l2addr.channel; break; case DL_ESTABLISH_IND: DEBUGP(DMI, "DL_ESTABLISH_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); ret = e1inp_event(e1i_ts, EVT_E1_TEI_UP, l2addr.tei, l2addr.sapi); break; case DL_RELEASE_IND: DEBUGP(DMI, "DL_RELEASE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); ret = e1inp_event(e1i_ts, EVT_E1_TEI_DN, l2addr.tei, l2addr.sapi); break; case DL_DATA_IND: case DL_UNITDATA_IND: msg->l2h = msg->data + MISDN_HEADER_LEN; DEBUGP(DMI, "RX: %s\n", hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN)); ret = e1inp_rx_ts(e1i_ts, msg, l2addr.tei, l2addr.sapi); break; case PH_ACTIVATE_IND: DEBUGP(DMI, "PH_ACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); break; case PH_DEACTIVATE_IND: DEBUGP(DMI, "PH_DEACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n", l2addr.channel, l2addr.sapi, l2addr.tei); break; default: break; } return ret; }
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; }