+ switch(state) {
+ case B_STATE_IDLE:
+ case B_STATE_ACTIVE:
+ /* bchannel is not exported */
+ break;
+
+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing because we must wait until bchanenl is active before deactivating */
+ break;
+
+ case B_STATE_REMOTE:
+ /* bchannel is exported, so we re-import */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_ACTIVATED:
+ timer = 0;
+ switch(state) {
+ case B_STATE_ACTIVATING:
+ if (b_port && !p_m_remote_id) {
+ /* bchannel is active and used by Port class, so we configure bchannel */
+ _bchannel_configure(mISDNport, i);
+ state = B_STATE_ACTIVE;
+ b_port->p_m_load = 0;
+ } else {
+ /* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
+ _bchannel_activate(mISDNport, i, 0);
+ state = B_STATE_DEACTIVATING;
+ timer = now_d + B_TIMER_DEACTIVATING;
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_EXPORTED:
+ switch(state) {
+ case B_STATE_EXPORTING:
+ if (b_port && p_m_remote_ref && p_m_remote_ref==mISDNport->b_remote_ref[i]) {
+ /* remote export done */
+ state = B_STATE_REMOTE;
+ } else {
+ /* bchannel is now exported, but we need bchannel back
+ * OR bchannel is not used anymore
+ * OR bchannel has been exported to an obsolete ref,
+ * so reimport, to later export to new remote */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_DROP:
+ if (!b_port)
+ FATAL("bchannel must be linked to a Port class\n");
+ switch(state) {
+ case B_STATE_IDLE:
+ /* bchannel is idle due to an error, so we do nothing */
+ break;
+
+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing because we must wait until bchanenl is active before deactivating */
+ break;
+
+ case B_STATE_ACTIVE:
+ /* bchannel is active, so we deactivate */
+ _bchannel_activate(mISDNport, i, 0);
+ state = B_STATE_DEACTIVATING;
+ timer = now_d + B_TIMER_DEACTIVATING;
+ break;
+
+ case B_STATE_REMOTE:
+ /* bchannel is exported, so we re-import */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_DEACTIVATED:
+ timer = 0;
+ switch(state) {
+ case B_STATE_IDLE:
+ /* ignore due to deactivation confirm after unloading */
+ break;
+
+ case B_STATE_DEACTIVATING:
+ _bchannel_destroy(mISDNport, i);
+ state = B_STATE_IDLE;
+ if (b_port) {
+ /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
+ if (p_m_remote_ref) {
+ message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "assign");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_EXPORTING;
+ mISDNport->b_remote_id[i] = p_m_remote_id;
+ mISDNport->b_remote_ref[i] = p_m_remote_ref;
+ } else {
+ if (_bchannel_create(mISDNport, i)) {
+ _bchannel_activate(mISDNport, i, 1);
+ state = B_STATE_ACTIVATING;
+ timer = now_d + B_TIMER_ACTIVATING;
+ }
+ }
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_IMPORTED:
+ switch(state) {
+ case B_STATE_IMPORTING:
+ state = B_STATE_IDLE;
+ mISDNport->b_remote_id[i] = 0;
+ mISDNport->b_remote_ref[i] = 0;
+ if (b_port) {
+ /* bchannel is now imported, but is requied by Port class, so we reactivate / export */
+ if (p_m_remote_ref) {
+ message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "assign");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_EXPORTING;
+ mISDNport->b_remote_id[i] = p_m_remote_id;
+ mISDNport->b_remote_ref[i] = p_m_remote_ref;
+ } else {
+ if (_bchannel_create(mISDNport, i)) {
+ _bchannel_activate(mISDNport, i, 1);
+ state = B_STATE_ACTIVATING;
+ timer = now_d + B_TIMER_ACTIVATING;
+ }
+ }
+ }
+ break;
+
+ default:
+ /* ignore, because not assigned */
+ ;
+ }
+ break;
+
+ case B_EVENT_TIMEOUT:
+ timer = 0;
+ switch(state) {
+ case B_STATE_IDLE:
+ /* ignore due to deactivation confirm after unloading */
+ break;
+
+ case B_STATE_ACTIVATING:
+ _bchannel_activate(mISDNport, i, 1);
+ timer = now_d + B_TIMER_ACTIVATING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ _bchannel_activate(mISDNport, i, 0);
+ timer = now_d + B_TIMER_DEACTIVATING;
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d, please correct.\n", event);
+ }
+
+ mISDNport->b_state[i] = state;
+ mISDNport->b_timer[i] = timer;
+}
+
+
+
+
+/*
+ * check for available channel and reserve+set it.
+ * give channel number or SEL_CHANNEL_ANY or SEL_CHANNEL_NO
+ * give exclusiv flag
+ * returns -(cause value) or x = channel x or 0 = no channel
+ * NOTE: no activation is done here
+ */
+int PmISDN::seize_bchannel(int channel, int exclusive)
+{
+ int i;
+
+ /* the channel is what we have */
+ if (p_m_b_channel == channel)
+ return(channel);
+
+ /* if channel already in use, release it */
+ if (p_m_b_channel)
+ drop_bchannel();
+
+ /* if CHANNEL_NO */
+ if (channel==CHANNEL_NO || channel==0)
+ return(0);
+
+ /* is channel in range ? */
+ if (channel==16
+ || (channel>p_m_mISDNport->b_num && channel<16)
+ || ((channel-1)>p_m_mISDNport->b_num && channel>16)) /* channel-1 because channel 16 is not counted */
+ return(-6); /* channel unacceptable */
+
+ /* request exclusive channel */
+ if (exclusive && channel>0) {
+ i = channel-1-(channel>16);
+ if (p_m_mISDNport->b_port[i])
+ return(-44); /* requested channel not available */
+ goto seize;
+ }
+
+ /* ask for channel */
+ if (channel>0) {
+ i = channel-1-(channel>16);
+ if (p_m_mISDNport->b_port[i] == NULL)
+ goto seize;
+ }
+
+ /* search for channel */
+ i = 0;
+ while(i < p_m_mISDNport->b_num) {
+ if (!p_m_mISDNport->b_port[i]) {
+ channel = i+1+(i>=15);
+ goto seize;
+ }
+ i++;
+ }
+ return(-34); /* no free channel */
+
+seize:
+ PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) seizing bchannel %d (index %d)\n", p_name, channel, i);
+
+ /* link Port, set parameters */
+ p_m_mISDNport->b_port[i] = this;
+ p_m_b_index = i;
+ p_m_b_channel = channel;
+ p_m_b_exclusive = exclusive;
+ p_m_mISDNport->b_mode[i] = p_m_b_mode;
+
+ /* reserve channel */
+ if (!p_m_b_reserve) {
+ p_m_b_reserve = 1;
+ p_m_mISDNport->b_reserved++;