static int hsl_bts_process(struct ipa_client_conn *link, struct msgb *msg) { struct ipaccess_head *hh; struct e1inp_sign_link *sign_link; struct e1inp_ts *e1i_ts = &link->line->ts[0]; 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 0; } sign_link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0); if (!sign_link) { LOGP(DLINP, LOGL_ERROR, "no matching signalling link for " "hh->proto=0x%02x\n", hh->proto); msgb_free(msg); return -EIO; } msg->dst = sign_link; /* XXX better use e1inp_ts_rx? */ if (!link->line->ops->sign_link) { LOGP(DLINP, LOGL_ERROR, "Fix your application, " "no action set for signalling messages.\n"); return -ENOENT; } link->line->ops->sign_link(msg); 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; }