upqueue_avail = 0;
}
-int load_timer(struct lcr_timer *timer, void *instance, int index);
+static int load_timer(struct lcr_timer *timer, void *instance, int index);
/*
* constructor
*/
-PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Port(type, portname, settings)
+PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_settings *settings, struct interface *interface, int channel, int exclusive, int mode) : Port(type, portname, settings, interface)
{
p_m_mISDNport = mISDNport;
p_m_portnum = mISDNport->portnum;
_bchannel_configure(mISDNport, i);
state = B_STATE_ACTIVE;
b_port->p_m_load = 0;
+ b_port->update_load();
} else {
/* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
_bchannel_activate(mISDNport, i, 0, 0);
*/
void PmISDN::update_load(void)
{
- /* don't trigger load event if: */
- if (!p_tone_name[0] && !p_m_crypt_msg_loops && !p_m_inband_send_on && !(p_bridge && p_m_disable_dejitter && p_m_preload > 0))
- return;
-
/* don't trigger load event if event already active */
if (p_m_loadtimer.active)
return;
schedule_timer(&p_m_loadtimer, 0, 0); /* no delay the first time */
}
-int load_timer(struct lcr_timer *timer, void *instance, int index)
+static int load_timer(struct lcr_timer *timer, void *instance, int index)
{
class PmISDN *isdnport = (class PmISDN *)instance;
p_m_last_tv_msec = current_time.tv_usec/1000;
/* process only if we have samples and we are active */
- if (elapsed && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
+ if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE)
+ return;
+
+ if (elapsed) {
/* update load */
if (elapsed < p_m_load)
p_m_load -= elapsed;
}
}
- if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on || p_m_load) {
- schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125);
- }
+ schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125);
}
/* handle timeouts */
end_trace();
if (!p_m_dtmf)
return;
- message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
- message->param.dtmf = cont & DTMF_TONE_MASK;
- PDEBUG(DEBUG_PORT, "PmISDN(%s) PH_CONTROL INDICATION DTMF digit '%c'\n", p_name, message->param.dtmf);
- message_put(message);
+ if (p_type == PORT_TYPE_POTS_FXS_IN && p_state == PORT_STATE_IN_OVERLAP) {
+ class Pfxs *pfxs = (class Pfxs *)this;
+ if (!pfxs->p_m_fxs_allow_dtmf) {
+ PDEBUG(DEBUG_PORT, "PmISDN(%s) DTMF for FXS currently disabled\n", p_name);
+ return;
+ }
+ SCCAT(p_dialinginfo.id, cont & DTMF_TONE_MASK);
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
+ message->param.information.id[0] = cont & DTMF_TONE_MASK;
+ PDEBUG(DEBUG_PORT, "PmISDN(%s) PH_CONTROL INDICATION INFORMATION digit '%s'\n", p_name, message->param.information.id);
+ message_put(message);
+ } else {
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
+ message->param.dtmf = cont & DTMF_TONE_MASK;
+ PDEBUG(DEBUG_PORT, "PmISDN(%s) PH_CONTROL INDICATION DTMF digit '%c'\n", p_name, message->param.dtmf);
+ message_put(message);
+ }
return;
}
switch(cont) {
// printf(".");fflush(stdout);return;
if (p_record)
record(data, len, 1); // from up
+ if (p_tap)
+ tap(data, len, 1); // from up
return;
}
if (hh->prim != PH_DATA_IND && hh->prim != DL_DATA_IND) {
/* record data */
if (p_record)
record(data, len, 0); // from down
+ if (p_tap)
+ tap(data, len, 0); // from down
/* randomize and listen to crypt message if enabled */
if (p_m_crypt_listen) {
p_m_crypt_msg_current = 0; /* reset */
p_m_crypt_msg_loops = 6; /* enable */
update_rxoff();
- update_load();
#if 0
/* disable txmix, or we get corrupt data due to audio process */
if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
int tx_dejitter = 0;
/* call bridges in user space OR crypto OR recording */
- if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_m_inband_receive_on) {
+ if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_tap || p_m_inband_receive_on) {
/* rx IS required */
if (p_m_rxoff) {
/* turn on RX */
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
}
}
- /* recording */
- if (p_record) {
+ /* recording / tapping */
+ if (p_record || p_tap) {
/* txdata IS required */
if (!p_m_txdata) {
/* turn on RX */
tx_dejitter = 1;
if (p_m_tx_dejitter != tx_dejitter) {
p_m_tx_dejitter = tx_dejitter;
- PDEBUG(DEBUG_BCHANNEL, "we change dejitter mode to delay=%d.\n", p_m_tx_dejitter);
+ PDEBUG(DEBUG_BCHANNEL, "we change dejitter mode to %s.\n", (p_m_tx_dejitter) ? "on" : "off");
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TX_DEJITTER, p_m_tx_dejitter, "DSP-TX_DEJITTER", p_m_tx_dejitter);
return (port);
}
+/* handle frames from pots */
+static int pots_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, int i)
+{
+ struct mISDNport *mISDNport = (struct mISDNport *)instance;
+ unsigned char buffer[2048+MISDN_HEADER_LEN];
+ struct mISDNhead *hh = (struct mISDNhead *)buffer;
+ unsigned int cont;
+ int ret;
+
+ ret = recv(fd->fd, buffer, sizeof(buffer), 0);
+ if (ret < 0) {
+ PERROR("read error frame, errno %d\n", errno);
+ return 0;
+ }
+ if (ret < (int)MISDN_HEADER_LEN) {
+ PERROR("read short frame, got %d, expected %d\n", ret, (int)MISDN_HEADER_LEN);
+ return 0;
+ }
+ switch(hh->prim) {
+ case PH_CONTROL_IND:
+ cont = *((unsigned int *)(buffer + MISDN_HEADER_LEN));
+ /* l1-control is sent to LCR */
+ if (mISDNport->ntmode)
+ stack2manager_fxs(mISDNport, cont);
+ else
+ PERROR("FXO not supported!\n");
+ break;
+ case PH_ACTIVATE_REQ:
+ break;
+
+ default:
+ PERROR("child message not handled: prim(0x%x) socket(%d) msg->len(%d)\n", hh->prim, fd->fd, ret-MISDN_HEADER_LEN);
+ }
+
+ return 0;
+}
+
/*
* global function to add a new card (port)
*/
pri = 1;
nt = 1;
}
-#ifdef ISDN_P_FXS
- if (devinfo.Dprotocols & (1 << ISDN_P_FXS)) {
+#ifdef ISDN_P_FXS_POTS
+ if (devinfo.Dprotocols & (1 << ISDN_P_FXO_POTS)) {
pots = 1;
te = 1;
}
-#endif
-#ifdef ISDN_P_FXO
- if (devinfo.Dprotocols & (1 << ISDN_P_FXO)) {
+ if (devinfo.Dprotocols & (1 << ISDN_P_FXS_POTS)) {
pots = 1;
nt = 1;
}
#endif
if (force_nt && !nt) {
- PERROR_RUNTIME("Port %d does not support NT-mode\n", port);
+ if (!pots)
+ PERROR_RUNTIME("Port %d does not support NT-mode\n", port);
+ else
+ PERROR_RUNTIME("Port %d does not support FXS-mode\n", port);
return(NULL);
}
if (bri && pri) {
PERROR_RUNTIME("Port %d supports BRI and PRI?? What kind of controller is that?. (Can't use this!)\n", port);
return(NULL);
}
- if (pots && !bri && !pri) {
- PERROR_RUNTIME("Port %d supports POTS, LCR does not!\n", port);
- return(NULL);
- }
- if (!bri && !pri) {
- PERROR_RUNTIME("Port %d does not support BRI nor PRI!\n", port);
+ if (!bri && !pri && !pots) {
+ PERROR_RUNTIME("Port %d does not support BRI nor PRI nor POTS!\n", port);
return(NULL);
}
if (!nt && !te) {
/* if TE an NT is supported (and not forced to NT), turn off NT */
if (te && nt)
nt = 0;
+ if (pots && te) {
+ PERROR_RUNTIME("Port %d uses FXO-mode, but not supported by LCR!\n", port);
+ return(NULL);
+ }
/* check for double use of port */
if (nt) {
}
/* allocate ressources of port */
- protocol = (nt)?L3_PROTOCOL_DSS1_NET:L3_PROTOCOL_DSS1_USER;
- prop = (1 << MISDN_FLG_L2_CLEAN);
- if (ptp) // ptp forced
- prop |= (1 << MISDN_FLG_PTP);
- if (nt) // supports hold/retrieve on nt-mode
- prop |= (1 << MISDN_FLG_NET_HOLD);
- if (l1hold) // supports layer 1 hold
- prop |= (1 << MISDN_FLG_L1_HOLD);
- if (l2hold) // supports layer 2 hold
- prop |= (1 << MISDN_FLG_L2_HOLD);
- /* open layer 3 and init upqueue */
- /* queue must be initializes, because l3-thread may send messages during open_layer3() */
- mqueue_init(&mISDNport->upqueue);
- mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
- if (!mISDNport->ml3) {
- mqueue_purge(&mISDNport->upqueue);
- PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
- start_trace(port,
- ifport->interface,
- NULL,
- NULL,
- DIRECTION_NONE,
- CATEGORY_CH,
- 0,
- "PORT (open failed)");
- end_trace();
- mISDNport_close(mISDNport);
- return(NULL);
+ if (!pots) {
+ /* ISDN */
+ protocol = (nt)?L3_PROTOCOL_DSS1_NET:L3_PROTOCOL_DSS1_USER;
+ prop = (1 << MISDN_FLG_L2_CLEAN);
+ if (ptp) // ptp forced
+ prop |= (1 << MISDN_FLG_PTP);
+ if (nt) // supports hold/retrieve on nt-mode
+ prop |= (1 << MISDN_FLG_NET_HOLD);
+ if (l1hold) // supports layer 1 hold
+ prop |= (1 << MISDN_FLG_L1_HOLD);
+ if (l2hold) // supports layer 2 hold
+ prop |= (1 << MISDN_FLG_L2_HOLD);
+ /* open layer 3 and init upqueue */
+ /* queue must be initializes, because l3-thread may send messages during open_layer3() */
+ mqueue_init(&mISDNport->upqueue);
+ mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
+ if (!mISDNport->ml3) {
+ mqueue_purge(&mISDNport->upqueue);
+ PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
+ start_trace(port,
+ ifport->interface,
+ NULL,
+ NULL,
+ DIRECTION_NONE,
+ CATEGORY_CH,
+ 0,
+ "PORT (open failed)");
+ end_trace();
+ mISDNport_close(mISDNport);
+ return(NULL);
+ }
+ } else {
+#ifdef ISDN_P_FXS_POTS
+ /* POTS */
+ int sock, ret;
+ struct sockaddr_mISDN addr;
+ struct mISDNhead act;
+
+ /* open socket */
+ /* queue must be initializes, because even pots interfaces are checked at mISDN_upqueue loop */
+ mqueue_init(&mISDNport->upqueue);
+ sock = socket(PF_ISDN, SOCK_DGRAM, (nt) ? ISDN_P_FXS_POTS : ISDN_P_FXO_POTS);
+ if (sock < 0) {
+ PERROR_RUNTIME("Cannot open mISDN due to '%s'.\n", strerror(errno));
+ return NULL;
+ }
+ /* bind socket to dchannel */
+ addr.family = AF_ISDN;
+ addr.dev = port;
+ addr.channel = 0;
+ ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ PERROR_RUNTIME("Error: Failed to bind pots control channel\n");
+ start_trace(port,
+ ifport->interface,
+ NULL,
+ NULL,
+ DIRECTION_NONE,
+ CATEGORY_CH,
+ 0,
+ "PORT (open failed)");
+ end_trace();
+ return(NULL);
+ }
+ act.prim = PH_ACTIVATE_REQ;
+ act.id = 0;
+ ret = sendto(sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
+ if (ret <= 0)
+ PERROR("Failed to send to socket %d\n", sock);
+ mISDNport->pots_sock.fd = sock;
+ register_fd(&mISDNport->pots_sock, LCR_FD_READ, pots_sock_callback, mISDNport, i);
+#endif
}
SCPY(mISDNport->name, devinfo.name);
mISDNport->b_num = devinfo.nrbchan;
mISDNport->portnum = port;
mISDNport->ntmode = nt;
+ mISDNport->pots = pots;
mISDNport->tespecial = ifport->tespecial;
mISDNport->pri = pri;
mISDNport->ptp = ptp;
}
/* if ptp, pull up the link */
- if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+ if (!pots && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
add_trace("tei", NULL, "%d", 0);
schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
}
- /* for nt-mode ptmp the link is always up */
- if (mISDNport->ntmode && !mISDNport->ptp)
+ /* for POTS or nt-mode ptmp the link is always up */
+ if (pots || (mISDNport->ntmode && !mISDNport->ptp))
mISDNport->l2link = 1;
PDEBUG(DEBUG_BCHANNEL, "using 'mISDN_dsp.o' module\n");
CATEGORY_CH,
0,
"PORT (open)");
- add_trace("mode", NULL, (mISDNport->ntmode)?"network":"terminal");
+ if (!pots)
+ add_trace("mode", NULL, (mISDNport->ntmode)?"network":"terminal");
+ else
+ add_trace("mode", NULL, (mISDNport->ntmode)?"FXS":"FXO");
add_trace("channels", NULL, "%d", mISDNport->b_num);
if (mISDNport->ss5)
add_trace("ccitt#5", NULL, "enabled");
close_layer3(mISDNport->ml3);
}
+ /* close layer 1, if open */
+ if (mISDNport->pots_sock.fd) {
+ unregister_fd(&mISDNport->pots_sock);
+ close(mISDNport->pots_sock.fd);
+ }
+
/* purge upqueue */
mqueue_purge(&mISDNport->upqueue);
if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE)
return -EINVAL;
- /* run load-timer when bridged and dejitter is disabled */
- if (!p_m_loadtimer.active && p_m_disable_dejitter && p_m_preload > 0)
- update_load();
-
/* check if high priority tones exist
* ignore data in this case
*/
{
PDEBUG(DEBUG_PORT, "turning inband signalling send on.\n");
p_m_inband_send_on = 1;
- /* trigger inband transmit */
- update_load();
}
void PmISDN::inband_send_off(void)