diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..fcf23f9 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# +# libpri: An implementation of Primary Rate ISDN +# +# Written by Mark Spencer +# +# Copyright (C) 2001, Linux Support Services, Inc. +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +TOBJS=testpri.o +STATIC_LIBRARY=libpri.a +DYNAMIC_LIBRARY=libpri.so.1.0 +STATIC_OBJS=pri.o q921.o prisched.o q931.o +DYNAMIC_OBJS=pri.lo q921.lo prisched.lo q931.lo +CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g + +all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) + +install: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) + mkdir -p /usr/lib + mkdir -p /usr/include + install -m 644 libpri.h /usr/include + install -m 755 $(DYNAMIC_LIBRARY) /usr/lib + ( cd /usr/lib ; ln -sf libpri.so.1 libpri.so ) + install -m 644 $(STATIC_LIBRARY) /usr/lib + /sbin/ldconfig + +%.lo : %.c + $(CC) -fPIC $(CFLAGS) -o $@ -c $< + +$(STATIC_LIBRARY): $(STATIC_OBJS) + ar rcs $(STATIC_LIBRARY) $(STATIC_OBJS) + ranlib $(STATIC_LIBRARY) + +$(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS) + $(CC) -shared -Wl,-soname,libpri.so.1 -o $@ $(DYNAMIC_OBJS) + /sbin/ldconfig -n . + ln -sf libpri.so.1 libpri.so + +clean: + rm -f *.o *.so *.lo + rm -f testpri $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) diff --git a/README b/README new file mode 100755 index 0000000..f2d6e3f --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +libpri: An implementation of Primate Rate ISDN + +Written by Mark Spencer + +What is libpri? +=============== + +libpri is a C implementation of the Primary Rate ISDN specification. It was +based on the Bellcore specification SR-NWT-002343 for National ISDN. As of +May 12, 2001, it has been tested work with NI-2, Nortel DMS-100, and Lucent 5E Custom protocols on switches from Nortel and Lucent. + +What is the license for libpri? +=============================== +libpri is distributed under the terms of the GNU General Public License, which permit its use and linking with other GPL'd software only. + +If you wish to use libpri in an application for which the GPL is not appropriate (e.g. a proprietary embedded system), licenses for libpri under more flexible terms can be readily obtained through Linux Support Services, Inc. at reasonable cost. + +How do I report bugs or contribute? +=================================== +For now, contact the author directly. In the future if there is sufficient interest, we will setup a mailing list. + +Does anything use this library so far? +====================================== +Yes, the Asterisk Open Source PBX does. http://www.asteriskpbx.com + +Also, the Zapata library has hooks for it. http://www.zapatatelephony.org + +Special thanks +============== +Special thanks to Jim Dixon for his help in testing and fixing the implementation. + diff --git a/TODO b/TODO new file mode 100755 index 0000000..aee1696 --- /dev/null +++ b/TODO @@ -0,0 +1,10 @@ +General: +-- D-Channel Backup +-- Test against 4e + +Q.921: +-- Support unnumbered information frames + +Q.931: +-- Locking Shift IE +-- Implement the 11 missing Q.931 timers diff --git a/libpri.h b/libpri.h new file mode 100755 index 0000000..68f07e6 --- /dev/null +++ b/libpri.h @@ -0,0 +1,254 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Written by Mark Spencer + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _PRI_H +#define _PRI_H + +/* Node types */ +#define PRI_NETWORK 1 +#define PRI_CPE 2 + +/* Debugging */ +#define PRI_DEBUG_Q921_RAW (1 << 0) /* Show raw HDLC frames */ +#define PRI_DEBUG_Q921_DUMP (1 << 1) /* Show each interpreted Q.921 frame */ +#define PRI_DEBUG_Q921_STATE (1 << 2) /* Debug state machine changes */ +#define PRI_DEBUG_CONFIG (1 << 3) /* Display error events on stdout */ +#define PRI_DEBUG_Q931_DUMP (1 << 5) /* Show interpreted Q.931 frames */ +#define PRI_DEBUG_Q931_STATE (1 << 6) /* Debug Q.931 state machine changes */ + +#define PRI_DEBUG_ALL (0xffff) /* Everything */ + +/* Switch types */ +#define PRI_SWITCH_UNKNOWN 0 +#define PRI_SWITCH_NI2 1 /* National ISDN 2 */ +#define PRI_SWITCH_DMS100 2 /* DMS 100 */ +#define PRI_SWITCH_LUCENT5E 3 /* Lucent 5E */ +#define PRI_SWITCH_ATT4ESS 4 /* AT&T 4ESS */ + +/* PRI D-Channel Events */ +#define PRI_EVENT_DCHAN_UP 1 /* D-channel is up */ +#define PRI_EVENT_DCHAN_DOWN 2 /* D-channel is down */ +#define PRI_EVENT_RESTART 3 /* B-channel is restarted */ +#define PRI_EVENT_CONFIG_ERR 4 /* Configuration Error Detected */ +#define PRI_EVENT_RING 5 /* Incoming call */ +#define PRI_EVENT_HANGUP 6 /* Call got hung up */ +#define PRI_EVENT_RINGING 7 /* Call is ringing (alerting) */ +#define PRI_EVENT_ANSWER 8 /* Call has been answered */ + +/* Simple states */ +#define PRI_STATE_DOWN 0 +#define PRI_STATE_UP 1 + +/* Dialing plan */ +#define PRI_INTERNATIONAL_ISDN 0x11 +#define PRI_NATIONAL_ISDN 0x21 +#define PRI_LOCAL_ISDN 0x41 +#define PRI_PRIVATE 0x49 +#define PRI_UNKNOWN 0x0 + +/* Presentation */ +#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00 +#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01 +#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02 +#define PRES_ALLOWED_NETWORK_NUMBER 0x03 +#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20 +#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21 +#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22 +#define PRES_PROHIB_NETWORK_NUMBER 0x23 +#define PRES_NUMBER_NOT_AVAILABLE 0x43 + +/* Causes for disconnection */ +#define PRI_CAUSE_UNALLOCATED 1 +#define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 +#define PRI_CAUSE_NO_ROUTE_DESTINATION 3 +#define PRI_CAUSE_CHANNEL_UNACCEPTABLE 6 +#define PRI_CAUSE_CALL_AWARDED_DELIVERED 7 +#define PRI_CAUSE_NORMAL_CLEARING 16 +#define PRI_CAUSE_USER_BUSY 17 +#define PRI_CAUSE_NO_USER_RESPONSE 18 +#define PRI_CAUSE_NO_ANSWER 19 +#define PRI_CAUSE_CALL_REJECTED 21 +#define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27 +#define PRI_CAUSE_INVALID_NUMBER_FORMAT 28 +#define PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY 30 +#define PRI_CAUSE_NORMAL_UNSPECIFIED 31 +#define PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION 34 +#define PRI_CAUSE_NORMAL_TEMPORARY_FAILURE 41 +#define PRI_CAUSE_SWITCH_CONGESTION 42 +#define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 +#define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44 +#define PRI_CAUSE_BEARERCAPABILITY_NOTAUTH 57 +#define PRI_CAUSE_BEARERCAPABILITY_NOTIMPL 65 +#define PRI_CAUSE_INVALID_CALL_REFERENCE 81 +#define PRI_CAUSE_INCOMPATIBLE_DESTINATION 88 +#define PRI_CAUSE_MANDATORY_IE_MISSING 96 +#define PRI_CAUSE_MESSAGE_TYPE_NONEXIST 97 +#define PRI_CAUSE_IE_NONEXIST 99 +#define PRI_CAUSE_INVALID_IE_CONTENTS 100 +#define PRI_CAUSE_WRONG_CALL_STATE 101 +#define PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE 102 +#define PRI_CAUSE_PROTOCOL_ERROR 111 +#define PRI_CAUSE_INTERWORKING 127 + +/* Transmit capabilities */ +#define PRI_TRANS_CAP_SPEECH 0x0 +#define PRI_TRANS_CAP_DIGITAL 0x80 +#define PRI_TRANS_CAP_AUDIO 0x10 + + +typedef struct q931_call q931_call; + +typedef struct pri_event_generic { + /* Events with no additional information fall in this category */ + int e; +} pri_event_generic; + +typedef struct pri_event_error { + int e; + char err[256]; +} pri_event_error; + +typedef struct pri_event_restart { + int e; + int channel; +} pri_event_restart; + +typedef struct pri_event_ringing { + int e; + int channel; + int cref; + q931_call *call; +} pri_event_ringing; + +typedef struct pri_event_answer { + int e; + int channel; + int cref; + q931_call *call; +} pri_event_answer; + +typedef struct pri_event_ring { + int e; + int channel; /* Channel requested */ + int callingpres; /* Presentation of Calling CallerID */ + int callingplan; /* Dialing plan of Calling entity */ + char callingnum[256]; /* Calling number */ + int calledplan; /* Dialing plan of Called number */ + char callednum[256]; /* Called number */ + int flexible; /* Are we flexible with our channel selection? */ + int cref; /* Call Reference Number */ + int ctype; /* Call type (see PRI_TRANS_CAP_* */ + q931_call *call; /* Opaque call pointer */ +} pri_event_ring; + +typedef struct pri_event_hangup { + int e; + int channel; /* Channel requested */ + int cause; + int cref; + q931_call *call; /* Opaque call pointer */ +} pri_event_hangup; + +typedef union { + int e; + pri_event_generic gen; /* Generic view */ + pri_event_restart restart; /* Restart view */ + pri_event_error err; /* Error view */ + pri_event_ring ring; /* Ring */ + pri_event_hangup hangup; /* Hang up */ + pri_event_ringing ringing; /* Ringing */ + pri_event_ringing answer; /* Answer */ +} pri_event; + +struct pri; + + +/* Create a D-channel on a given file descriptor. The file descriptor must be a + channel operating in HDLC mode with FCS computed by the fd's driver. Also it + must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype + must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */ +extern struct pri *pri_new(int fd, int nodetype, int switchtype); + +/* Set debug parameters on PRI -- see above debug definitions */ +extern void pri_set_debug(struct pri *pri, int debug); + +/* Run PRI on the given D-channel, taking care of any events that + need to be handled. If block is set, it will block until an event + occurs which needs to be handled */ +extern pri_event *pri_dchannel_run(struct pri *pri, int block); + +/* Check for an outstanding event on the PRI */ +pri_event *pri_check_event(struct pri *pri); + +/* Give a name to a given event ID */ +extern char *pri_event2str(int id); + +/* Give a name toa node type */ +extern char *pri_node2str(int id); + +/* Give a name to a switch type */ +extern char *pri_switch2str(int id); + +/* Print an event */ +extern void pri_dump_event(struct pri *pri, pri_event *e); + +/* Turn an event ID into a string */ +extern char *pri_event2str(int e); + +/* Turn presentation into a string */ +extern char *pri_pres2str(int pres); + +/* Turn numbering plan into a string */ +extern char *pri_plan2str(int plan); + +/* Turn cause into a string */ +extern char *pri_cause2str(int cause); + +/* Acknowledge a call and place it on the given channel. Set info to non-zero if there + is in-band data available on the channel */ +extern int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info); + +/* Answer the call on the given channel (ignored if you called acknowledge already). + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ +extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn); + +/* Release/Reject a call */ +extern int pri_release(struct pri *pri, q931_call *call, int cause); + +/* Hangup / Disconnect a call */ +extern int pri_disconnect(struct pri *pri, q931_call *call, int cause); + +/* Create a new call */ +extern q931_call *pri_new_call(struct pri *pri); + +/* How long until you need to poll for a new event */ +extern struct timeval *pri_schedule_next(struct pri *pri); + +/* Run any pending schedule events */ +extern int pri_schedule_run(struct pri *pri); + +extern int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, + int exclusive, int nonisdn, char *caller, int callerplan, int callerpres, + char *called,int calledplan); +#endif diff --git a/pri_internal.h b/pri_internal.h new file mode 100755 index 0000000..a518271 --- /dev/null +++ b/pri_internal.h @@ -0,0 +1,90 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Written by Mark Spencer + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _PRI_INTERNAL_H +#define _PRI_INTERNAL_H + +#include + +struct pri_sched { + struct timeval when; + void (*callback)(void *data); + void *data; +}; + +struct q921_frame; +enum q931_state; +enum q931_mode; + +/* No more than 128 scheduled events */ +#define MAX_SCHED 128 + +struct pri { + int fd; /* File descriptor for D-Channel */ + struct pri_sched pri_sched[MAX_SCHED]; /* Scheduled events */ + int debug; /* Debug stuff */ + int state; /* State of D-channel */ + int switchtype; /* Switch type */ + int localtype; /* Local network type (unknown, network, cpe) */ + int remotetype; /* Remote network type (unknown, network, cpe) */ + + /* Q.921 State */ + int q921_state; + int window; /* Max window size */ + int v_s; /* Next N(S) for transmission */ + int v_a; /* Last acknowledged frame */ + int v_r; /* Next frame expected to be received */ + int v_na; /* What we've told our peer we've acknowledged */ + int solicitfbit; /* Have we sent an I or S frame with the F-bit set? */ + int retrans; /* Retransmissions */ + + int cref; /* Next call reference value */ + + int busy; /* Peer is busy */ + + /* Various timers */ + int sabme_timer; /* SABME retransmit */ + int t203_timer; /* Max idle time */ + int t200_timer; /* T-200 retransmission timer */ + + /* Used by scheduler */ + struct timeval tv; + pri_event ev; /* Static event thingy */ + + /* Q.921 Re-transmission queue */ + struct q921_frame *txqueue; + + /* Q.931 calls */ + q931_call *calls; +}; + +extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data); + +extern int pri_schedule_run(struct pri *pri); + +extern void pri_schedule_del(struct pri *pri, int ev); + +extern pri_event *pri_mkerror(struct pri *pri, char *errstr); + +#endif diff --git a/pri_q921.h b/pri_q921.h new file mode 100755 index 0000000..d10b31c --- /dev/null +++ b/pri_q921.h @@ -0,0 +1,153 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Written by Mark Spencer + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _PRI_Q921_H +#define _PRI_Q921_H + +#include +#include + +/* Timer values */ + +#define T_WAIT_MIN 2000 +#define T_WAIT_MAX 10000 +#define T_200 1000 /* 1 second between SABME's */ +#define T_203 10000 /* 10 seconds with no packets max */ + +#define Q921_FRAMETYPE_MASK 0x3 + +#define Q921_FRAMETYPE_U 0x3 +#define Q921_FRAMETYPE_I 0x0 +#define Q921_FRAMETYPE_S 0x1 + + +typedef struct q921_header { +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t sapi:6; /* Service Access Point Indentifier (always 0 for PRI) (0) */ + u_int8_t c_r:1; /* Command/Response (0 if CPE, 1 if network) */ + u_int8_t ea1:1; /* Extended Address (0) */ + u_int8_t tei:7; /* Terminal Endpoint Identifier (0) */ + u_int8_t ea2:1; /* Extended Address Bit (1) */ +#else + u_int8_t ea1:1; /* Extended Address (0) */ + u_int8_t c_r:1; /* Command/Response (0 if CPE, 1 if network) */ + u_int8_t sapi:6; /* Service Access Point Indentifier (always 0 for PRI) (0) */ + u_int8_t ea2:1; /* Extended Address Bit (1) */ + u_int8_t tei:7; /* Terminal Endpoint Identifier (0) */ +#endif + u_int8_t data[0]; /* Further data */ +} q921_header; + +/* A Supervisory Format frame */ +typedef struct q921_s { + struct q921_header h; /* Header */ +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t x0:4; /* Unused */ + u_int8_t ss:2; /* Supervisory frame bits */ + u_int8_t ft:2; /* Frame type bits (01) */ + u_int8_t n_r:7; /* Number Received */ + u_int8_t p_f:1; /* Poll/Final bit */ +#else + u_int8_t ft:2; /* Frame type bits (01) */ + u_int8_t ss:2; /* Supervisory frame bits */ + u_int8_t x0:4; /* Unused */ + u_int8_t p_f:1; /* Poll/Final bit */ + u_int8_t n_r:7; /* Number Received */ +#endif + u_int8_t data[0]; /* Any further data */ + u_int8_t fcs[2]; /* At least an FCS */ +} q921_s; + +/* An Unnumbered Format frame */ +typedef struct q921_u { + struct q921_header h; /* Header */ +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t m3:3; /* Top 3 modifier bits */ + u_int8_t p_f:1; /* Poll/Final bit */ + u_int8_t m2:2; /* Two more modifier bits */ + u_int8_t ft:2; /* Frame type bits (11) */ +#else + u_int8_t ft:2; /* Frame type bits (11) */ + u_int8_t m2:2; /* Two more modifier bits */ + u_int8_t p_f:1; /* Poll/Final bit */ + u_int8_t m3:3; /* Top 3 modifier bits */ +#endif + u_int8_t data[0]; /* Any further data */ + u_int8_t fcs[2]; /* At least an FCS */ +} q921_u; + +/* An Information frame */ +typedef struct q921_i { + struct q921_header h; /* Header */ +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t n_s:7; /* Number sent */ + u_int8_t ft:1; /* Frame type (0) */ + u_int8_t n_r:7; /* Number received */ + u_int8_t p_f:1; /* Poll/Final bit */ +#else + u_int8_t ft:1; /* Frame type (0) */ + u_int8_t n_s:7; /* Number sent */ + u_int8_t p_f:1; /* Poll/Final bit */ + u_int8_t n_r:7; /* Number received */ +#endif + u_int8_t data[0]; /* Any further data */ + u_int8_t fcs[2]; /* At least an FCS */ +} q921_i; + +typedef union { + u_int8_t raw[0]; + q921_u u; + q921_s s; + q921_i i; + struct q921_header h; +} q921_h; + +typedef struct q921_frame { + struct q921_frame *next; /* Next in list */ + int len; /* Length of header + body */ + q921_i h; +} q921_frame; + +#define Q921_INC(j) (j) = ((j) + 1) % 128 + +typedef enum q921_state { + Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */ + Q921_LINK_CONNECTION_ESTABLISHED, + Q921_AWAITING_ESTABLISH, + Q921_AWAITING_RELEASE +} q921_state; + +/* Dumps a *known good* Q.921 packet */ +extern void q921_dump(q921_h *h, int len, int showraw, int txrx); + +/* Bring up the D-channel */ +extern void q921_start(struct pri *pri); + +extern void q921_reset(struct pri *pri); + +extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len); + +extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr); + +#endif diff --git a/pri_q931.h b/pri_q931.h new file mode 100755 index 0000000..1d0c551 --- /dev/null +++ b/pri_q931.h @@ -0,0 +1,190 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Written by Mark Spencer + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _PRI_Q931_H +#define _PRI_Q931_H + +typedef enum q931_state { + /* User states */ + U0_NULL_STATE, + U1_CALL_INITIATED, + U2_OVERLAP_SENDING, + U3_OUTGOING_CALL_PROCEEDING, + U4_CALL_DELIVERED, + U6_CALL_PRESENT, + U7_CALL_RECEIVED, + U8_CONNECT_REQUEST, + U9_INCOMING_CALL_PROCEEDING, + U10_ACTIVE, + U11_DISCONNECT_REQUEST, + U12_DISCONNECT_INDICATION, + U15_SUSPEND_REQUEST, + U17_RESUME_REQUEST, + U19_RELEASE_REQUEST, + U25_OVERLAP_RECEIVING, + /* Network states */ + N0_NULL_STATE, + N1_CALL_INITIATED, + N2_OVERLAP_SENDING, + N3_OUTGOING_CALL_PROCEEDING, + N4_CALL_DELIVERED, + N6_CALL_PRESENT, + N7_CALL_RECEIVED, + N8_CONNECT_REQUEST, + N9_INCOMING_CALL_PROCEEDING, + N10_ACTIVE, + N11_DISCONNECT_REQUEST, + N12_DISCONNECT_INDICATION, + N15_SUSPEND_REQUEST, + N17_RESUME_REQUEST, + N19_RELEASE_REQUEST, + N22_CALL_ABORT, + N25_OVERLAP_RECEIVING +} q931_state; + +typedef enum q931_mode { + UNKNOWN_MODE, + CIRCUIT_MODE, + PACKET_MODE +} q931_mode; + +typedef struct q931_h { + unsigned char raw[0]; + u_int8_t pd; /* Protocol Discriminator */ +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t x0:4; + u_int8_t crlen:4; +#else + u_int8_t crlen:4; + u_int8_t x0:4; +#endif + u_int8_t contents[0]; + u_int8_t crv[3]; +} q931_h; + + +/* Message type header */ +typedef struct q931_mh { +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t f:1; + u_int8_t msg:7; +#else + u_int8_t msg:7; + u_int8_t f:1; +#endif + u_int8_t data[0]; +} q931_mh; + +/* Information element format */ +typedef struct q931_ie { +#if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t f:1; + u_int8_t ie:7; +#else + u_int8_t ie:7; + u_int8_t f:1; +#endif + u_int8_t len; + u_int8_t data[0]; +} q931_ie; + +#define Q931_RES_HAVEEVENT (1 << 0) +#define Q931_RES_INERRROR (1 << 1) + +#define Q931_PROTOCOL_DISCRIMINATOR 0x08 + +/* Q.931 / National ISDN Message Types */ + +/* Call Establishment Messages */ +#define Q931_ALERTING 0x01 +#define Q931_CALL_PROCEEDING 0x02 +#define Q931_CONNECT 0x07 +#define Q931_CONNECT_ACKNOWLEDGE 0x0f +#define Q931_PROGRESS 0x03 +#define Q931_SETUP 0x05 + +/* Call Disestablishment Messages */ +#define Q931_DISCONNECT 0x45 +#define Q931_RELEASE 0x4d +#define Q931_RELEASE_COMPLETE 0x5a +#define Q931_RESTART 0x46 +#define Q931_RESTART_ACKNOWLEDGE 0x4e + +/* Miscellaneous Messages */ +#define Q931_STATUS 0x7d +#define Q931_STATUS_ENQUIRY 0x75 + +/* Maintenance messages (codeset 0 only) */ +#define NATIONAL_SERVICE 0x0f +#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07 + +/* Special codeset 0 IE */ +#define NATIONAL_CHANGE_STATUS 0x1 + +/* Q.931 / National ISDN Information Elements */ +#define Q931_LOCKING_SHIFT 0x90 +#define Q931_BEARER_CAPABILITY 0x04 +#define Q931_CAUSE 0x08 +#define Q931_CALL_STATE 0x14 +#define Q931_CHANNEL_IDENT 0x18 +#define Q931_PROGRESS_INDICATOR 0x1e +#define Q931_NETWORK_SPEC_FAC 0x20 +#define Q931_INFORMATION_RATE 0x40 +#define Q931_TRANSIT_DELAY 0x42 +#define Q931_TRANS_DELAY_SELECT 0x43 +#define Q931_BINARY_PARAMETERS 0x44 +#define Q931_WINDOW_SIZE 0x45 +#define Q931_PACKET_SIZE 0x46 +#define Q931_CLOSED_USER_GROUP 0x47 +#define Q931_REVERSE_CHARGE_INDIC 0x4a +#define Q931_CALLING_PARTY_NUMBER 0x6c +#define Q931_CALLING_PARTY_SUBADDR 0x6d +#define Q931_CALLED_PARTY_NUMBER 0x70 +#define Q931_CALLED_PARTY_SUBADDR 0x71 +#define Q931_REDIRECTING_NUMBER 0x74 +#define Q931_REDIRECTING_SUBADDR 0x75 +#define Q931_TRANSIT_NET_SELECT 0x78 +#define Q931_RESTART_INDICATOR 0x79 +#define Q931_LOW_LAYER_COMPAT 0x7c +#define Q931_HIGH_LAYER_COMPAT 0x7d + +extern int q931_receive(struct pri *pri, q931_h *h, int len); + +extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info); + +extern int q931_call_proceeding(struct pri *pri, q931_call *call); + +extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn); + +extern int q931_release(struct pri *pri, q931_call *call, int cause); + +extern int q931_disconnect(struct pri *pri, q931_call *call, int cause); + +extern q931_call *q931_new_call(struct pri *pri); + +extern int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, + int nonisdn, char *caller, int callerplan, int callerpres, char *called, + int calledplan); + +#endif diff --git a/prisched.c b/prisched.c new file mode 100755 index 0000000..ec18da9 --- /dev/null +++ b/prisched.c @@ -0,0 +1,100 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Written by Mark Spencer + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "libpri.h" +#include "pri_internal.h" +#include + + +static int maxsched = 0; + +/* Scheduler routines */ +int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data) +{ + int x; + struct timeval tv; + for (x=1;xpri_sched[x].callback) + break; + if (x == MAX_SCHED) { + fprintf(stderr, "No more room in scheduler\n"); + return -1; + } + if (x > maxsched) + maxsched = x; + gettimeofday(&tv, NULL); + tv.tv_sec += ms / 1000; + tv.tv_usec += (ms % 1000) * 1000; + if (tv.tv_usec > 1000000) + tv.tv_usec -= 1000000; + pri->pri_sched[x].when = tv; + pri->pri_sched[x].callback = function; + pri->pri_sched[x].data = data; + return x; +} + +struct timeval *pri_schedule_next(struct pri *pri) +{ + struct timeval *closest = NULL; + int x; + for (x=1;xpri_sched[x].callback && + (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) || + ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) && + (closest->tv_usec > pri->pri_sched[x].when.tv_usec)))) + closest = &pri->pri_sched[x].when; + } + return closest; +} + +int pri_schedule_run(struct pri *pri) +{ + struct timeval tv; + int x; + int p = 0; + void (*callback)(void *); + void *data; + gettimeofday(&tv, NULL); + for (x=1;xpri_sched[x].callback && + ((pri->pri_sched[x].when.tv_sec < tv.tv_sec) || + ((pri->pri_sched[x].when.tv_sec == tv.tv_sec) && + (pri->pri_sched[x].when.tv_usec <= tv.tv_usec)))) { + p++; + callback = pri->pri_sched[x].callback; + data = pri->pri_sched[x].data; + pri->pri_sched[x].callback = NULL; + pri->pri_sched[x].data = NULL; + callback(data); + } + } + return p; +} + +void pri_schedule_del(struct pri *pri,int id) +{ + if ((id >= MAX_SCHED) || (id < 0)) + fprintf(stderr, "Asked to delete sched id %d???\n", id); + pri->pri_sched[id].callback = NULL; +}