+++ /dev/null
-$Id: INTERFACE,v 1.15.8.2 2001/03/13 16:17:07 kai Exp $
-
-Description of the Interface between Linklevel and Hardwarelevel
- of isdn4linux:
-
-
- The Communication between Linklevel (LL) and Hardwarelevel (HL)
- is based on the struct isdn_if (defined in isdnif.h).
-
- An HL-driver can register itself at LL by calling the function
- register_isdn() with a pointer to that struct. Prior to that, it has
- to preset some of the fields of isdn_if. The LL sets the rest of
- the fields. All further communication is done via callbacks using
- the function-pointers defined in isdn_if.
-
- Changes/Version numbering:
-
- During development of the ISDN subsystem, several changes have been
- made to the interface. Before it went into kernel, the package
- had a unique version number. The last version, distributed separately
- was 0.7.4. When the subsystem went into kernel, every functional unit
- got a separate version number. These numbers are shown at initialization,
- separated by slashes:
-
- c.c/t.t/n.n/p.p/a.a/v.v
-
- where
-
- c.c is the revision of the common code.
- t.t is the revision of the tty related code.
- n.n is the revision of the network related code.
- p.p is the revision of the ppp related code.
- a.a is the revision of the audio related code.
- v.v is the revision of the V.110 related code.
-
- Changes in this document are marked with '***CHANGEx' where x representing
- the version number. If that number starts with 0, it refers to the old,
- separately distributed package. If it starts with one of the letters
- above, it refers to the revision of the corresponding module.
- ***CHANGEIx refers to the revision number of the isdnif.h
-
-1. Description of the fields of isdn_if:
-
- int channels;
-
- This field has to be set by the HL-driver to the number of channels
- supported prior to calling register_isdn(). Upon return of the call,
- the LL puts an id there, which has to be used by the HL-driver when
- invoking the other callbacks.
-
- int maxbufsize;
-
- ***CHANGE0.6: New since this version.
-
- Also to be preset by the HL-driver. With this value the HL-driver
- tells the LL the maximum size of a data-packet it will accept.
-
- unsigned long features;
-
- To be preset by the HL-driver. Using this field, the HL-driver
- announces the features supported. At the moment this is limited to
- report the supported layer2 and layer3-protocols. For setting this
- field the constants ISDN_FEATURE..., declared in isdnif.h have to be
- used.
-
- ***CHANGE0.7.1: The line type (1TR6, EDSS1) has to be set.
-
- unsigned short hl_hdrlen;
-
- ***CHANGE0.7.4: New field.
-
- To be preset by the HL-driver, if it supports sk_buff's. The driver
- should put here the amount of additional space needed in sk_buff's for
- its internal purposes. Drivers not supporting sk_buff's should
- initialize this field to 0.
-
- void (*rcvcallb_skb)(int, int, struct sk_buff *)
-
- ***CHANGE0.7.4: New field.
-
- This field will be set by LL. The HL-driver delivers received data-
- packets by calling this function. Upon calling, the HL-driver must
- already have its private data pulled off the head of the sk_buff.
-
- Parameter:
- int driver-Id
- int Channel-number locally to the driver. (starting with 0)
- struct sk_buff * Pointer to sk_buff, containing received data.
-
- int (*statcallb)(isdn_ctrl*);
-
- This field will be set by LL. This function has to be called by the
- HL-driver for signaling status-changes or other events to the LL.
-
- Parameter:
- isdn_ctrl*
-
- The struct isdn_ctrl also defined in isdn_if. The exact meanings of its
- fields are described together with the descriptions of the possible
- events. Here is only a short description of the fields:
-
- driver = driver Id.
- command = event-type. (one of the constants ISDN_STAT_...)
- arg = depends on event-type.
- num = depends on event-type.
-
- Returnvalue:
- 0 on success, else -1
-
- int (*command)(isdn_ctrl*);
-
- This field has to be preset by the HL-driver. It points to a function,
- to be called by LL to perform functions like dialing, B-channel
- setup, etc. The exact meaning of the parameters is described with the
- descriptions of the possible commands.
-
- Parameter:
- isdn_ctrl*
- driver = driver-Id
- command = command to perform. (one of the constants ISDN_CMD_...)
- arg = depends on command.
- num = depends on command.
-
- Returnvalue:
- >=0 on success, else error-code (-ENODEV etc.)
-
- int (*writebuf_skb)(int, int, int, struct sk_buff *)
-
- ***CHANGE0.7.4: New field.
- ***CHANGEI.1.21: New field.
-
- This field has to be preset by the HL-driver. The given function will
- be called by the LL for delivering data to be send via B-Channel.
-
-
- Parameter:
- int driver-Id ***CHANGE0.7.4: New parameter.
- int channel-number locally to the HL-driver. (starts with 0)
- int ack ***ChangeI1.21: New parameter
- If this is !0, the driver has to signal the delivery
- by sending an ISDN_STAT_BSENT. If this is 0, the driver
- MUST NOT send an ISDN_STAT_BSENT.
- struct sk_buff * Pointer to sk_buff containing data to be send via
- B-channel.
-
- Returnvalue:
- Length of data accepted on success, else error-code (-EINVAL on
- oversized packets etc.)
-
- int (*writecmd)(u_char*, int, int, int, int);
-
- This field has to be preset by the HL-driver. The given function will be
- called to perform write-requests on /dev/isdnctrl (i.e. sending commands
- to the card) The data-format is hardware-specific. This function is
- intended for debugging only. It is not necessary for normal operation
- and never will be called by the tty-emulation- or network-code. If
- this function is not supported, the driver has to set NULL here.
-
- Parameter:
- u_char* pointer to data.
- int length of data.
- int flag: 0 = call from within kernel-space. (HL-driver must use
- memcpy, may NOT use schedule())
- 1 = call from user-space. (HL-driver must use
- memcpy_fromfs, use of schedule() allowed)
- int driver-Id.
- int channel-number locally to the HL-driver. (starts with 0)
-
-***CHANGEI1.14: The driver-Id and channel-number are new since this revision.
-
- Returnvalue:
- Length of data accepted on success, else error-code (-EINVAL etc.)
-
- int (*readstat)(u_char*, int, int, int, int);
-
- This field has to be preset by the HL-driver. The given function will be
- called to perform read-requests on /dev/isdnctrl (i.e. reading replies
- from the card) The data-format is hardware-specific. This function is
- intended for debugging only. It is not necessary for normal operation
- and never will be called by the tty-emulation- or network-code. If
- this function is not supported, the driver has to set NULL here.
-
- Parameter:
- u_char* pointer to data.
- int length of data.
- int flag: 0 = call from within kernel-space. (HL-driver must use
- memcpy, may NOT use schedule())
- 1 = call from user-space. (HL-driver must use
- memcpy_fromfs, use of schedule() allowed)
- int driver-Id.
- int channel-number locally to the HL-driver. (starts with 0)
-
-***CHANGEI1.14: The driver-Id and channel-number are new since this revision.
-
- Returnvalue:
- Length of data on success, else error-code (-EINVAL etc.)
-
- char id[20];
- ***CHANGE0.7: New since this version.
-
- This string has to be preset by the HL-driver. Its purpose is for
- identification of the driver by the user. Eg.: it is shown in the
- status-info of /dev/isdninfo. Furthermore it is used as Id for binding
- net-interfaces to a specific channel. If a string of length zero is
- given, upon return, isdn4linux will replace it by a generic name. (line0,
- line1 etc.) It is recommended to make this string configurable during
- module-load-time. (copy a global variable to this string.) For doing that,
- modules 1.2.8 or newer are necessary.
-
-2. Description of the commands, a HL-driver has to support:
-
- All commands will be performed by calling the function command() described
- above from within the LL. The field command of the struct-parameter will
- contain the desired command, the field driver is always set to the
- appropriate driver-Id.
-
- Until now, the following commands are defined:
-
-***CHANGEI1.34: The parameter "num" has been replaced by a union "parm" containing
- the old "num" and a new setup_type struct used for ISDN_CMD_DIAL
- and ISDN_STAT_ICALL callback.
-
- ISDN_CMD_IOCTL:
-
- This command is intended for performing ioctl-calls for configuring
- hardware or similar purposes (setting port-addresses, loading firmware
- etc.) For this purpose, in the LL all ioctl-calls with an argument
- >= IIOCDRVCTL (0x100) will be handed transparently to this
- function after subtracting 0x100 and placing the result in arg.
- Example:
- If a userlevel-program calls ioctl(0x101,...) the function gets
- called with the field command set to 1.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_IOCTL
- arg = Original ioctl-cmd - IIOCDRVCTL
- parm.num = first bytes filled with (unsigned long)arg
-
- Returnvalue:
- Depending on driver.
-
-
- ISDN_CMD_DIAL:
-
- This command is used to tell the HL-driver it should dial a given
- number.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_DIAL
- arg = channel-number locally to the driver. (starting with 0)
-
- parm.setup.phone = An ASCII-String containing the number to dial.
- parm.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN.
- parm.setup.si1 = The Service-Indicator.
- parm.setup.si2 = Additional Service-Indicator.
-
- If the Line has been designed as SPV (a special german
- feature, meaning semi-leased-line) the phone has to
- start with an "S".
- ***CHANGE0.6: In previous versions the EAZ has been given in the
- highbyte of arg.
- ***CHANGE0.7.1: New since this version: ServiceIndicator and AddInfo.
-
- ISDN_CMD_ACCEPTD:
-
- With this command, the HL-driver is told to accept a D-Channel-setup.
- (Response to an incoming call)
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_ACCEPTD
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_CMD_ACCEPTB:
-
- With this command, the HL-driver is told to perform a B-Channel-setup.
- (after establishing D-Channel-Connection)
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_ACCEPTB
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_CMD_HANGUP:
-
- With this command, the HL-driver is told to hangup (B-Channel if
- established first, then D-Channel). This command is also used for
- actively rejecting an incoming call.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_HANGUP
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_CMD_CLREAZ:
-
- With this command, the HL-driver is told not to signal incoming
- calls to the LL.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_CLREAZ
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_CMD_SETEAZ:
-
- With this command, the HL-driver is told to signal incoming calls for
- the given EAZs/MSNs to the LL.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_SETEAZ
- arg = channel-number locally to the driver. (starting with 0)
- parm.num = ASCII-String, containing the desired EAZ's/MSN's
- (comma-separated). If an empty String is given, the
- HL-driver should respond to ALL incoming calls,
- regardless of the destination-address.
- ***CHANGE0.6: New since this version the "empty-string"-feature.
-
- ISDN_CMD_GETEAZ: (currently unused)
-
- With this command, the HL-driver is told to report the current setting
- given with ISDN_CMD_SETEAZ.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_GETEAZ
- arg = channel-number locally to the driver. (starting with 0)
- parm.num = ASCII-String, containing the current EAZ's/MSN's
-
- ISDN_CMD_SETSIL: (currently unused)
-
- With this command, the HL-driver is told to signal only incoming
- calls with the given Service-Indicators.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_SETSIL
- arg = channel-number locally to the driver. (starting with 0)
- parm.num = ASCII-String, containing the desired Service-Indicators.
-
- ISDN_CMD_GETSIL: (currently unused)
-
- With this command, the HL-driver is told to return the current
- Service-Indicators it will respond to.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_SETSIL
- arg = channel-number locally to the driver. (starting with 0)
- parm.num = ASCII-String, containing the current Service-Indicators.
-
- ISDN_CMD_SETL2:
-
- With this command, the HL-driver is told to select the given Layer-2-
- protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
- ISDN_CMD_ACCEPTD.
-
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_SETL2
- arg = channel-number locally to the driver. (starting with 0)
- logical or'ed with (protocol-Id << 8)
- protocol-Id is one of the constants ISDN_PROTO_L2...
- parm = unused.
-
- ISDN_CMD_GETL2: (currently unused)
-
- With this command, the HL-driver is told to return the current
- setting of the Layer-2-protocol.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_GETL2
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
- Returnvalue:
- current protocol-Id (one of the constants ISDN_L2_PROTO)
-
- ISDN_CMD_SETL3:
-
- With this command, the HL-driver is told to select the given Layer-3-
- protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
- ISDN_CMD_ACCEPTD.
-
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_SETL3
- arg = channel-number locally to the driver. (starting with 0)
- logical or'ed with (protocol-Id << 8)
- protocol-Id is one of the constants ISDN_PROTO_L3...
- parm.fax = Pointer to T30_s fax struct. (fax usage only)
-
- ISDN_CMD_GETL2: (currently unused)
-
- With this command, the HL-driver is told to return the current
- setting of the Layer-3-protocol.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_GETL3
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
- Returnvalue:
- current protocol-Id (one of the constants ISDN_L3_PROTO)
-
- ISDN_CMD_PROCEED:
-
- With this command, the HL-driver is told to proceed with a incoming call.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_PROCEED
- arg = channel-number locally to the driver. (starting with 0)
- setup.eazmsn= empty string or string send as uus1 in DSS1 with
- PROCEED message
-
- ISDN_CMD_ALERT:
-
- With this command, the HL-driver is told to alert a proceeding call.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_ALERT
- arg = channel-number locally to the driver. (starting with 0)
- setup.eazmsn= empty string or string send as uus1 in DSS1 with
- ALERT message
-
- ISDN_CMD_REDIR:
-
- With this command, the HL-driver is told to redirect a call in proceeding
- or alerting state.
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_REDIR
- arg = channel-number locally to the driver. (starting with 0)
- setup.eazmsn= empty string or string send as uus1 in DSS1 protocol
- setup.screen= screening indicator
- setup.phone = redirected to party number
-
- ISDN_CMD_PROT_IO:
-
- With this call, the LL-driver invokes protocol specific features through
- the LL.
- The call is not implicitely bound to a connection.
-
- Parameter:
- driver = driver-Id
- command = ISDN_CMD_PROT_IO
- arg = The lower 8 Bits define the addressed protocol as defined
- in ISDN_PTYPE..., the upper bits are used to differentiate
- the protocol specific CMD.
-
- para = protocol and function specific. See isdnif.h for detail.
-
-
- ISDN_CMD_FAXCMD:
-
- With this command the HL-driver receives a fax sub-command.
- For details refer to INTERFACE.fax
-
- Parameter:
- driver = driver-Id.
- command = ISDN_CMD_FAXCMD
- arg = channel-number locally to the driver. (starting with 0)
- parm = unused.
-
-
-3. Description of the events to be signaled by the HL-driver to the LL.
-
- All status-changes are signaled via calling the previously described
- function statcallb(). The field command of the struct isdn_cmd has
- to be set by the HL-driver with the appropriate Status-Id (event-number).
- The field arg has to be set to the channel-number (locally to the driver,
- starting with 0) to which this event applies. (Exception: STAVAIL-event)
-
- Until now, the following Status-Ids are defined:
-
- ISDN_STAT_AVAIL:
-
- With this call, the HL-driver signals the availability of new data
- for readstat(). Used only for debugging-purposes, see description
- of readstat().
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_STAVAIL
- arg = length of available data.
- parm = unused.
-
- ISDN_STAT_ICALL:
- ISDN_STAT_ICALLW:
-
- With this call, the HL-driver signals an incoming call to the LL.
- If ICALLW is signalled the incoming call is a waiting call without
- a available B-chan.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_ICALL
- arg = channel-number, locally to the driver. (starting with 0)
- para.setup.phone = Callernumber.
- para.setup.eazmsn = CalledNumber.
- para.setup.si1 = Service Indicator.
- para.setup.si2 = Additional Service Indicator.
- para.setup.plan = octet 3 from Calling party number Information Element.
- para.setup.screen = octet 3a from Calling party number Information Element.
-
- Return:
- 0 = No device matching this call.
- 1 = At least one device matching this call (RING on ttyI).
- HL-driver may send ALERTING on the D-channel in this case.
- 2 = Call will be rejected.
- 3 = Incoming called party number is currently incomplete.
- Additional digits are required.
- Used for signalling with PtP connections.
- 4 = Call will be held in a proceeding state
- (HL driver sends PROCEEDING)
- Used when a user space prog needs time to interpret a call
- para.setup.eazmsn may be filled with an uus1 message of
- 30 octets maximum. Empty string if no uus.
- 5 = Call will be actively deflected to another party
- Only available in DSS1/EURO protocol
- para.setup.phone must be set to destination party number
- para.setup.eazmsn may be filled with an uus1 message of
- 30 octets maximum. Empty string if no uus.
- -1 = An error happened. (Invalid parameters for example.)
- The keypad support now is included in the dial command.
-
-
- ISDN_STAT_RUN:
-
- With this call, the HL-driver signals availability of the ISDN-card.
- (after initializing, loading firmware)
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_RUN
- arg = unused.
- parm = unused.
-
- ISDN_STAT_STOP:
-
- With this call, the HL-driver signals unavailability of the ISDN-card.
- (before unloading, while resetting/reconfiguring the card)
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_STOP
- arg = unused.
- parm = unused.
-
- ISDN_STAT_DCONN:
-
- With this call, the HL-driver signals the successful establishment of
- a D-Channel-connection. (Response to ISDN_CMD_ACCEPTD or ISDN_CMD_DIAL)
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_DCONN
- arg = channel-number, locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_STAT_BCONN:
-
- With this call, the HL-driver signals the successful establishment of
- a B-Channel-connection. (Response to ISDN_CMD_ACCEPTB or because the
- remote-station has initiated establishment)
-
- The HL driver should call this when the logical l2/l3 protocol
- connection on top of the physical B-channel is established.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_BCONN
- arg = channel-number, locally to the driver. (starting with 0)
- parm.num = ASCII-String, containing type of connection (for analog
- modem only). This will be appended to the CONNECT message
- e.g. 14400/V.32bis
-
- ISDN_STAT_DHUP:
-
- With this call, the HL-driver signals the shutdown of a
- D-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
- or caused by a remote-hangup or if the remote-station has actively
- rejected a call.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_DHUP
- arg = channel-number, locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_STAT_BHUP:
-
- With this call, the HL-driver signals the shutdown of a
- B-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
- or caused by a remote-hangup.
-
- The HL driver should call this as soon as the logical l2/l3 protocol
- connection on top of the physical B-channel is released.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_BHUP
- arg = channel-number, locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_STAT_CINF:
-
- With this call, the HL-driver delivers charge-unit information to the
- LL.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_CINF
- arg = channel-number, locally to the driver. (starting with 0)
- parm.num = ASCII string containing charge-units (digits only).
-
- ISDN_STAT_LOAD: (currently unused)
-
- ISDN_STAT_UNLOAD:
-
- With this call, the HL-driver signals that it will be unloaded now. This
- tells the LL to release all corresponding data-structures.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_UNLOAD
- arg = unused.
- parm = unused.
-
- ISDN_STAT_BSENT:
-
- With this call the HL-driver signals the delivery of a data-packet.
- This callback is used by the network-interfaces only, tty-Emulation
- does not need this call.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_BSENT
- arg = channel-number, locally to the driver. (starting with 0)
- parm.length = ***CHANGEI.1.21: New field.
- the driver has to set this to the original length
- of the skb at the time of receiving it from the linklevel.
-
- ISDN_STAT_NODCH:
-
- With this call, the driver has to respond to a prior ISDN_CMD_DIAL, if
- no D-Channel is available.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_NODCH
- arg = channel-number, locally to the driver. (starting with 0)
- parm = unused.
-
- ISDN_STAT_ADDCH:
-
- This call is for HL-drivers, which are unable to check card-type
- or numbers of supported channels before they have loaded any firmware
- using ioctl. Those HL-driver simply set the channel-parameter to a
- minimum channel-number when registering, and later if they know
- the real amount, perform this call, allocating additional channels.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_ADDCH
- arg = number of channels to be added.
- parm = unused.
-
- ISDN_STAT_CAUSE:
-
- With this call, the HL-driver delivers CAUSE-messages to the LL.
- Currently the LL does not use this messages. Their contents is simply
- logged via kernel-messages. Therefore, currently the format of the
- messages is completely free. However they should be printable.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_NODCH
- arg = channel-number, locally to the driver. (starting with 0)
- parm.num = ASCII string containing CAUSE-message.
-
- ISDN_STAT_DISPLAY:
-
- With this call, the HL-driver delivers DISPLAY-messages to the LL.
- Currently the LL does not use this messages.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_DISPLAY
- arg = channel-number, locally to the driver. (starting with 0)
- para.display= string containing DISPLAY-message.
-
- ISDN_STAT_PROT:
-
- With this call, the HL-driver delivers protocol specific infos to the LL.
- The call is not implicitely bound to a connection.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_PROT
- arg = The lower 8 Bits define the addressed protocol as defined
- in ISDN_PTYPE..., the upper bits are used to differentiate
- the protocol specific STAT.
-
- para = protocol and function specific. See isdnif.h for detail.
-
- ISDN_STAT_DISCH:
-
- With this call, the HL-driver signals the LL to disable or enable the
- use of supplied channel and driver.
- The call may be used to reduce the available number of B-channels after
- loading the driver. The LL has to ignore a disabled channel when searching
- for free channels. The HL driver itself never delivers STAT callbacks for
- disabled channels.
- The LL returns a nonzero code if the operation was not successful or the
- selected channel is actually regarded as busy.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_DISCH
- arg = channel-number, locally to the driver. (starting with 0)
- parm.num[0] = 0 if channel shall be disabled, else enabled.
-
- ISDN_STAT_L1ERR:
-
- ***CHANGEI1.21 new status message.
- A signal can be sent to the linklevel if an Layer1-error results in
- packet-loss on receive or send. The field errcode of the cmd.parm
- union describes the error more precisely.
-
- Parameter:
- driver = driver-Id
- command = ISDN_STAT_L1ERR
- arg = channel-number, locally to the driver. (starting with 0)
- parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending.
- ISDN_STAT_L1ERR_RECV: Packet lost while receiving.
- ISDN_STAT_FAXIND:
-
- With this call the HL-driver signals a fax sub-command to the LL.
- For details refer to INTERFACE.fax
-
- Parameter:
- driver = driver-Id.
- command = ISDN_STAT_FAXIND
- arg = channel-number, locally to the driver. (starting with 0)
- parm = unused.
-
+++ /dev/null
-$Id: INTERFACE.fax,v 1.2 2000/08/06 09:22:50 armin Exp $
-
-
-Description of the fax-subinterface between linklevel and hardwarelevel of
- isdn4linux.
-
- The communication between linklevel (LL) and hardwarelevel (HL) for fax
- is based on the struct T30_s (defined in isdnif.h).
- This struct is allocated in the LL.
- In order to use fax, the LL provides the pointer to this struct with the
- command ISDN_CMD_SETL3 (parm.fax). This pointer expires in case of hangup
- and when a new channel to a new connection is assigned.
-
-
-Data handling:
- In send-mode the HL-driver has to handle the <DLE> codes and the bit-order
- conversion by itself.
- In receive-mode the LL-driver takes care of the bit-order conversion
- (specified by +FBOR)
-
-Structure T30_s description:
-
- This structure stores the values (set by AT-commands), the remote-
- capability-values and the command-codes between LL and HL.
-
- If the HL-driver receives ISDN_CMD_FAXCMD, all needed information
- is in this struct set by the LL.
- To signal information to the LL, the HL-driver has to set the
- parameters and use ISDN_STAT_FAXIND.
- (Please refer to INTERFACE)
-
-Structure T30_s:
-
- All members are 8-bit unsigned (__u8)
-
- - resolution
- - rate
- - width
- - length
- - compression
- - ecm
- - binary
- - scantime
- - id[]
- Local faxmachine's parameters, set by +FDIS, +FDCS, +FLID, ...
-
- - r_resolution
- - r_rate
- - r_width
- - r_length
- - r_compression
- - r_ecm
- - r_binary
- - r_scantime
- - r_id[]
- Remote faxmachine's parameters. To be set by HL-driver.
-
- - phase
- Defines the actual state of fax connection. Set by HL or LL
- depending on progress and type of connection.
- If the phase changes because of an AT command, the LL driver
- changes this value. Otherwise the HL-driver takes care of it, but
- only necessary on call establishment (from IDLE to PHASE_A).
- (one of the constants ISDN_FAX_PHASE_[IDLE,A,B,C,D,E])
-
- - direction
- Defines outgoing/send or incoming/receive connection.
- (ISDN_TTY_FAX_CONN_[IN,OUT])
-
- - code
- Commands from LL to HL; possible constants :
- ISDN_TTY_FAX_DR signals +FDR command to HL
-
- ISDN_TTY_FAX_DT signals +FDT command to HL
-
- ISDN_TTY_FAX_ET signals +FET command to HL
-
-
- Other than that the "code" is set with the hangup-code value at
- the end of connection for the +FHNG message.
-
- - r_code
- Commands from HL to LL; possible constants :
- ISDN_TTY_FAX_CFR output of +FCFR message.
-
- ISDN_TTY_FAX_RID output of remote ID set in r_id[]
- (+FCSI/+FTSI on send/receive)
-
- ISDN_TTY_FAX_DCS output of +FDCS and CONNECT message,
- switching to phase C.
-
- ISDN_TTY_FAX_ET signals end of data,
- switching to phase D.
-
- ISDN_TTY_FAX_FCON signals the established, outgoing connection,
- switching to phase B.
-
- ISDN_TTY_FAX_FCON_I signals the established, incoming connection,
- switching to phase B.
-
- ISDN_TTY_FAX_DIS output of +FDIS message and values.
-
- ISDN_TTY_FAX_SENT signals that all data has been sent
- and <DLE><ETX> is acknowledged,
- OK message will be sent.
-
- ISDN_TTY_FAX_PTS signals a msg-confirmation (page sent successful),
- depending on fet value:
- 0: output OK message (more pages follow)
- 1: switching to phase B (next document)
-
- ISDN_TTY_FAX_TRAIN_OK output of +FDCS and OK message (for receive mode).
-
- ISDN_TTY_FAX_EOP signals end of data in receive mode,
- switching to phase D.
-
- ISDN_TTY_FAX_HNG output of the +FHNG and value set by code and
- OK message, switching to phase E.
-
-
- - badlin
- Value of +FBADLIN
-
- - badmul
- Value of +FBADMUL
-
- - bor
- Value of +FBOR
-
- - fet
- Value of +FET command in send-mode.
- Set by HL in receive-mode for +FET message.
-
- - pollid[]
- ID-string, set by +FCIG
-
- - cq
- Value of +FCQ
-
- - cr
- Value of +FCR
-
- - ctcrty
- Value of +FCTCRTY
-
- - minsp
- Value of +FMINSP
-
- - phcto
- Value of +FPHCTO
-
- - rel
- Value of +FREL
-
- - nbc
- Value of +FNBC (0,1)
- (+FNBC is not a known class 2 fax command, I added this to change the
- automatic "best capabilities" connection in the eicon HL-driver)
-
-
-Armin
-mac@melware.de
-
+++ /dev/null
-README for the ISDN-subsystem
-
-1. Preface
-
- 1.1 Introduction
-
- This README describes how to set up and how to use the different parts
- of the ISDN-subsystem.
-
- For using the ISDN-subsystem, some additional userlevel programs are
- necessary. Those programs and some contributed utilities are available
- at
-
- ftp.isdn4linux.de
-
- /pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
-
-
- We also have set up a mailing-list:
-
- The isdn4linux-project originates in Germany, and therefore by historical
- reasons, the mailing-list's primary language is german. However mails
- written in english have been welcome all the time.
-
- to subscribe: write a email to majordomo@listserv.isdn4linux.de,
- Subject irrelevant, in the message body:
- subscribe isdn4linux <your_email_address>
-
- To write to the mailing-list, write to isdn4linux@listserv.isdn4linux.de
-
- This mailinglist is bidirectionally gated to the newsgroup
-
- de.alt.comm.isdn4linux
-
- There is also a well maintained FAQ in English available at
- https://www.mhessler.de/i4lfaq/
- It can be viewed online, or downloaded in sgml/text/html format.
- The FAQ can also be viewed online at
- https://www.isdn4linux.de/faq/i4lfaq.html
- or downloaded from
- ftp://ftp.isdn4linux.de/pub/isdn4linux/FAQ/
-
- 1.1 Technical details
-
- In the following Text, the terms MSN and EAZ are used.
-
- MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies
- to Euro(EDSS1)-type lines. Usually it is simply the phone number.
-
- EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and
- applies to German 1TR6-type lines. This is a one-digit string,
- simply appended to the base phone number
-
- The internal handling is nearly identical, so replace the appropriate
- term to that one, which applies to your local ISDN-environment.
-
- When the link-level-module isdn.o is loaded, it supports up to 16
- low-level-modules with up to 64 channels. (The number 64 is arbitrarily
- chosen and can be configured at compile-time --ISDN_MAX in isdn.h).
- A low-level-driver can register itself through an interface (which is
- defined in isdnif.h) and gets assigned a slot.
- The following char-devices are made available for each channel:
-
- A raw-control-device with the following functions:
- write: raw D-channel-messages (format: depends on driver).
- read: raw D-channel-messages (format: depends on driver).
- ioctl: depends on driver, i.e. for the ICN-driver, the base-address of
- the ports and the shared memory on the card can be set and read
- also the boot-code and the protocol software can be loaded into
- the card.
-
- O N L Y !!! for debugging (no locking against other devices):
- One raw-data-device with the following functions:
- write: data to B-channel.
- read: data from B-channel.
-
- In addition the following devices are made available:
-
- 128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator:
- The functionality is almost the same as that of a serial device
- (the line-discs are handled by the kernel), which lets you run
- SLIP, CSLIP and asynchronous PPP through the devices. We have tested
- Seyon, minicom, CSLIP (uri-dip) PPP, mgetty, XCept and Hylafax.
-
- The modem-emulation supports the following:
- 1.3.1 Commands:
-
- ATA Answer incoming call.
- ATD<No.> Dial, the number may contain:
- [0-9] and [,#.*WPT-S]
- the latter are ignored until 'S'.
- The 'S' must precede the number, if
- the line is a SPV (German 1TR6).
- ATE0 Echo off.
- ATE1 Echo on (default).
- ATH Hang-up.
- ATH1 Off hook (ignored).
- ATH0 Hang-up.
- ATI Return "ISDN for Linux...".
- ATI0 "
- ATI1 "
- ATI2 Report of last connection.
- ATO On line (data mode).
- ATQ0 Enable result codes (default).
- ATQ1 Disable result codes (default).
- ATSx=y Set register x to y.
- ATSx? Show contents of register x.
- ATV0 Numeric responses.
- ATV1 English responses (default).
- ATZ Load registers and EAZ/MSN from Profile.
- AT&Bx Set Send-Packet-size to x (max. 4000)
- The real packet-size may be limited by the
- low-level-driver used. e.g. the HiSax-Module-
- limit is 2000. You will get NO Error-Message,
- if you set it to higher values, because at the
- time of giving this command the corresponding
- driver may not be selected (see "Automatic
- Assignment") however the size of outgoing packets
- will be limited correctly.
- AT&D0 Ignore DTR
- AT&D2 DTR-low-edge: Hang up and return to
- command mode (default).
- AT&D3 Same as AT&D2 but also resets all registers.
- AT&Ex Set the EAZ/MSN for this channel to x.
- AT&F Reset all registers and profile to "factory-defaults"
- AT&Lx Set list of phone numbers to listen on. x is a
- list of wildcard patterns separated by semicolon.
- If this is set, it has precedence over the MSN set
- by AT&E.
- AT&Rx Select V.110 bitrate adaption.
- This command enables V.110 protocol with 9600 baud
- (x=9600), 19200 baud (x=19200) or 38400 baud
- (x=38400). A value of x=0 disables V.110 switching
- back to default X.75. This command sets the following
- Registers:
- Reg 14 (Layer-2 protocol):
- x = 0: 0
- x = 9600: 7
- x = 19200: 8
- x = 38400: 9
- Reg 18.2 = 1
- Reg 19 (Additional Service Indicator):
- x = 0: 0
- x = 9600: 197
- x = 19200: 199
- x = 38400: 198
- Note on value in Reg 19:
- There is _NO_ common convention for 38400 baud.
- The value 198 is chosen arbitrarily. Users
- _MUST_ negotiate this value before establishing
- a connection.
- AT&Sx Set window-size (x = 1..8) (not yet implemented)
- AT&V Show all settings.
- AT&W0 Write registers and EAZ/MSN to profile. See also
- iprofd (5.c in this README).
- AT&X0 BTX-mode and T.70-mode off (default)
- AT&X1 BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0)
- AT&X2 T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0)
- AT+Rx Resume a suspended call with CallID x (x = 1,2,3...)
- AT+Sx Suspend a call with CallID x (x = 1,2,3...)
-
- For voice-mode commands refer to README.audio
-
- 1.3.2 Escape sequence:
- During a connection, the emulation reacts just like
- a normal modem to the escape sequence <DELAY>+++<DELAY>.
- (The escape character - default '+' - can be set in the
- register 2).
- The DELAY must at least be 1.5 seconds long and delay
- between the escape characters must not exceed 0.5 seconds.
-
- 1.3.3 Registers:
-
- Nr. Default Description
- 0 0 Answer on ring number.
- (no auto-answer if S0=0).
- 1 0 Count of rings.
- 2 43 Escape character.
- (a value >= 128 disables the escape sequence).
- 3 13 Carriage return character (ASCII).
- 4 10 Line feed character (ASCII).
- 5 8 Backspace character (ASCII).
- 6 3 Delay in seconds before dialing.
- 7 60 Wait for carrier.
- 8 2 Pause time for comma (ignored)
- 9 6 Carrier detect time (ignored)
- 10 7 Carrier loss to disconnect time (ignored).
- 11 70 Touch tone timing (ignored).
- 12 69 Bit coded register:
- Bit 0: 0 = Suppress response messages.
- 1 = Show response messages.
- Bit 1: 0 = English response messages.
- 1 = Numeric response messages.
- Bit 2: 0 = Echo off.
- 1 = Echo on.
- Bit 3 0 = DCD always on.
- 1 = DCD follows carrier.
- Bit 4 0 = CTS follows RTS
- 1 = Ignore RTS, CTS always on.
- Bit 5 0 = return to command mode on DTR low.
- 1 = Same as 0 but also resets all
- registers.
- See also register 13, bit 2
- Bit 6 0 = DSR always on.
- 1 = DSR only on if channel is available.
- Bit 7 0 = Cisco-PPP-flag-hack off (default).
- 1 = Cisco-PPP-flag-hack on.
- 13 0 Bit coded register:
- Bit 0: 0 = Use delayed tty-send-algorithm
- 1 = Direct tty-send.
- Bit 1: 0 = T.70 protocol (Only for BTX!) off
- 1 = T.70 protocol (Only for BTX!) on
- Bit 2: 0 = Don't hangup on DTR low.
- 1 = Hangup on DTR low.
- Bit 3: 0 = Standard response messages
- 1 = Extended response messages
- Bit 4: 0 = CALLER NUMBER before every RING.
- 1 = CALLER NUMBER after first RING.
- Bit 5: 0 = T.70 extended protocol off
- 1 = T.70 extended protocol on
- Bit 6: 0 = Special RUNG Message off
- 1 = Special RUNG Message on
- "RUNG" is delivered on a ttyI, if
- an incoming call happened (RING) and
- the remote party hung up before any
- local ATA was given.
- Bit 7: 0 = Don't show display messages from net
- 1 = Show display messages from net
- (S12 Bit 1 must be 0 too)
- 14 0 Layer-2 protocol:
- 0 = X75/LAPB with I-frames
- 1 = X75/LAPB with UI-frames
- 2 = X75/LAPB with BUI-frames
- 3 = HDLC
- 4 = Transparent (audio)
- 7 = V.110, 9600 baud
- 8 = V.110, 19200 baud
- 9 = V.110, 38400 baud
- 10 = Analog Modem (only if hardware supports this)
- 11 = Fax G3 (only if hardware supports this)
- 15 0 Layer-3 protocol:
- 0 = transparent
- 1 = transparent with audio features (e.g. DSP)
- 2 = Fax G3 Class 2 commands (S14 has to be set to 11)
- 3 = Fax G3 Class 1 commands (S14 has to be set to 11)
- 16 250 Send-Packet-size/16
- 17 8 Window-size (not yet implemented)
- 18 4 Bit coded register, Service-Octet-1 to accept,
- or to be used on dialout:
- Bit 0: Service 1 (audio) when set.
- Bit 1: Service 5 (BTX) when set.
- Bit 2: Service 7 (data) when set.
- Note: It is possible to set more than one
- bit. In this case, on incoming calls
- the selected services are accepted,
- and if the service is "audio", the
- Layer-2-protocol is automatically
- changed to 4 regardless of the setting
- of register 14. On outgoing calls,
- the most significant 1-bit is chosen to
- select the outgoing service octet.
- 19 0 Service-Octet-2
- 20 0 Bit coded register (readonly)
- Service-Octet-1 of last call.
- Bit mapping is the same as register 18
- 21 0 Bit coded register (readonly)
- Set on incoming call (during RING) to
- octet 3 of calling party number IE (Numbering plan)
- See section 4.5.10 of ITU Q.931
- 22 0 Bit coded register (readonly)
- Set on incoming call (during RING) to
- octet 3a of calling party number IE (Screening info)
- See section 4.5.10 of ITU Q.931
- 23 0 Bit coded register:
- Bit 0: 0 = Add CPN to RING message off
- 1 = Add CPN to RING message on
- Bit 1: 0 = Add CPN to FCON message off
- 1 = Add CPN to FCON message on
- Bit 2: 0 = Add CDN to RING/FCON message off
- 1 = Add CDN to RING/FCON message on
-
- Last but not least a (at the moment fairly primitive) device to request
- the line-status (/dev/isdninfo) is made available.
-
- Automatic assignment of devices to lines:
-
- All inactive physical lines are listening to all EAZs for incoming
- calls and are NOT assigned to a specific tty or network interface.
- When an incoming call is detected, the driver looks first for a network
- interface and then for an opened tty which:
-
- 1. is configured for the same EAZ.
- 2. has the same protocol settings for the B-channel.
- 3. (only for network interfaces if the security flag is set)
- contains the caller number in its access list.
- 4. Either the channel is not bound exclusively to another Net-interface, or
- it is bound AND the other checks apply to exactly this interface.
- (For usage of the bind-features, refer to the isdnctrl-man-page)
-
- Only when a matching interface or tty is found is the call accepted
- and the "connection" between the low-level-layer and the link-level-layer
- is established and kept until the end of the connection.
- In all other cases no connection is established. Isdn4linux can be
- configured to either do NOTHING in this case (which is useful, if
- other, external devices with the same EAZ/MSN are connected to the bus)
- or to reject the call actively. (isdnctrl busreject ...)
-
- For an outgoing call, the inactive physical lines are searched.
- The call is placed on the first physical line, which supports the
- requested protocols for the B-channel. If a net-interface, however
- is pre-bound to a channel, this channel is used directly.
-
- This makes it possible to configure several network interfaces and ttys
- for one EAZ, if the network interfaces are set to secure operation.
- If an incoming call matches one network interface, it gets connected to it.
- If another incoming call for the same EAZ arrives, which does not match
- a network interface, the first tty gets a "RING" and so on.
-
-2 System prerequisites:
-
- ATTENTION!
-
- Always use the latest module utilities. The current version is
- named in Documentation/Changes. Some old versions of insmod
- are not capable of setting the driver-Ids correctly.
-
-3. Lowlevel-driver configuration.
-
- Configuration depends on how the drivers are built. See the
- README.<yourDriver> for information on driver-specific setup.
-
-4. Device-inodes
-
- The major and minor numbers and their names are described in
- Documentation/admin-guide/devices.rst. The major numbers are:
-
- 43 for the ISDN-tty's.
- 44 for the ISDN-callout-tty's.
- 45 for control/info/debug devices.
-
-5. Application
-
- a) For some card-types, firmware has to be loaded into the cards, before
- proceeding with device-independent setup. See README.<yourDriver>
- for how to do that.
-
- b) If you only intend to use ttys, you are nearly ready now.
-
- c) If you want to have really permanent "Modem"-settings on disk, you
- can start the daemon iprofd. Give it a path to a file at the command-
- line. It will store the profile-settings in this file every time
- an AT&W0 is performed on any ISDN-tty. If the file already exists,
- all profiles are initialized from this file. If you want to unload
- any of the modules, kill iprofd first.
-
- d) For networking, continue: Create an interface:
- isdnctrl addif isdn0
-
- e) Set the EAZ (or MSN for Euro-ISDN):
- isdnctrl eaz isdn0 2
-
- (For 1TR6 a single digit is allowed, for Euro-ISDN the number is your
- real MSN e.g.: Phone-Number)
-
- f) Set the number for outgoing calls on the interface:
- isdnctrl addphone isdn0 out 1234567
- ... (this can be executed more than once, all assigned numbers are
- tried in order)
- and the number(s) for incoming calls:
- isdnctrl addphone isdn0 in 1234567
-
- g) Set the timeout for hang-up:
- isdnctrl huptimeout isdn0 <timeout_in_seconds>
-
- h) additionally you may activate charge-hang-up (= Hang up before
- next charge-info, this only works, if your isdn-provider transmits
- the charge-info during and after the connection):
- isdnctrl chargehup isdn0 on
-
- i) Set the dial mode of the interface:
- isdnctrl dialmode isdn0 auto
- "off" means that you (or the system) cannot make any connection
- (neither incoming or outgoing connections are possible). Use
- this if you want to be sure that no connections will be made.
- "auto" means that the interface is in auto-dial mode, and will
- attempt to make a connection whenever a network data packet needs
- the interface's link. Note that this can cause unexpected dialouts,
- and lead to a high phone bill! Some daemons or other pc's that use
- this interface can cause this.
- Incoming connections are also possible.
- "manual" is a dial mode created to prevent the unexpected dialouts.
- In this mode, the interface will never make any connections on its
- own. You must explicitly initiate a connection with "isdnctrl dial
- isdn0". However, after an idle time of no traffic as configured for
- the huptimeout value with isdnctrl, the connection _will_ be ended.
- If you don't want any automatic hangup, set the huptimeout value to 0.
- "manual" is the default.
-
- j) Setup the interface with ifconfig as usual, and set a route to it.
-
- k) (optional) If you run X11 and have Tcl/Tk-wish version 4.0, you can use
- the script tools/tcltk/isdnmon. You can add actions for line-status
- changes. See the comments at the beginning of the script for how to
- do that. There are other tty-based tools in the tools-subdirectory
- contributed by Michael Knigge (imon), Volker Götz (imontty) and
- Andreas Kool (isdnmon).
-
- l) For initial testing, you can set the verbose-level to 2 (default: 0).
- Then all incoming calls are logged, even if they are not addressed
- to one of the configured net-interfaces:
- isdnctrl verbose 2
-
- Now you are ready! A ping to the set address should now result in an
- automatic dial-out (look at syslog kernel-messages).
- The phone numbers and EAZs can be assigned at any time with isdnctrl.
- You can add as many interfaces as you like with addif following the
- directions above. Of course, there may be some limitations. But we have
- tested as many as 20 interfaces without any problem. However, if you
- don't give an interface name to addif, the kernel will assign a name
- which starts with "eth". The number of "eth"-interfaces is limited by
- the kernel.
-
-5. Additional options for isdnctrl:
-
- "isdnctrl secure <InterfaceName> on"
- Only incoming calls, for which the caller-id is listed in the access
- list of the interface are accepted. You can add caller-id's With the
- command "isdnctrl addphone <InterfaceName> in <caller-id>"
- Euro-ISDN does not transmit the leading '0' of the caller-id for an
- incoming call, therefore you should configure it accordingly.
- If the real number for the dialout e.g. is "09311234567" the number
- to configure here is "9311234567". The pattern-match function
- works similar to the shell mechanism.
-
- ? one arbitrary digit
- * zero or arbitrary many digits
- [123] one of the digits in the list
- [1-5] one digit between '1' and '5'
- a '^' as the first character in a list inverts the list
-
-
- "isdnctrl secure <InterfaceName> off"
- Switch off secure operation (default).
-
- "isdnctrl ihup <InterfaceName> [on|off]"
- Switch the hang-up-timer for incoming calls on or off.
-
- "isdnctrl eaz <InterfaceName>"
- Returns the EAZ of an interface.
-
- "isdnctrl delphone <InterfaceName> in|out <number>"
- Deletes a number from one of the access-lists of the interface.
-
- "isdnctrl delif <InterfaceName>"
- Removes the interface (and possible slaves) from the kernel.
- (You have to unregister it with "ifconfig <InterfaceName> down" before).
-
- "isdnctrl callback <InterfaceName> [on|off]"
- Switches an interface to callback-mode. In this mode, an incoming call
- will be rejected and after this the remote-station will be called. If
- you test this feature by using ping, some routers will re-dial very
- quickly, so that the callback from isdn4linux may not be recognized.
- In this case use ping with the option -i <sec> to increase the interval
- between echo-packets.
-
- "isdnctrl cbdelay <InterfaceName> [seconds]"
- Sets the delay (default 5 sec) between an incoming call and start of
- dialing when callback is enabled.
-
- "isdnctrl cbhup <InterfaceName> [on|off]"
- This enables (default) or disables an active hangup (reject) when getting an
- incoming call for an interface which is configured for callback.
-
- "isdnctrl encap <InterfaceName> <EncapType>"
- Selects the type of packet-encapsulation. The encapsulation can be changed
- only while an interface is down.
-
- At the moment the following values are supported:
-
- rawip (Default) Selects raw-IP-encapsulation. This means, MAC-headers
- are stripped off.
- ip IP with type-field. Same as IP but the type-field of the MAC-header
- is preserved.
- x25iface X.25 interface encapsulation (first byte semantics as defined in
- ../networking/x25-iface.txt). Use this for running the linux
- X.25 network protocol stack (AF_X25 sockets) on top of isdn.
- cisco-h A special-mode for communicating with a Cisco, which is configured
- to do "hdlc"
- ethernet No stripping. Packets are sent with full MAC-header.
- The Ethernet-address of the interface is faked, from its
- IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values.
- syncppp Synchronous PPP
-
- uihdlc HDLC with UI-frame-header (for use with DOS ISPA, option -h1)
-
-
- NOTE: x25iface encapsulation is currently experimental. Please
- read README.x25 for further details
-
-
- Watching packets, using standard-tcpdump will fail for all encapsulations
- except ethernet because tcpdump does not know how to handle packets
- without MAC-header. A patch for tcpdump is included in the utility-package
- mentioned above.
-
- "isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>"
- Selects a layer-2-protocol.
- (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
- With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be
- possible too. See README.x25 for x25 related l2 protocols.)
-
- isdnctrl l3_prot <InterfaceName> <L3-ProtocolName>
- The same for layer-3. (At the moment only "trans" is allowed)
-
- "isdnctrl list <InterfaceName>"
- Shows all parameters of an interface and the charge-info.
- Try "all" as the interface name.
-
- "isdnctrl hangup <InterfaceName>"
- Forces hangup of an interface.
-
- "isdnctrl bind <InterfaceName> <DriverId>,<ChannelNumber> [exclusive]"
- If you are using more than one ISDN card, it is sometimes necessary to
- dial out using a specific card or even preserve a specific channel for
- dialout of a specific net-interface. This can be done with the above
- command. Replace <DriverId> by whatever you assigned while loading the
- module. The <ChannelNumber> is counted from zero. The upper limit
- depends on the card used. At the moment no card supports more than
- 2 channels, so the upper limit is one.
-
- "isdnctrl unbind <InterfaceName>"
- unbinds a previously bound interface.
-
- "isdnctrl busreject <DriverId> on|off"
- If switched on, isdn4linux replies a REJECT to incoming calls, it
- cannot match to any configured interface.
- If switched off, nothing happens in this case.
- You normally should NOT enable this feature, if the ISDN adapter is not
- the only device connected to the S0-bus. Otherwise it could happen that
- isdn4linux rejects an incoming call, which belongs to another device on
- the bus.
-
- "isdnctrl addslave <InterfaceName> <SlaveName>
- Creates a slave interface for channel-bundling. Slave interfaces are
- not seen by the kernel, but their ISDN-part can be configured with
- isdnctrl as usual. (Phone numbers, EAZ/MSN, timeouts etc.) If more
- than two channels are to be bundled, feel free to create as many as you
- want. InterfaceName must be a real interface, NOT a slave. Slave interfaces
- start dialing, if the master interface resp. the previous slave interface
- has a load of more than 7000 cps. They hangup if the load goes under 7000
- cps, according to their "huptimeout"-parameter.
-
- "isdnctrl sdelay <InterfaceName> secs."
- This sets the minimum time an Interface has to be fully loaded, until
- it sends a dial-request to its slave.
-
- "isdnctrl dial <InterfaceName>"
- Forces an interface to start dialing even if no packets are to be
- transferred.
-
- "isdnctrl mapping <DriverId> MSN0,MSN1,MSN2,...MSN9"
- This installs a mapping table for EAZ<->MSN-mapping for a single line.
- Missing MSN's have to be given as "-" or can be omitted, if at the end
- of the commandline.
- With this command, it's now possible to have an interface listening to
- mixed 1TR6- and Euro-Type lines. In this case, the interface has to be
- configured to a 1TR6-type EAZ (one digit). The mapping is also valid
- for tty-emulation. Seen from the interface/tty-level the mapping
- CAN be used, however it's possible to use single tty's/interfaces with
- real MSN's (more digits) also, in which case the mapping will be ignored.
- Here is an example:
-
- You have a 1TR6-type line with base-nr. 1234567 and a Euro-line with
- MSN's 987654, 987655 and 987656. The DriverId for the Euro-line is "EURO".
-
- isdnctrl mapping EURO -,987654,987655,987656,-,987655
- ...
- isdnctrl eaz isdn0 1 # listen on 12345671(1tr6) and 987654(euro)
- ...
- isdnctrl eaz isdn1 4 # listen on 12345674(1tr6) only.
- ...
- isdnctrl eaz isdn2 987654 # listen on 987654(euro) only.
-
- Same scheme is used with AT&E... at the tty's.
-
-6. If you want to write a new low-level-driver, you are welcome.
- The interface to the link-level-module is described in the file INTERFACE.
- If the interface should be expanded for any reason, don't do it
- on your own, send me a mail containing the proposed changes and
- some reasoning about them.
- If other drivers will not be affected, I will include the changes
- in the next release.
- For developers only, there is a second mailing-list. Write to me
- (fritz@isdn4linux.de), if you want to join that list.
-
-Have fun!
-
- -Fritz
-
+++ /dev/null
-
-The FAQ for isdn4linux
-======================
-
-Please note that there is a big FAQ available in the isdn4k-utils.
-You find it in:
- isdn4k-utils/FAQ/i4lfaq.sgml
-
-In case you just want to see the FAQ online, or download the newest version,
-you can have a look at my website:
-https://www.mhessler.de/i4lfaq/ (view + download)
-or:
-https://www.isdn4linux.de/faq/4lfaq.html (view)
-
-As the extension tells, the FAQ is in SGML format, and you can convert it
-into text/html/... format by using the sgml2txt/sgml2html/... tools.
-Alternatively, you can also do a 'configure; make all' in the FAQ directory.
-
-
-Please have a look at the FAQ before posting anything in the Mailinglist,
-or the newsgroup!
-
-
-Matthias Hessler
-hessler@isdn4linux.de
-
+++ /dev/null
-$Id: README.audio,v 1.8 1999/07/11 17:17:29 armin Exp $
-
-ISDN subsystem for Linux.
- Description of audio mode.
-
-When enabled during kernel configuration, the tty emulator of the ISDN
-subsystem is capable of a reduced set of commands to support audio.
-This document describes the commands supported and the format of
-audio data.
-
-Commands for enabling/disabling audio mode:
-
- AT+FCLASS=8 Enable audio mode.
- This affects the following registers:
- S18: Bits 0 and 2 are set.
- S16: Set to 48 and any further change to
- larger values is blocked.
- AT+FCLASS=0 Disable audio mode.
- Register 18 is set to 4.
- AT+FCLASS=? Show possible modes.
- AT+FCLASS? Report current mode (0 or 8).
-
-Commands supported in audio mode:
-
-All audio mode commands have one of the following forms:
-
- AT+Vxx? Show current setting.
- AT+Vxx=? Show possible settings.
- AT+Vxx=v Set simple parameter.
- AT+Vxx=v,v ... Set complex parameter.
-
-where xx is a two-character code and v are alphanumerical parameters.
-The following commands are supported:
-
- AT+VNH=x Auto hangup setting. NO EFFECT, supported
- for compatibility only.
- AT+VNH? Always reporting "1"
- AT+VNH=? Always reporting "1"
-
- AT+VIP Reset all audio parameters.
-
- AT+VLS=x Line select. x is one of the following:
- 0 = No device.
- 2 = Phone line.
- AT+VLS=? Always reporting "0,2"
- AT+VLS? Show current line.
-
- AT+VRX Start recording. Emulator responds with
- CONNECT and starts sending audio data to
- the application. See below for data format
-
- AT+VSD=x,y Set silence-detection parameters.
- Possible parameters:
- x = 0 ... 31 sensitivity threshold level.
- (default 0 , deactivated)
- y = 0 ... 255 range of interval in units
- of 0.1 second. (default 70)
- AT+VSD=? Report possible parameters.
- AT+VSD? Show current parameters.
-
- AT+VDD=x,y Set DTMF-detection parameters.
- Only possible if online and during this connection.
- Possible parameters:
- x = 0 ... 15 sensitivity threshold level.
- (default 0 , I4L soft-decode)
- (1-15 soft-decode off, hardware on)
- y = 0 ... 255 tone duration in units of 5ms.
- Not for I4L soft decode (default 8, 40ms)
- AT+VDD=? Report possible parameters.
- AT+VDD? Show current parameters.
-
- AT+VSM=x Select audio data format.
- Possible parameters:
- 2 = ADPCM-2
- 3 = ADPCM-3
- 4 = ADPCM-4
- 5 = aLAW
- 6 = uLAW
- AT+VSM=? Show possible audio formats.
-
- AT+VTX Start audio playback. Emulator responds
- with CONNECT and starts sending audio data
- received from the application via phone line.
-General behavior and description of data formats/protocol.
- when a connection is made:
-
- On incoming calls, if the application responds to a RING
- with ATA, depending on the calling service, the emulator
- responds with either CONNECT (data call) or VCON (voice call).
-
- On outgoing voice calls, the emulator responds with VCON
- upon connection setup.
-
- Audio recording.
-
- When receiving audio data, a kind of bisync protocol is used.
- Upon AT+VRX command, the emulator responds with CONNECT, and
- starts sending audio data to the application. There are several
- escape sequences defined, all using DLE (0x10) as Escape char:
-
- <DLE><ETX> End of audio data. (i.e. caused by a
- hangup of the remote side) Emulator stops
- recording, responding with VCON.
- <DLE><DC4> Abort recording, (send by appl.) Emulator
- stops recording, sends DLE,ETX.
- <DLE><DLE> Escape sequence for DLE in data stream.
- <DLE>0 Touchtone "0" received.
- ...
- <DLE>9 Touchtone "9" received.
- <DLE># Touchtone "#" received.
- <DLE>* Touchtone "*" received.
- <DLE>A Touchtone "A" received.
- <DLE>B Touchtone "B" received.
- <DLE>C Touchtone "C" received.
- <DLE>D Touchtone "D" received.
-
- <DLE>q quiet. Silence detected after non-silence.
- <DLE>s silence. Silence detected from the
- start of recording.
-
- Currently unsupported DLE sequences:
-
- <DLE>c FAX calling tone received.
- <DLE>b busy tone received.
-
- Audio playback.
-
- When sending audio data, upon AT+VTX command, emulator responds with
- CONNECT, and starts transferring data from application to the phone line.
- The same DLE sequences apply to this mode.
-
- Full-Duplex-Audio:
-
- When _both_ commands for recording and playback are given in _one_
- AT-command-line (i.e.: "AT+VTX+VRX"), full-duplex-mode is selected.
- In this mode, the only way to stop recording is sending <DLE><DC4>
- and the only way to stop playback is to send <DLE><ETX>.
-
+++ /dev/null
-Description of the "concap" encapsulation protocol interface
-============================================================
-
-The "concap" interface is intended to be used by network device
-drivers that need to process an encapsulation protocol.
-It is assumed that the protocol interacts with a linux network device by
-- data transmission
-- connection control (establish, release)
-Thus, the mnemonic: "CONnection CONtrolling eNCAPsulation Protocol".
-
-This is currently only used inside the isdn subsystem. But it might
-also be useful to other kinds of network devices. Thus, if you want
-to suggest changes that improve usability or performance of the
-interface, please let me know. I'm willing to include them in future
-releases (even if I needed to adapt the current isdn code to the
-changed interface).
-
-
-Why is this useful?
-===================
-
-The encapsulation protocol used on top of WAN connections or permanent
-point-to-point links are frequently chosen upon bilateral agreement.
-Thus, a device driver for a certain type of hardware must support
-several different encapsulation protocols at once.
-
-The isdn device driver did already support several different
-encapsulation protocols. The encapsulation protocol is configured by a
-user space utility (isdnctrl). The isdn network interface code then
-uses several case statements which select appropriate actions
-depending on the currently configured encapsulation protocol.
-
-In contrast, LAN network interfaces always used a single encapsulation
-protocol which is unique to the hardware type of the interface. The LAN
-encapsulation is usually done by just sticking a header on the data. Thus,
-traditional linux network device drivers used to process the
-encapsulation protocol directly (usually by just providing a hard_header()
-method in the device structure) using some hardware type specific support
-functions. This is simple, direct and efficient. But it doesn't fit all
-the requirements for complex WAN encapsulations.
-
-
- The configurability of the encapsulation protocol to be used
- makes isdn network interfaces more flexible, but also much more
- complex than traditional lan network interfaces.
-
-
-Many Encapsulation protocols used on top of WAN connections will not just
-stick a header on the data. They also might need to set up or release
-the WAN connection. They also might want to send other data for their
-private purpose over the wire, e.g. ppp does a lot of link level
-negotiation before the first piece of user data can be transmitted.
-Such encapsulation protocols for WAN devices are typically more complex
-than encapsulation protocols for lan devices. Thus, network interface
-code for typical WAN devices also tends to be more complex.
-
-
-In order to support Linux' x25 PLP implementation on top of
-isdn network interfaces I could have introduced yet another branch to
-the various case statements inside drivers/isdn/isdn_net.c.
-This eventually made isdn_net.c even more complex. In addition, it made
-isdn_net.c harder to maintain. Thus, by identifying an abstract
-interface between the network interface code and the encapsulation
-protocol, complexity could be reduced and maintainability could be
-increased.
-
-
-Likewise, a similar encapsulation protocol will frequently be needed by
-several different interfaces of even different hardware type, e.g. the
-synchronous ppp implementation used by the isdn driver and the
-asynchronous ppp implementation used by the ppp driver have a lot of
-similar code in them. By cleanly separating the encapsulation protocol
-from the hardware specific interface stuff such code could be shared
-better in future.
-
-
-When operating over dial-up-connections (e.g. telephone lines via modem,
-non-permanent virtual circuits of wide area networks, ISDN) many
-encapsulation protocols will need to control the connection. Therefore,
-some basic connection control primitives are supported. The type and
-semantics of the connection (i.e the ISO layer where connection service
-is provided) is outside our scope and might be different depending on
-the encapsulation protocol used, e.g. for a ppp module using our service
-on top of a modem connection a connect_request will result in dialing
-a (somewhere else configured) remote phone number. For an X25-interface
-module (LAPB semantics, as defined in Documentation/networking/x25-iface.txt)
-a connect_request will ask for establishing a reliable lapb
-datalink connection.
-
-
-The encapsulation protocol currently provides the following
-service primitives to the network device.
-
-- create a new encapsulation protocol instance
-- delete encapsulation protocol instance and free all its resources
-- initialize (open) the encapsulation protocol instance for use.
-- deactivate (close) an encapsulation protocol instance.
-- process (xmit) data handed down by upper protocol layer
-- receive data from lower (hardware) layer
-- process connect indication from lower (hardware) layer
-- process disconnect indication from lower (hardware) layer
-
-
-The network interface driver accesses those primitives via callbacks
-provided by the encapsulation protocol instance within a
-struct concap_proto_ops.
-
-struct concap_proto_ops{
-
- /* create a new encapsulation protocol instance of same type */
- struct concap_proto * (*proto_new) (void);
-
- /* delete encapsulation protocol instance and free all its resources.
- cprot may no longer be referenced after calling this */
- void (*proto_del)(struct concap_proto *cprot);
-
- /* initialize the protocol's data. To be called at interface startup
- or when the device driver resets the interface. All services of the
- encapsulation protocol may be used after this*/
- int (*restart)(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops);
-
- /* deactivate an encapsulation protocol instance. The encapsulation
- protocol may not call any *dops methods after this. */
- int (*close)(struct concap_proto *cprot);
-
- /* process a frame handed down to us by upper layer */
- int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
-
- /* to be called for each data entity received from lower layer*/
- int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
-
- /* to be called when a connection was set up/down.
- Protocols that don't process these primitives might fill in
- dummy methods here */
- int (*connect_ind)(struct concap_proto *cprot);
- int (*disconn_ind)(struct concap_proto *cprot);
-};
-
-
-The data structures are defined in the header file include/linux/concap.h.
-
-
-A Network interface using encapsulation protocols must also provide
-some service primitives to the encapsulation protocol:
-
-- request data being submitted by lower layer (device hardware)
-- request a connection being set up by lower layer
-- request a connection being released by lower layer
-
-The encapsulation protocol accesses those primitives via callbacks
-provided by the network interface within a struct concap_device_ops.
-
-struct concap_device_ops{
-
- /* to request data be submitted by device */
- int (*data_req)(struct concap_proto *, struct sk_buff *);
-
- /* Control methods must be set to NULL by devices which do not
- support connection control. */
- /* to request a connection be set up */
- int (*connect_req)(struct concap_proto *);
-
- /* to request a connection be released */
- int (*disconn_req)(struct concap_proto *);
-};
-
-The network interface does not explicitly provide a receive service
-because the encapsulation protocol directly calls netif_rx().
-
-
-
-
-An encapsulation protocol itself is actually the
-struct concap_proto{
- struct net_device *net_dev; /* net device using our service */
- struct concap_device_ops *dops; /* callbacks provided by device */
- struct concap_proto_ops *pops; /* callbacks provided by us */
- int flags;
- void *proto_data; /* protocol specific private data, to
- be accessed via *pops methods only*/
- /*
- :
- whatever
- :
- */
-};
-
-Most of this is filled in when the device requests the protocol to
-be reset (opend). The network interface must provide the net_dev and
-dops pointers. Other concap_proto members should be considered private
-data that are only accessed by the pops callback functions. Likewise,
-a concap proto should access the network device's private data
-only by means of the callbacks referred to by the dops pointer.
-
-
-A possible extended device structure which uses the connection controlling
-encapsulation services could look like this:
-
-struct concap_device{
- struct net_device net_dev;
- struct my_priv /* device->local stuff */
- /* the my_priv struct might contain a
- struct concap_device_ops *dops;
- to provide the device specific callbacks
- */
- struct concap_proto *cprot; /* callbacks provided by protocol */
-};
-
-
-
-Misc Thoughts
-=============
-
-The concept of the concap proto might help to reuse protocol code and
-reduce the complexity of certain network interface implementations.
-The trade off is that it introduces yet another procedure call layer
-when processing the protocol. This has of course some impact on
-performance. However, typically the concap interface will be used by
-devices attached to slow lines (like telephone, isdn, leased synchronous
-lines). For such slow lines, the overhead is probably negligible.
-This might no longer hold for certain high speed WAN links (like
-ATM).
-
-
-If general linux network interfaces explicitly supported concap
-protocols (e.g. by a member struct concap_proto* in struct net_device)
-then the interface of the service function could be changed
-by passing a pointer of type (struct net_device*) instead of
-type (struct concap_proto*). Doing so would make many of the service
-functions compatible to network device support functions.
-
-e.g. instead of the concap protocol's service function
-
- int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
-
-we could have
-
- int (*encap_and_xmit)(struct net_device *ndev, struct sk_buff *skb);
-
-As this is compatible to the dev->hard_start_xmit() method, the device
-driver could directly register the concap protocol's encap_and_xmit()
-function as its hard_start_xmit() method. This would eliminate one
-procedure call layer.
-
-
-The device's data request function could also be defined as
-
- int (*data_req)(struct net_device *ndev, struct sk_buff *skb);
-
-This might even allow for some protocol stacking. And the network
-interface might even register the same data_req() function directly
-as its hard_start_xmit() method when a zero layer encapsulation
-protocol is configured. Thus, eliminating the performance penalty
-of the concap interface when a trivial concap protocol is used.
-Nevertheless, the device remains able to support encapsulation
-protocol configuration.
-
+++ /dev/null
-The isdn diversion services are a supporting module working together with
-the isdn4linux and the HiSax module for passive cards.
-Active cards, TAs and cards using a own or other driver than the HiSax
-module need to be adapted to the HL<->LL interface described in a separate
-document. The diversion services may be used with all cards supported by
-the HiSax driver.
-The diversion kernel interface and controlling tool divertctrl were written
-by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the
-GNU General Public License.
-
- 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.
-
-Table of contents
-=================
-
-1. Features of the i4l diversion services
- (Or what can the i4l diversion services do for me)
-
-2. Required hard- and software
-
-3. Compiling, installing and loading/unloading the module
- Tracing calling and diversion information
-
-4. Tracing calling and diversion information
-
-5. Format of the divert device ASCII output
-
-
-1. Features of the i4l diversion services
- (Or what can the i4l diversion services do for me)
-
- The i4l diversion services offers call forwarding and logging normally
- only supported by isdn phones. Incoming calls may be diverted
- unconditionally (CFU), when not reachable (CFNR) or on busy condition
- (CFB).
- The diversions may be invoked statically in the providers exchange
- as normally done by isdn phones. In this case all incoming calls
- with a special (or all) service identifiers are forwarded if the
- forwarding reason is met. Activated static services may also be
- interrogated (queried).
- The i4l diversion services additionally offers a dynamic version of
- call forwarding which is not preprogrammed inside the providers exchange
- but dynamically activated by i4l.
- In this case all incoming calls are checked by rules that may be
- compared to the mechanism of ipfwadm or ipchains. If a given rule matches
- the checking process is finished and the rule matching will be applied
- to the call.
- The rules include primary and secondary service identifiers, called
- number and subaddress, callers number and subaddress and whether the rule
- matches to all filtered calls or only those when all B-channel resources
- are exhausted.
- Actions that may be invoked by a rule are ignore, proceed, reject,
- direct divert or delayed divert of a call.
- All incoming calls matching a rule except the ignore rule a reported and
- logged as ASCII via the proc filesystem (/proc/net/isdn/divert). If proceed
- is selected the call will be held in a proceeding state (without ringing)
- for a certain amount of time to let an external program or client decide
- how to handle the call.
-
-
-2. Required hard- and software
-
- For using the i4l diversion services the isdn line must be of a EURO/DSS1
- type. Additionally the i4l services only work together with the HiSax
- driver for passive isdn cards. All HiSax supported cards may be used for
- the diversion purposes.
- The static diversion services require the provider having static services
- CFU, CFNR, CFB activated on an MSN-line. The static services may not be
- used on a point-to-point connection. Further the static services are only
- available in some countries (for example germany). Countries requiring the
- keypad protocol for activating static diversions (like the netherlands) are
- not supported but may use the tty devices for this purpose.
- The dynamic diversion services may be used in all countries if the provider
- enables the feature CF (call forwarding). This should work on both MSN- and
- point-to-point lines.
- To add and delete rules the additional divertctrl program is needed. This
- program is part of the isdn4kutils package.
-
-3. Compiling, installing and loading/unloading the module
- Tracing calling and diversion information
-
-
- To compile the i4l code with diversion support you need to say yes to the
- DSS1 diversion services when selecting the i4l options in the kernel
- config (menuconfig or config).
- After having properly activated a make modules and make modules_install all
- required modules will be correctly installed in the needed modules dirs.
- As the diversion services are currently not included in the scripts of most
- standard distributions you will have to add a "insmod dss1_divert" after
- having loaded the global isdn module.
- The module can be loaded without any command line parameters.
- If the module is actually loaded and active may be checked with a
- "cat /proc/modules" or "ls /proc/net/isdn/divert". The divert file is
- dynamically created by the diversion module and removed when the module is
- unloaded.
-
-
-4. Tracing calling and diversion information
-
- You also may put a "cat /proc/net/isdn/divert" in the background with the
- output redirected to a file. Then all actions of the module are logged.
- The divert file in the proc system may be opened more than once, so in
- conjunction with inetd and a small remote client on other machines inside
- your network incoming calls and reactions by the module may be shown on
- every listening machine.
- If a call is reported as proceeding an external program or client may
- specify during a certain amount of time (normally 4 to 10 seconds) what
- to do with that call.
- To unload the module all open files to the device in the proc system must
- be closed. Otherwise the module (and isdn.o) may not be unloaded.
-
-5. Format of the divert device ASCII output
-
- To be done later
-
+++ /dev/null
-
-Fax with isdn4linux
-===================
-
-When enabled during kernel configuration, the tty emulator
-of the ISDN subsystem is capable of the Fax Class 2 commands.
-
-This only makes sense under the following conditions :
-
-- You need the commands as dummy, because you are using
- hylafax (with patch) for AVM capi.
-- You want to use the fax capabilities of your isdn-card.
- (supported cards are listed below)
-
-
-NOTE: This implementation does *not* support fax with passive
- ISDN-cards (known as softfax). The low-level driver of
- the ISDN-card and/or the card itself must support this.
-
-
-Supported ISDN-Cards
---------------------
-
-Eicon DIVA Server BRI/PCI
- - full support with both B-channels.
-
-Eicon DIVA Server 4BRI/PCI
- - full support with all B-channels.
-
-Eicon DIVA Server PRI/PCI
- - full support on amount of B-channels
- depending on DSPs on board.
-
-
-
-The command set is known as Class 2 (not Class 2.0) and
-can be activated by AT+FCLASS=2
-
-
-The interface between the link-level-module and the hardware-level driver
-is described in the files INTERFACE.fax and INTERFACE.
-
-Armin
-mac@melware.de
-
+++ /dev/null
-The driver for the HFC-PCI and HFC-PCI-A chips from CCD may be used
-for many OEM cards using this chips.
-Additionally the driver has a special feature which makes it possible
-to read the echo-channel of the isdn bus. So all frames in both directions
-may be logged.
-When the echo logging feature is used the number of available B-channels
-for a HFC-PCI card is reduced to 1. Of course this is only relevant to
-the card, not to the isdn line.
-To activate the echo mode the following ioctls must be entered:
-
-hisaxctrl <driver/cardname> 10 1
-
-This reduces the available channels to 1. There must not be open connections
-through this card when entering the command.
-And then:
-
-hisaxctrl <driver/cardname> 12 1
-
-This enables the echo mode. If Hex logging is activated the isdnctrlx
-devices show a output with a line beginning of HEX: for the providers
-exchange and ECHO: for isdn devices sending to the provider.
-
-If more than one HFC-PCI cards are installed, a specific card may be selected
-at the hisax module load command line. Supply the load command with the desired
-IO-address of the desired card.
-Example:
-There tree cards installed in your machine at IO-base addresses 0xd000, 0xd400
-and 0xdc00
-If you want to use the card at 0xd400 standalone you should supply the insmod
-or depmod with type=35 io=0xd400.
-If you want to use all three cards, but the order needs to be at 0xdc00,0xd400,
-0xd000 you may give the parameters type=35,35,35 io=0xdc00,0xd400,0xd00
-Then the desired card will be the initialised in the desired order.
-If the io parameter is used the io addresses of all used cards should be
-supplied else the parameter is assumed 0 and a auto search for a free card is
-invoked which may not give the wanted result.
-
-Comments and reports to werner@isdn4linux.de or werner@isdn-development.de
-
-
-
+++ /dev/null
-Some additional information for setting up a syncPPP
-connection using network interfaces.
----------------------------------------------------------------
-
-You need one thing beside the isdn4linux package:
-
- a patched pppd .. (I called it ipppd to show the difference)
-
-Compiling isdn4linux with sync PPP:
------------------------------------
-To compile isdn4linux with the sync PPP part, you have
-to answer the appropriate question when doing a "make config"
-Don't forget to load the slhc.o
-module before the isdn.o module, if VJ-compression support
-is not compiled into your kernel. (e.g if you have no PPP or
-CSLIP in the kernel)
-
-Using isdn4linux with sync PPP:
--------------------------------
-Sync PPP is just another encapsulation for isdn4linux. The
-name to enable sync PPP encapsulation is 'syncppp' .. e.g:
-
- /sbin/isdnctrl encap ippp0 syncppp
-
-The name of the interface is here 'ippp0'. You need
-one interface with the name 'ippp0' to saturate the
-ipppd, which checks the ppp version via this interface.
-Currently, all devices must have the name ipppX where
-'X' is a decimal value.
-
-To set up a PPP connection you need the ipppd .. You must start
-the ipppd once after installing the modules. The ipppd
-communicates with the isdn4linux link-level driver using the
-/dev/ippp0 to /dev/ippp15 devices. One ipppd can handle
-all devices at once. If you want to use two PPP connections
-at the same time, you have to connect the ipppd to two
-devices .. and so on.
-I've implemented one additional option for the ipppd:
- 'useifip' will get (if set to not 0.0.0.0) the IP address
- for the negotiation from the attached network-interface.
-(also: ipppd will try to negotiate pointopoint IP as remote IP)
-You must disable BSD-compression, this implementation can't
-handle compressed packets.
-
-Check the etc/rc.isdn.syncppp in the isdn4kernel-util package
-for an example setup script.
-
-To use the MPPP stuff, you must configure a slave device
-with isdn4linux. Now call the ipppd with the '+mp' option.
-To increase the number of links, you must use the
-'addlink' option of the isdnctrl tool. (rc.isdn.syncppp.MPPP is
-an example script)
-
-enjoy it,
- michael
-
-
-
+++ /dev/null
-
-X.25 support within isdn4linux
-==============================
-
-This is alpha/beta test code. Use it completely at your own risk.
-As new versions appear, the stuff described here might suddenly change
-or become invalid without notice.
-
-Keep in mind:
-
-You are using several new parts of the 2.2.x kernel series which
-have not been tested in a large scale. Therefore, you might encounter
-more bugs as usual.
-
-- If you connect to an X.25 neighbour not operated by yourself, ASK the
- other side first. Be prepared that bugs in the protocol implementation
- might result in problems.
-
-- This implementation has never wiped out my whole hard disk yet. But as
- this is experimental code, don't blame me if that happened to you.
- Backing up important data will never harm.
-
-- Monitor your isdn connections while using this software. This should
- prevent you from undesired phone bills in case of driver problems.
-
-
-
-
-How to configure the kernel
-===========================
-
-The ITU-T (former CCITT) X.25 network protocol layer has been implemented
-in the Linux source tree since version 2.1.16. The isdn subsystem might be
-useful to run X.25 on top of ISDN. If you want to try it, select
-
- "CCITT X.25 Packet Layer"
-
-from the networking options as well as
-
- "ISDN Support" and "X.25 PLP on Top of ISDN"
-
-from the ISDN subsystem options when you configure your kernel for
-compilation. You currently also need to enable
-"Prompt for development and/or incomplete code/drivers" from the
-"Code maturity level options" menu. For the x25trace utility to work
-you also need to enable "Packet socket".
-
-For local testing it is also recommended to enable the isdnloop driver
-from the isdn subsystem's configuration menu.
-
-For testing, it is recommended that all isdn drivers and the X.25 PLP
-protocol are compiled as loadable modules. Like this, you can recover
-from certain errors by simply unloading and reloading the modules.
-
-
-
-What's it for? How to use it?
-=============================
-
-X.25 on top of isdn might be useful with two different scenarios:
-
-- You might want to access a public X.25 data network from your Linux box.
- You can use i4l if you were physically connected to the X.25 switch
- by an ISDN B-channel (leased line as well as dial up connection should
- work).
-
- This corresponds to ITU-T recommendation X.31 Case A (circuit-mode
- access to PSPDN [packet switched public data network]).
-
- NOTE: X.31 also covers a Case B (access to PSPDN via virtual
- circuit / packet mode service). The latter mode (which in theory
- also allows using the D-channel) is not supported by isdn4linux.
- It should however be possible to establish such packet mode connections
- with certain active isdn cards provided that the firmware supports X.31
- and the driver exports this functionality to the user. Currently,
- the AVM B1 driver is the only driver which does so. (It should be
- possible to access D-channel X.31 with active AVM cards using the
- CAPI interface of the AVM-B1 driver).
-
-- Or you might want to operate certain ISDN teleservices on your linux
- box. A lot of those teleservices run on top of the ISO-8208
- (DTE-DTE mode) network layer protocol. ISO-8208 is essentially the
- same as ITU-T X.25.
-
- Popular candidates of such teleservices are EUROfile transfer or any
- teleservice applying ITU-T recommendation T.90.
-
-To use the X.25 protocol on top of isdn, just create an isdn network
-interface as usual, configure your own and/or peer's ISDN numbers,
-and choose x25iface encapsulation by
-
- isdnctrl encap <iface-name> x25iface.
-
-Once encap is set like this, the device can be used by the X.25 packet layer.
-
-All the stuff needed for X.25 is implemented inside the isdn link
-level (mainly isdn_net.c and some new source files). Thus, it should
-work with every existing HL driver. I was able to successfully open X.25
-connections on top of the isdnloop driver and the hisax driver.
-"x25iface"-encapsulation bypasses demand dialing. Dialing will be
-initiated when the upper (X.25 packet) layer requests the lapb datalink to
-be established. But hangup timeout is still active. Whenever a hangup
-occurs, all existing X.25 connections on that link will be cleared
-It is recommended to use sufficiently large hangup-timeouts for the
-isdn interfaces.
-
-
-In order to set up a conforming protocol stack you also need to
-specify the proper l2_prot parameter:
-
-To operate in ISO-8208 X.25 DTE-DTE mode, use
-
- isdnctrl l2_prot <iface-name> x75i
-
-To access an X.25 network switch via isdn (your linux box is the DTE), use
-
- isdnctrl l2_prot <iface-name> x25dte
-
-To mimic an X.25 network switch (DCE side of the connection), use
-
- isdnctrl l2_prot <iface-name> x25dce
-
-However, x25dte or x25dce is currently not supported by any real HL
-level driver. The main difference between x75i and x25dte/dce is that
-x25d[tc]e uses fixed lap_b addresses. With x75i, the side which
-initiates the isdn connection uses the DTE's lap_b address while the
-called side used the DCE's lap_b address. Thus, l2_prot x75i might
-probably work if you access a public X.25 network as long as the
-corresponding isdn connection is set up by you. At least one test
-was successful to connect via isdn4linux to an X.25 switch using this
-trick. At the switch side, a terminal adapter X.21 was used to connect
-it to the isdn.
-
-
-How to set up a test installation?
-==================================
-
-To test X.25 on top of isdn, you need to get
-
-- a recent version of the "isdnctrl" program that supports setting the new
- X.25 specific parameters.
-
-- the x25-utils-2.X package from
- ftp://ftp.hes.iki.fi/pub/ham/linux/ax25/x25utils-*
- (don't confuse the x25-utils with the ax25-utils)
-
-- an application program that uses linux PF_X25 sockets (some are
- contained in the x25-util package).
-
-Before compiling the user level utilities make sure that the compiler/
-preprocessor will fetch the proper kernel header files of this kernel
-source tree. Either make /usr/include/linux a symbolic link pointing to
-this kernel's include/linux directory or set the appropriate compiler flags.
-
-When all drivers and interfaces are loaded and configured you need to
-ifconfig the network interfaces up and add X.25-routes to them. Use
-the usual ifconfig tool.
-
-ifconfig <iface-name> up
-
-But a special x25route tool (distributed with the x25-util package)
-is needed to set up X.25 routes. I.e.
-
-x25route add 01 <iface-name>
-
-will cause all x.25 connections to the destination X.25-address
-"01" to be routed to your created isdn network interface.
-
-There are currently no real X.25 applications available. However, for
-tests, the x25-utils package contains a modified version of telnet
-and telnetd that uses X.25 sockets instead of tcp/ip sockets. You can
-use those for your first tests. Furthermore, you might check
-ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/ which contains some
-alpha-test implementation ("eftp4linux") of the EUROfile transfer
-protocol.
-
-The scripts distributed with the eftp4linux test releases might also
-provide useful examples for setting up X.25 on top of isdn.
-
-The x25-utility package also contains an x25trace tool that can be
-used to monitor X.25 packets received by the network interfaces.
-The /proc/net/x25* files also contain useful information.
-
-- Henner
+++ /dev/null
-simple isdn4linux PPP FAQ .. to be continued .. not 'debugged'
--------------------------------------------------------------------
-
-Q01: what's pppd, ipppd, syncPPP, asyncPPP ??
-Q02: error message "this system lacks PPP support"
-Q03: strange information using 'ifconfig'
-Q04: MPPP?? What's that and how can I use it ...
-Q05: I tried MPPP but it doesn't work
-Q06: can I use asynchronous PPP encapsulation with network devices
-Q07: A SunISDN machine can't connect to my i4l system
-Q08: I wanna talk to several machines, which need different configs
-Q09: Starting the ipppd, I get only error messages from i4l
-Q10: I wanna use dynamic IP address assignment
-Q11: I can't connect. How can I check where the problem is.
-Q12: How can I reduce login delay?
-
--------------------------------------------------------------------
-
-Q01: pppd, ipppd, syncPPP, asyncPPP .. what is that ?
- what should I use?
-A: The pppd is for asynchronous PPP .. asynchronous means
- here, the framing is character based. (e.g when
- using ttyI* or tty* devices)
-
- The ipppd handles PPP packets coming in HDLC
- frames (bit based protocol) ... The PPP driver
- in isdn4linux pushes all IP packets direct
- to the network layer and all PPP protocol
- frames to the /dev/ippp* device.
- So, the ipppd is a simple external network
- protocol handler.
-
- If you login into a remote machine using the
- /dev/ttyI* devices and then enable PPP on the
- remote terminal server -> use the 'old' pppd
-
- If your remote side immediately starts to send
- frames ... you probably connect to a
- syncPPP machine .. use the network device part
- of isdn4linux with the 'syncppp' encapsulation
- and make sure, that the ipppd is running and
- connected to at least one /dev/ippp*. Check the
- isdn4linux manual on how to configure a network device.
-
---
-
-Q02: when I start the ipppd .. I only get the
- error message "this system lacks PPP support"
-A: check that at least the device 'ippp0' exists.
- (you can check this e.g with the program 'ifconfig')
- The ipppd NEEDS this device under THIS name ..
- If this device doesn't exists, use:
- isdnctrl addif ippp0
- isdnctrl encap ippp0 syncppp
- ... (see isdn4linux doc for more) ...
-A: Maybe you have compiled the ipppd with another
- kernel source tree than the kernel you currently
- run ...
-
---
-
-Q03: when I list the netdevices with ifconfig I see, that
- my ISDN interface has a HWaddr and IRQ=0 and Base
- address = 0
-A: The device is a fake ethernet device .. ignore IRQ and baseaddr
- You need the HWaddr only for ethernet encapsulation.
-
---
-
-Q04: MPPP?? What's that and how can I use it ...
-
-A: MPPP or MP or MPP (Warning: MP is also an
- acronym for 'Multi Processor') stands for
- Multi Point to Point and means bundling
- of several channels to one logical stream.
- To enable MPPP negotiation you must call the
- ipppd with the '+mp' option.
- You must also configure a slave device for
- every additional channel. (see the i4l manual
- for more)
- To use channel bundling you must first activate
- the 'master' or initial call. Now you can add
- the slave channels with the command:
- isdnctrl addlink <device>
- e.g:
- isdnctrl addlink ippp0
- This is different from other encapsulations of
- isdn4linux! With syncPPP, there is no automatic
- activation of slave devices.
-
---
-
-Q05: I tried MPPP but it doesn't work .. the ipppd
- writes in the debug log something like:
- .. rcvd [0][proto=0x3d] c0 00 00 00 80 fd 01 01 00 0a ...
- .. sent [0][LCP ProtRej id=0x2 00 3d c0 00 00 00 80 fd 01 ...
-
-A: you forgot to compile MPPP/RFC1717 support into the
- ISDN Subsystem. Recompile with this option enabled.
-
---
-
-Q06: can I use asynchronous PPP encapsulation
- over the network interface of isdn4linux ..
-
-A: No .. that's not possible .. Use the standard
- PPP package over the /dev/ttyI* devices. You
- must not use the ipppd for this.
-
---
-
-Q07: A SunISDN machine tries to connect my i4l system,
- which doesn't work.
- Checking the debug log I just saw garbage like:
-!![ ... fill in the line ... ]!!
-
-A: The Sun tries to talk asynchronous PPP ... i4l
- can't understand this ... try to use the ttyI*
- devices with the standard PPP/pppd package
-
-A: (from Alexanter Strauss: )
-!![ ... fill in mail ]!!
-
---
-
-Q08: I wanna talk to remote machines, which need
- a different configuration. The only way
- I found to do this is to kill the ipppd and
- start a new one with another config to connect
- to the second machine.
-
-A: you must bind a network interface explicitly to
- an ippp device, where you can connect a (for this
- interface) individually configured ipppd.
-
---
-
-Q09: When I start the ipppd I only get error messages
- from the i4l driver ..
-
-A: When starting, the ipppd calls functions which may
- trigger a network packet. (e.g gethostbyname()).
- Without the ipppd (at this moment, it is not
- fully started) we can't handle this network request.
- Try to configure hostnames necessary for the ipppd
- in your local /etc/hosts file or in a way, that
- your system can resolve it without using an
- isdn/ippp network-interface.
-
---
-
-Q10: I wanna use dynamic IP address assignment ... How
- must I configure the network device.
-
-A: At least you must have a route which forwards
- a packet to the ippp network-interface to trigger
- the dial-on-demand.
- A default route to the ippp-interface will work.
- Now you must choose a dummy IP address for your
- interface.
- If for some reason you can't set the default
- route to the ippp interface, you may take any
- address of the subnet from which you expect your
- dynamic IP number and set a 'network route' for
- this subnet to the ippp interface.
- To allow overriding of the dummy address you
- must call the ipppd with the 'ipcp-accept-local' option.
-
-A: You must know, how the ipppd gets the addresses it wanna
- configure. If you don't give any option, the ipppd
- tries to negotiate the local host address!
- With the option 'noipdefault' it requests an address
- from the remote machine. With 'useifip' it gets the
- addresses from the net interface. Or you set the address
- on the option line with the <a.b.c.d:e.f.g.h> option.
- Note: the IP address of the remote machine must be configured
- locally or the remote machine must send it in an IPCP request.
- If your side doesn't know the IP address after negotiation, it
- closes the connection!
- You must allow overriding of address with the 'ipcp-accept-*'
- options, if you have set your own or the remote address
- explicitly.
-
-A: Maybe you try these options .. e.g:
-
- /sbin/ipppd :$REMOTE noipdefault /dev/ippp0
-
- where REMOTE must be the address of the remote machine (the
- machine, which gives you your address)
-
---
-
-Q11: I can't connect. How can I check where the problem is.
-
-A: A good help log is the debug output from the ipppd...
- Check whether you can find there:
- - only a few LCP-conf-req SENT messages (less then 10)
- and then a Term-REQ:
- -> check whether your ISDN card is well configured
- it seems, that your machine doesn't dial
- (IRQ,IO,Proto, etc problems)
- Configure your ISDN card to print debug messages and
- check the /dev/isdnctrl output next time. There
- you can see, whether there is activity on the card/line.
- - there are at least a few RECV messages in the log:
- -> fine: your card is dialing and your remote machine
- tries to talk with you. Maybe only a missing
- authentication. Check your ipppd configuration again.
- - the ipppd exits for some reason:
- -> not good ... check /var/adm/syslog and /var/adm/daemon.
- Could be a bug in the ipppd.
-
---
-
-Q12: How can I reduce login delay?
-
-A: Log a login session ('debug' log) and check which options
- your remote side rejects. Next time configure your ipppd
- to not negotiate these options. Another 'side effect' is, that
- this increases redundancy. (e.g your remote side is buggy and
- rejects options in a wrong way).
-
-
-
Again, keep in mind that this list assumes you are already functionally
running a Linux kernel. Also, not all tools are necessary on all
-systems; obviously, if you don't have any ISDN hardware, for example,
-you probably needn't concern yourself with isdn4k-utils.
+systems; obviously, if you don't have any PC Card hardware, for example,
+you probably needn't concern yourself with pcmciautils.
====================== =============== ========================================
Program Minimal version Command to check the version
pcmciautils 004 pccardctl -V
quota-tools 3.09 quota -V
PPP 2.4.0 pppd --version
-isdn4k-utils 3.1pre1 isdnctrl 2>&1|grep version
nfs-utils 1.0.5 showmount --version
procps 3.2.0 ps --version
oprofile 0.9 oprofiled --version
as root.
-Isdn4k-utils
-------------
-
-Due to changes in the length of the phone number field, isdn4k-utils
-needs to be recompiled or (preferably) upgraded.
-
NFS-utils
---------
- <ftp://ftp.samba.org/pub/ppp/>
-Isdn4k-utils
-------------
-
-- <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/>
-
NFS-utils
---------
S: Maintained
F: Documentation/isdn/
F: drivers/isdn/
-F: include/linux/isdn.h
F: include/linux/isdn/
-F: include/uapi/linux/isdn.h
F: include/uapi/linux/isdn/
IT87 HARDWARE MONITORING DRIVER
if ISDN
-menuconfig ISDN_I4L
- tristate "Old ISDN4Linux (deprecated)"
- depends on TTY
- ---help---
- This driver allows you to use an ISDN adapter for networking
- connections and as dialin/out device. The isdn-tty's have a built
- in AT-compatible modem emulator. Network devices support autodial,
- channel-bundling, callback and caller-authentication without having
- a daemon running. A reduced T.70 protocol is supported with tty's
- suitable for German BTX. On D-Channel, the protocols EDSS1
- (Euro-ISDN) and 1TR6 (German style) are supported. See
- <file:Documentation/isdn/README> for more information.
-
- ISDN support in the linux kernel is moving towards a new API,
- called CAPI (Common ISDN Application Programming Interface).
- Therefore the old ISDN4Linux layer will eventually become obsolete.
- It is still available, though, for use with adapters that are not
- supported by the new CAPI subsystem yet.
-
-source "drivers/isdn/i4l/Kconfig"
-
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
help
source "drivers/isdn/mISDN/Kconfig"
-config ISDN_HDLC
- tristate
- select CRC_CCITT
- select BITREVERSE
-
endif # ISDN
obj-$(CONFIG_ISDN_CAPI) += capi/
obj-$(CONFIG_MISDN) += mISDN/
obj-$(CONFIG_ISDN) += hardware/
-obj-$(CONFIG_ISDN_DIVERSION) += divert/
-obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
obj-$(CONFIG_HYSDN) += hysdn/
obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/
device. If you want to use pppd with pppdcapiplugin to dial up to
your ISP, say Y here.
-config ISDN_CAPI_CAPIDRV
- tristate "CAPI2.0 capidrv interface support"
- depends on ISDN_I4L
- help
- This option provides the glue code to hook up CAPI driven cards to
- the legacy isdn4linux link layer. If you have a card which is
- supported by a CAPI driver, but still want to use old features like
- ippp interfaces or ttyI emulation, say Y/M here.
-
config ISDN_CAPI_CAPIDRV_VERBOSE
bool "Verbose reason code reporting"
depends on ISDN_CAPI_CAPIDRV
+++ /dev/null
-/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
- *
- * ISDN4Linux Driver, using capi20 interface (kernelcapi)
- *
- * Copyright 1997 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/signal.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/skbuff.h>
-#include <linux/isdn.h>
-#include <linux/isdnif.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/capi.h>
-#include <linux/kernelcapi.h>
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-
-#include <linux/isdn/capiutil.h>
-#include <linux/isdn/capicmd.h>
-#include "capidrv.h"
-
-static int debugmode = 0;
-
-MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-module_param(debugmode, uint, S_IRUGO | S_IWUSR);
-
-/* -------- type definitions ----------------------------------------- */
-
-
-struct capidrv_contr {
-
- struct capidrv_contr *next;
- struct module *owner;
- u32 contrnr;
- char name[20];
-
- /*
- * for isdn4linux
- */
- isdn_if interface;
- int myid;
-
- /*
- * LISTEN state
- */
- int state;
- u32 cipmask;
- u32 cipmask2;
- struct timer_list listentimer;
-
- /*
- * ID of capi message sent
- */
- u16 msgid;
-
- /*
- * B-Channels
- */
- int nbchan;
- struct capidrv_bchan {
- struct capidrv_contr *contr;
- u8 msn[ISDN_MSNLEN];
- int l2;
- int l3;
- u8 num[ISDN_MSNLEN];
- u8 mynum[ISDN_MSNLEN];
- int si1;
- int si2;
- int incoming;
- int disconnecting;
- struct capidrv_plci {
- struct capidrv_plci *next;
- u32 plci;
- u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
- u16 msgid; /* to identfy CONNECT_CONF */
- int chan;
- int state;
- int leasedline;
- struct capidrv_ncci {
- struct capidrv_ncci *next;
- struct capidrv_plci *plcip;
- u32 ncci;
- u16 msgid; /* to identfy CONNECT_B3_CONF */
- int chan;
- int state;
- int oldstate;
- /* */
- u16 datahandle;
- struct ncci_datahandle_queue {
- struct ncci_datahandle_queue *next;
- u16 datahandle;
- int len;
- } *ackqueue;
- } *ncci_list;
- } *plcip;
- struct capidrv_ncci *nccip;
- } *bchans;
-
- struct capidrv_plci *plci_list;
-
- /* for q931 data */
- u8 q931_buf[4096];
- u8 *q931_read;
- u8 *q931_write;
- u8 *q931_end;
-};
-
-
-struct capidrv_data {
- struct capi20_appl ap;
- int ncontr;
- struct capidrv_contr *contr_list;
-};
-
-typedef struct capidrv_plci capidrv_plci;
-typedef struct capidrv_ncci capidrv_ncci;
-typedef struct capidrv_contr capidrv_contr;
-typedef struct capidrv_data capidrv_data;
-typedef struct capidrv_bchan capidrv_bchan;
-
-/* -------- data definitions ----------------------------------------- */
-
-static capidrv_data global;
-static DEFINE_SPINLOCK(global_lock);
-
-static void handle_dtrace_data(capidrv_contr *card,
- int send, int level2, u8 *data, u16 len);
-
-/* -------- convert functions ---------------------------------------- */
-
-static inline u32 b1prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- return 0;
- case ISDN_PROTO_L2_HDLC:
- default:
- return 0;
- case ISDN_PROTO_L2_TRANS:
- return 1;
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- return 2;
- case ISDN_PROTO_L2_FAX:
- return 4;
- case ISDN_PROTO_L2_MODEM:
- return 8;
- }
-}
-
-static inline u32 b2prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- default:
- return 0;
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- case ISDN_PROTO_L2_MODEM:
- return 1;
- case ISDN_PROTO_L2_FAX:
- return 4;
- }
-}
-
-static inline u32 b3prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- case ISDN_PROTO_L2_MODEM:
- default:
- return 0;
- case ISDN_PROTO_L2_FAX:
- return 4;
- }
-}
-
-static _cstruct b1config_async_v110(u16 rate)
-{
- /* CAPI-Spec "B1 Configuration" */
- static unsigned char buf[9];
- buf[0] = 8; /* len */
- /* maximum bitrate */
- buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
- buf[3] = 8; buf[4] = 0; /* 8 bits per character */
- buf[5] = 0; buf[6] = 0; /* parity none */
- buf[7] = 0; buf[8] = 0; /* 1 stop bit */
- return buf;
-}
-
-static _cstruct b1config(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- default:
- return NULL;
- case ISDN_PROTO_L2_V11096:
- return b1config_async_v110(9600);
- case ISDN_PROTO_L2_V11019:
- return b1config_async_v110(19200);
- case ISDN_PROTO_L2_V11038:
- return b1config_async_v110(38400);
- }
-}
-
-static inline u16 si2cip(u8 si1, u8 si2)
-{
- static const u8 cip[17][5] =
- {
- /* 0 1 2 3 4 */
- {0, 0, 0, 0, 0}, /*0 */
- {16, 16, 4, 26, 16}, /*1 */
- {17, 17, 17, 4, 4}, /*2 */
- {2, 2, 2, 2, 2}, /*3 */
- {18, 18, 18, 18, 18}, /*4 */
- {2, 2, 2, 2, 2}, /*5 */
- {0, 0, 0, 0, 0}, /*6 */
- {2, 2, 2, 2, 2}, /*7 */
- {2, 2, 2, 2, 2}, /*8 */
- {21, 21, 21, 21, 21}, /*9 */
- {19, 19, 19, 19, 19}, /*10 */
- {0, 0, 0, 0, 0}, /*11 */
- {0, 0, 0, 0, 0}, /*12 */
- {0, 0, 0, 0, 0}, /*13 */
- {0, 0, 0, 0, 0}, /*14 */
- {22, 22, 22, 22, 22}, /*15 */
- {27, 27, 27, 28, 27} /*16 */
- };
- if (si1 > 16)
- si1 = 0;
- if (si2 > 4)
- si2 = 0;
-
- return (u16) cip[si1][si2];
-}
-
-static inline u8 cip2si1(u16 cipval)
-{
- static const u8 si[32] =
- {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
- 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
- 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
- 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
-
- if (cipval > 31)
- cipval = 0; /* .... */
- return si[cipval];
-}
-
-static inline u8 cip2si2(u16 cipval)
-{
- static const u8 si[32] =
- {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
- 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
- 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
- 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
-
- if (cipval > 31)
- cipval = 0; /* .... */
- return si[cipval];
-}
-
-
-/* -------- controller management ------------------------------------- */
-
-static inline capidrv_contr *findcontrbydriverid(int driverid)
-{
- unsigned long flags;
- capidrv_contr *p;
-
- spin_lock_irqsave(&global_lock, flags);
- for (p = global.contr_list; p; p = p->next)
- if (p->myid == driverid)
- break;
- spin_unlock_irqrestore(&global_lock, flags);
- return p;
-}
-
-static capidrv_contr *findcontrbynumber(u32 contr)
-{
- unsigned long flags;
- capidrv_contr *p = global.contr_list;
-
- spin_lock_irqsave(&global_lock, flags);
- for (p = global.contr_list; p; p = p->next)
- if (p->contrnr == contr)
- break;
- spin_unlock_irqrestore(&global_lock, flags);
- return p;
-}
-
-
-/* -------- plci management ------------------------------------------ */
-
-static capidrv_plci *new_plci(capidrv_contr *card, int chan)
-{
- capidrv_plci *plcip;
-
- plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
-
- if (plcip == NULL)
- return NULL;
-
- plcip->state = ST_PLCI_NONE;
- plcip->plci = 0;
- plcip->msgid = 0;
- plcip->chan = chan;
- plcip->next = card->plci_list;
- card->plci_list = plcip;
- card->bchans[chan].plcip = plcip;
-
- return plcip;
-}
-
-static capidrv_plci *find_plci_by_plci(capidrv_contr *card, u32 plci)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->plci == plci)
- return p;
- return NULL;
-}
-
-static capidrv_plci *find_plci_by_msgid(capidrv_contr *card, u16 msgid)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->msgid == msgid)
- return p;
- return NULL;
-}
-
-static capidrv_plci *find_plci_by_ncci(capidrv_contr *card, u32 ncci)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->plci == (ncci & 0xffff))
- return p;
- return NULL;
-}
-
-static void free_plci(capidrv_contr *card, capidrv_plci *plcip)
-{
- capidrv_plci **pp;
-
- for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
- if (*pp == plcip) {
- *pp = (*pp)->next;
- card->bchans[plcip->chan].plcip = NULL;
- card->bchans[plcip->chan].disconnecting = 0;
- card->bchans[plcip->chan].incoming = 0;
- kfree(plcip);
- return;
- }
- }
- printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
- card->contrnr, plcip, plcip->plci);
-}
-
-/* -------- ncci management ------------------------------------------ */
-
-static inline capidrv_ncci *new_ncci(capidrv_contr *card,
- capidrv_plci *plcip,
- u32 ncci)
-{
- capidrv_ncci *nccip;
-
- nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
-
- if (nccip == NULL)
- return NULL;
-
- nccip->ncci = ncci;
- nccip->state = ST_NCCI_NONE;
- nccip->plcip = plcip;
- nccip->chan = plcip->chan;
- nccip->datahandle = 0;
-
- nccip->next = plcip->ncci_list;
- plcip->ncci_list = nccip;
-
- card->bchans[plcip->chan].nccip = nccip;
-
- return nccip;
-}
-
-static inline capidrv_ncci *find_ncci(capidrv_contr *card, u32 ncci)
-{
- capidrv_plci *plcip;
- capidrv_ncci *p;
-
- if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
- return NULL;
-
- for (p = plcip->ncci_list; p; p = p->next)
- if (p->ncci == ncci)
- return p;
- return NULL;
-}
-
-static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr *card,
- u32 ncci, u16 msgid)
-{
- capidrv_plci *plcip;
- capidrv_ncci *p;
-
- if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
- return NULL;
-
- for (p = plcip->ncci_list; p; p = p->next)
- if (p->msgid == msgid)
- return p;
- return NULL;
-}
-
-static void free_ncci(capidrv_contr *card, struct capidrv_ncci *nccip)
-{
- struct capidrv_ncci **pp;
-
- for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
- if (*pp == nccip) {
- *pp = (*pp)->next;
- break;
- }
- }
- card->bchans[nccip->chan].nccip = NULL;
- kfree(nccip);
-}
-
-static int capidrv_add_ack(struct capidrv_ncci *nccip,
- u16 datahandle, int len)
-{
- struct ncci_datahandle_queue *n, **pp;
-
- n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
- if (!n) {
- printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
- return -1;
- }
- n->next = NULL;
- n->datahandle = datahandle;
- n->len = len;
- for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next);
- *pp = n;
- return 0;
-}
-
-static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
-{
- struct ncci_datahandle_queue **pp, *p;
- int len;
-
- for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
- if ((*pp)->datahandle == datahandle) {
- p = *pp;
- len = p->len;
- *pp = (*pp)->next;
- kfree(p);
- return len;
- }
- }
- return -1;
-}
-
-/* -------- convert and send capi message ---------------------------- */
-
-static void send_message(capidrv_contr *card, _cmsg *cmsg)
-{
- struct sk_buff *skb;
- size_t len;
-
- if (capi_cmsg2message(cmsg, cmsg->buf)) {
- printk(KERN_ERR "capidrv::send_message: parser failure\n");
- return;
- }
- len = CAPIMSG_LEN(cmsg->buf);
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
- return;
- }
- skb_put_data(skb, cmsg->buf, len);
- if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
- kfree_skb(skb);
-}
-
-/* -------- state machine -------------------------------------------- */
-
-struct listenstatechange {
- int actstate;
- int nextstate;
- int event;
-};
-
-static struct listenstatechange listentable[] =
-{
- {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
- {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
- {},
-};
-
-static void listen_change_state(capidrv_contr *card, int event)
-{
- struct listenstatechange *p = listentable;
- while (p->event) {
- if (card->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
- card->contrnr, card->state, p->nextstate);
- card->state = p->nextstate;
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
- card->contrnr, card->state, event);
-
-}
-
-/* ------------------------------------------------------------------ */
-
-static void p0(capidrv_contr *card, capidrv_plci *plci)
-{
- isdn_ctrl cmd;
-
- card->bchans[plci->chan].contr = NULL;
- cmd.command = ISDN_STAT_DHUP;
- cmd.driver = card->myid;
- cmd.arg = plci->chan;
- card->interface.statcallb(&cmd);
- free_plci(card, plci);
-}
-
-/* ------------------------------------------------------------------ */
-
-struct plcistatechange {
- int actstate;
- int nextstate;
- int event;
- void (*changefunc)(capidrv_contr *card, capidrv_plci *plci);
-};
-
-static struct plcistatechange plcitable[] =
-{
- /* P-0 */
- {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
- {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
- {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
- {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
- /* P-0.1 */
- {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
- {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
- /* P-1 */
- {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-ACT */
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
- /* P-2 */
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
- /* P-3 */
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-4 */
- {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-5 */
- {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-6 */
- {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
- /* P-0.Res */
- {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
- {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
- /* P-RES */
- {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
- /* P-HELD */
- {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
- {},
-};
-
-static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event)
-{
- struct plcistatechange *p = plcitable;
- while (p->event) {
- if (plci->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
- card->contrnr, plci->plci, plci->state, p->nextstate);
- plci->state = p->nextstate;
- if (p->changefunc)
- p->changefunc(card, plci);
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
- card->contrnr, plci->plci, plci->state, event);
-}
-
-/* ------------------------------------------------------------------ */
-
-static _cmsg cmsg;
-
-static void n0(capidrv_contr *card, capidrv_ncci *ncci)
-{
- isdn_ctrl cmd;
-
- capi_fill_DISCONNECT_REQ(&cmsg,
- global.ap.applid,
- card->msgid++,
- ncci->plcip->plci,
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */ /* $$$$ */
- NULL /* Facilitydataarray */
- );
- plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
- send_message(card, &cmsg);
-
- cmd.command = ISDN_STAT_BHUP;
- cmd.driver = card->myid;
- cmd.arg = ncci->chan;
- card->interface.statcallb(&cmd);
- free_ncci(card, ncci);
-}
-
-/* ------------------------------------------------------------------ */
-
-struct nccistatechange {
- int actstate;
- int nextstate;
- int event;
- void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci);
-};
-
-static struct nccistatechange nccitable[] =
-{
- /* N-0 */
- {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
- {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
- /* N-0.1 */
- {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
- {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
- /* N-1 */
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-2 */
- {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
- {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-ACT */
- {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-3 */
- {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
- {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-4 */
- {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL},
- /* N-5 */
- {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
- {},
-};
-
-static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event)
-{
- struct nccistatechange *p = nccitable;
- while (p->event) {
- if (ncci->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
- card->contrnr, ncci->ncci, ncci->state, p->nextstate);
- if (p->nextstate == ST_NCCI_PREVIOUS) {
- ncci->state = ncci->oldstate;
- ncci->oldstate = p->actstate;
- } else {
- ncci->oldstate = p->actstate;
- ncci->state = p->nextstate;
- }
- if (p->changefunc)
- p->changefunc(card, ncci);
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
- card->contrnr, ncci->ncci, ncci->state, event);
-}
-
-/* ------------------------------------------------------------------- */
-
-static inline int new_bchan(capidrv_contr *card)
-{
- int i;
- for (i = 0; i < card->nbchan; i++) {
- if (card->bchans[i].plcip == NULL) {
- card->bchans[i].disconnecting = 0;
- return i;
- }
- }
- return -1;
-}
-
-/* ------------------------------------------------------------------- */
-static char *capi_info2str(u16 reason)
-{
-#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE
- return "..";
-#else
- switch (reason) {
-
-/*-- informative values (corresponding message was processed) -----*/
- case 0x0001:
- return "NCPI not supported by current protocol, NCPI ignored";
- case 0x0002:
- return "Flags not supported by current protocol, flags ignored";
- case 0x0003:
- return "Alert already sent by another application";
-
-/*-- error information concerning CAPI_REGISTER -----*/
- case 0x1001:
- return "Too many applications";
- case 0x1002:
- return "Logical block size too small, must be at least 128 Bytes";
- case 0x1003:
- return "Buffer exceeds 64 kByte";
- case 0x1004:
- return "Message buffer size too small, must be at least 1024 Bytes";
- case 0x1005:
- return "Max. number of logical connections not supported";
- case 0x1006:
- return "Reserved";
- case 0x1007:
- return "The message could not be accepted because of an internal busy condition";
- case 0x1008:
- return "OS resource error (no memory ?)";
- case 0x1009:
- return "CAPI not installed";
- case 0x100A:
- return "Controller does not support external equipment";
- case 0x100B:
- return "Controller does only support external equipment";
-
-/*-- error information concerning message exchange functions -----*/
- case 0x1101:
- return "Illegal application number";
- case 0x1102:
- return "Illegal command or subcommand or message length less than 12 bytes";
- case 0x1103:
- return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
- case 0x1104:
- return "Queue is empty";
- case 0x1105:
- return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
- case 0x1106:
- return "Unknown notification parameter";
- case 0x1107:
- return "The Message could not be accepted because of an internal busy condition";
- case 0x1108:
- return "OS Resource error (no memory ?)";
- case 0x1109:
- return "CAPI not installed";
- case 0x110A:
- return "Controller does not support external equipment";
- case 0x110B:
- return "Controller does only support external equipment";
-
-/*-- error information concerning resource / coding problems -----*/
- case 0x2001:
- return "Message not supported in current state";
- case 0x2002:
- return "Illegal Controller / PLCI / NCCI";
- case 0x2003:
- return "Out of PLCI";
- case 0x2004:
- return "Out of NCCI";
- case 0x2005:
- return "Out of LISTEN";
- case 0x2006:
- return "Out of FAX resources (protocol T.30)";
- case 0x2007:
- return "Illegal message parameter coding";
-
-/*-- error information concerning requested services -----*/
- case 0x3001:
- return "B1 protocol not supported";
- case 0x3002:
- return "B2 protocol not supported";
- case 0x3003:
- return "B3 protocol not supported";
- case 0x3004:
- return "B1 protocol parameter not supported";
- case 0x3005:
- return "B2 protocol parameter not supported";
- case 0x3006:
- return "B3 protocol parameter not supported";
- case 0x3007:
- return "B protocol combination not supported";
- case 0x3008:
- return "NCPI not supported";
- case 0x3009:
- return "CIP Value unknown";
- case 0x300A:
- return "Flags not supported (reserved bits)";
- case 0x300B:
- return "Facility not supported";
- case 0x300C:
- return "Data length not supported by current protocol";
- case 0x300D:
- return "Reset procedure not supported by current protocol";
-
-/*-- informations about the clearing of a physical connection -----*/
- case 0x3301:
- return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
- case 0x3302:
- return "Protocol error layer 2";
- case 0x3303:
- return "Protocol error layer 3";
- case 0x3304:
- return "Another application got that call";
-/*-- T.30 specific reasons -----*/
- case 0x3311:
- return "Connecting not successful (remote station is no FAX G3 machine)";
- case 0x3312:
- return "Connecting not successful (training error)";
- case 0x3313:
- return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
- case 0x3314:
- return "Disconnected during transfer (remote abort)";
- case 0x3315:
- return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
- case 0x3316:
- return "Disconnected during transfer (local tx data underrun)";
- case 0x3317:
- return "Disconnected during transfer (local rx data overflow)";
- case 0x3318:
- return "Disconnected during transfer (local abort)";
- case 0x3319:
- return "Illegal parameter coding (e.g. SFF coding error)";
-
-/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
- case 0x3481: return "Unallocated (unassigned) number";
- case 0x3482: return "No route to specified transit network";
- case 0x3483: return "No route to destination";
- case 0x3486: return "Channel unacceptable";
- case 0x3487:
- return "Call awarded and being delivered in an established channel";
- case 0x3490: return "Normal call clearing";
- case 0x3491: return "User busy";
- case 0x3492: return "No user responding";
- case 0x3493: return "No answer from user (user alerted)";
- case 0x3495: return "Call rejected";
- case 0x3496: return "Number changed";
- case 0x349A: return "Non-selected user clearing";
- case 0x349B: return "Destination out of order";
- case 0x349C: return "Invalid number format";
- case 0x349D: return "Facility rejected";
- case 0x349E: return "Response to STATUS ENQUIRY";
- case 0x349F: return "Normal, unspecified";
- case 0x34A2: return "No circuit / channel available";
- case 0x34A6: return "Network out of order";
- case 0x34A9: return "Temporary failure";
- case 0x34AA: return "Switching equipment congestion";
- case 0x34AB: return "Access information discarded";
- case 0x34AC: return "Requested circuit / channel not available";
- case 0x34AF: return "Resources unavailable, unspecified";
- case 0x34B1: return "Quality of service unavailable";
- case 0x34B2: return "Requested facility not subscribed";
- case 0x34B9: return "Bearer capability not authorized";
- case 0x34BA: return "Bearer capability not presently available";
- case 0x34BF: return "Service or option not available, unspecified";
- case 0x34C1: return "Bearer capability not implemented";
- case 0x34C2: return "Channel type not implemented";
- case 0x34C5: return "Requested facility not implemented";
- case 0x34C6: return "Only restricted digital information bearer capability is available";
- case 0x34CF: return "Service or option not implemented, unspecified";
- case 0x34D1: return "Invalid call reference value";
- case 0x34D2: return "Identified channel does not exist";
- case 0x34D3: return "A suspended call exists, but this call identity does not";
- case 0x34D4: return "Call identity in use";
- case 0x34D5: return "No call suspended";
- case 0x34D6: return "Call having the requested call identity has been cleared";
- case 0x34D8: return "Incompatible destination";
- case 0x34DB: return "Invalid transit network selection";
- case 0x34DF: return "Invalid message, unspecified";
- case 0x34E0: return "Mandatory information element is missing";
- case 0x34E1: return "Message type non-existent or not implemented";
- case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
- case 0x34E3: return "Information element non-existent or not implemented";
- case 0x34E4: return "Invalid information element contents";
- case 0x34E5: return "Message not compatible with call state";
- case 0x34E6: return "Recovery on timer expiry";
- case 0x34EF: return "Protocol error, unspecified";
- case 0x34FF: return "Interworking, unspecified";
-
- default: return "No additional information";
- }
-#endif
-}
-
-static void handle_controller(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_LISTEN_CONF: /* Controller */
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
- card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
- if (cmsg->Info) {
- listen_change_state(card, EV_LISTEN_CONF_ERROR);
- } else if (card->cipmask == 0) {
- listen_change_state(card, EV_LISTEN_CONF_EMPTY);
- } else {
- listen_change_state(card, EV_LISTEN_CONF_OK);
- }
- break;
-
- case CAPI_MANUFACTURER_IND: /* Controller */
- if (cmsg->ManuID == 0x214D5641
- && cmsg->Class == 0
- && cmsg->Function == 1) {
- u8 *data = cmsg->ManuData + 3;
- u16 len = cmsg->ManuData[0];
- u16 layer;
- int direction;
- if (len == 255) {
- len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
- data += 2;
- }
- len -= 2;
- layer = ((*(data - 1)) << 8) | *(data - 2);
- if (layer & 0x300)
- direction = (layer & 0x200) ? 0 : 1;
- else direction = (layer & 0x800) ? 0 : 1;
- if (layer & 0x0C00) {
- if ((layer & 0xff) == 0x80) {
- handle_dtrace_data(card, direction, 1, data, len);
- break;
- }
- } else if ((layer & 0xff) < 0x80) {
- handle_dtrace_data(card, direction, 0, data, len);
- break;
- }
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController, layer);
- break;
- }
- goto ignored;
- case CAPI_MANUFACTURER_CONF: /* Controller */
- if (cmsg->ManuID == 0x214D5641) {
- char *s = NULL;
- switch (cmsg->Class) {
- case 0: break;
- case 1: s = "unknown class"; break;
- case 2: s = "unknown function"; break;
- default: s = "unknown error"; break;
- }
- if (s)
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController,
- cmsg->Function, s);
- break;
- }
- goto ignored;
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_INFO_IND: /* Controller/plci */
- goto ignored;
- case CAPI_INFO_CONF: /* Controller/plci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController);
- }
- return;
-
-ignored:
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController);
-}
-
-static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg)
-{
- capidrv_plci *plcip;
- capidrv_bchan *bchan;
- isdn_ctrl cmd;
- int chan;
-
- if ((chan = new_bchan(card)) == -1) {
- printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
- return;
- }
- bchan = &card->bchans[chan];
- if ((plcip = new_plci(card, chan)) == NULL) {
- printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
- return;
- }
- bchan->incoming = 1;
- plcip->plci = cmsg->adr.adrPLCI;
- plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
-
- cmd.command = ISDN_STAT_ICALL;
- cmd.driver = card->myid;
- cmd.arg = chan;
- memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
- strncpy(cmd.parm.setup.phone,
- cmsg->CallingPartyNumber + 3,
- cmsg->CallingPartyNumber[0] - 2);
- strncpy(cmd.parm.setup.eazmsn,
- cmsg->CalledPartyNumber + 2,
- cmsg->CalledPartyNumber[0] - 1);
- cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
- cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
- cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
- cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
-
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
-
- if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
- printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
- card->contrnr,
- cmd.parm.setup.si2);
- cmd.parm.setup.si2 = 0;
- }
-
- switch (card->interface.statcallb(&cmd)) {
- case 0:
- case 3:
- /* No device matching this call.
- * and isdn_common.c has send a HANGUP command
- * which is ignored in state ST_PLCI_INCOMING,
- * so we send RESP to ignore the call
- */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 1; /* ignore */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- break;
- case 1:
- /* At least one device matching this call (RING on ttyI)
- * HL-driver may send ALERTING on the D-channel in this
- * case.
- * really means: RING on ttyI or a net interface
- * accepted this call already.
- *
- * If the call was accepted, state has already changed,
- * and CONNECT_RESP already sent.
- */
- if (plcip->state == ST_PLCI_INCOMING) {
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- capi_fill_ALERT_REQ(cmsg,
- global.ap.applid,
- card->msgid++,
- plcip->plci, /* adr */
- NULL,/* BChannelinformation */
- NULL,/* Keypadfacility */
- NULL,/* Useruserdata */
- NULL /* Facilitydataarray */
- );
- plcip->msgid = cmsg->Messagenumber;
- send_message(card, cmsg);
- } else {
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- }
- break;
-
- case 2: /* Call will be rejected. */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 2; /* reject call, normal call clearing */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- break;
-
- default:
- /* An error happened. (Invalid parameters for example.) */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 8; /* reject call,
- destination out of order */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- break;
- }
- return;
-}
-
-static void handle_plci(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_plci *plcip;
- isdn_ctrl cmd;
- _cdebbuf *cdb;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_DISCONNECT_IND: /* plci */
- if (cmsg->Reason) {
- printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- goto notfound;
- }
- card->bchans[plcip->chan].disconnecting = 1;
- plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
- capi_cmsg_answer(cmsg);
- plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
- send_message(card, cmsg);
- break;
-
- case CAPI_DISCONNECT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- card->bchans[plcip->chan].disconnecting = 1;
- break;
-
- case CAPI_ALERT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- break;
-
- case CAPI_CONNECT_IND: /* plci */
- handle_incoming_call(card, cmsg);
- break;
-
- case CAPI_CONNECT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
- goto notfound;
-
- plcip->plci = cmsg->adr.adrPLCI;
- if (cmsg->Info) {
- plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
- } else {
- plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
- }
- break;
-
- case CAPI_CONNECT_ACTIVE_IND: /* plci */
-
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- if (card->bchans[plcip->chan].incoming) {
- capi_cmsg_answer(cmsg);
- plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
- send_message(card, cmsg);
- } else {
- capidrv_ncci *nccip;
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
-
- nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
-
- if (!nccip) {
- printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
- break; /* $$$$ */
- }
- capi_fill_CONNECT_B3_REQ(cmsg,
- global.ap.applid,
- card->msgid++,
- plcip->plci, /* adr */
- NULL /* NCPI */
- );
- nccip->msgid = cmsg->Messagenumber;
- plci_change_state(card, plcip,
- EV_PLCI_CONNECT_ACTIVE_IND);
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
- send_message(card, cmsg);
- cmd.command = ISDN_STAT_DCONN;
- cmd.driver = card->myid;
- cmd.arg = plcip->chan;
- card->interface.statcallb(&cmd);
- }
- break;
-
- case CAPI_INFO_IND: /* Controller/plci */
-
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- if (cmsg->InfoNumber == 0x4000) {
- if (cmsg->InfoElement[0] == 4) {
- cmd.command = ISDN_STAT_CINF;
- cmd.driver = card->myid;
- cmd.arg = plcip->chan;
- sprintf(cmd.parm.num, "%lu",
- (unsigned long)
- ((u32) cmsg->InfoElement[1]
- | ((u32) (cmsg->InfoElement[2]) << 8)
- | ((u32) (cmsg->InfoElement[3]) << 16)
- | ((u32) (cmsg->InfoElement[4]) << 24)));
- card->interface.statcallb(&cmd);
- break;
- }
- }
- cdb = capi_cmsg2str(cmsg);
- if (cdb) {
- printk(KERN_WARNING "capidrv-%d: %s\n",
- card->contrnr, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
- card->contrnr, cmsg->InfoNumber);
-
- break;
-
- case CAPI_CONNECT_ACTIVE_CONF: /* plci */
- goto ignored;
- case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
- goto ignored;
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
-
- case CAPI_INFO_CONF: /* Controller/plci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- }
- return;
-ignored:
- printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- return;
-notfound:
- printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- return;
-}
-
-static void handle_ncci(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_plci *plcip;
- capidrv_ncci *nccip;
- isdn_ctrl cmd;
- int len;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- capi_cmsg_answer(cmsg);
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
- send_message(card, cmsg);
-
- cmd.command = ISDN_STAT_BCONN;
- cmd.driver = card->myid;
- cmd.arg = nccip->chan;
- card->interface.statcallb(&cmd);
-
- printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
- card->contrnr, nccip->chan, nccip->ncci);
- break;
-
- case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
- goto ignored;
-
- case CAPI_CONNECT_B3_IND: /* ncci */
-
- plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
- if (plcip) {
- nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
- if (nccip) {
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
- capi_fill_CONNECT_B3_RESP(cmsg,
- global.ap.applid,
- card->msgid++,
- nccip->ncci, /* adr */
- 0, /* Reject */
- NULL /* NCPI */
- );
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
- send_message(card, cmsg);
- break;
- }
- printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
- } else {
- printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- }
- capi_fill_CONNECT_B3_RESP(cmsg,
- global.ap.applid,
- card->msgid++,
- cmsg->adr.adrNCCI,
- 2, /* Reject */
- NULL /* NCPI */
- );
- send_message(card, cmsg);
- break;
-
- case CAPI_CONNECT_B3_CONF: /* ncci */
-
- if (!(nccip = find_ncci_by_msgid(card,
- cmsg->adr.adrNCCI,
- cmsg->Messagenumber)))
- goto notfound;
-
- nccip->ncci = cmsg->adr.adrNCCI;
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrNCCI);
- }
-
- if (cmsg->Info)
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
- else
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
- break;
-
- case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- break;
-
- case CAPI_DATA_B3_IND: /* ncci */
- /* handled in handle_data() */
- goto ignored;
-
- case CAPI_DATA_B3_CONF: /* ncci */
- if (cmsg->Info) {
- printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
- cmsg->Info, capi_info2str(cmsg->Info));
- }
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- len = capidrv_del_ack(nccip, cmsg->DataHandle);
- if (len < 0)
- break;
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = nccip->chan;
- cmd.parm.length = len;
- card->interface.statcallb(&cmd);
- break;
-
- case CAPI_DISCONNECT_B3_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- card->bchans[nccip->chan].disconnecting = 1;
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
- capi_cmsg_answer(cmsg);
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
- send_message(card, cmsg);
- break;
-
- case CAPI_DISCONNECT_B3_CONF: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrNCCI);
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
- }
- break;
-
- case CAPI_RESET_B3_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
- ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- break;
-
- case CAPI_RESET_B3_CONF: /* ncci */
- goto ignored; /* $$$$ */
-
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- }
- return;
-ignored:
- printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- return;
-notfound:
- printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
-}
-
-
-static void handle_data(_cmsg *cmsg, struct sk_buff *skb)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_ncci *nccip;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- kfree_skb(skb);
- return;
- }
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
- printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- kfree_skb(skb);
- return;
- }
- (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
- card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
-}
-
-static _cmsg s_cmsg;
-
-static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
-{
- if (capi_message2cmsg(&s_cmsg, skb->data)) {
- printk(KERN_ERR "capidrv: applid=%d: received invalid message\n",
- ap->applid);
- kfree_skb(skb);
- return;
- }
- if (debugmode > 3) {
- _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
-
- if (cdb) {
- printk(KERN_DEBUG "%s: applid=%d %s\n", __func__,
- ap->applid, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
- __func__, ap->applid,
- capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
- }
- if (s_cmsg.Command == CAPI_DATA_B3
- && s_cmsg.Subcommand == CAPI_IND) {
- handle_data(&s_cmsg, skb);
- return;
- }
- if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
- handle_controller(&s_cmsg);
- else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
- handle_plci(&s_cmsg);
- else
- handle_ncci(&s_cmsg);
- /*
- * data of skb used in s_cmsg,
- * free data when s_cmsg is not used again
- * thanks to Lars Heete <hel@admin.de>
- */
- kfree_skb(skb);
-}
-
-/* ------------------------------------------------------------------- */
-
-#define PUTBYTE_TO_STATUS(card, byte) \
- do { \
- *(card)->q931_write++ = (byte); \
- if ((card)->q931_write > (card)->q931_end) \
- (card)->q931_write = (card)->q931_buf; \
- } while (0)
-
-static void handle_dtrace_data(capidrv_contr *card,
- int send, int level2, u8 *data, u16 len)
-{
- u8 *p, *end;
- isdn_ctrl cmd;
-
- if (!len) {
- printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
- card->contrnr, len);
- return;
- }
-
- if (level2) {
- PUTBYTE_TO_STATUS(card, 'D');
- PUTBYTE_TO_STATUS(card, '2');
- PUTBYTE_TO_STATUS(card, send ? '>' : '<');
- PUTBYTE_TO_STATUS(card, ':');
- } else {
- PUTBYTE_TO_STATUS(card, 'D');
- PUTBYTE_TO_STATUS(card, '3');
- PUTBYTE_TO_STATUS(card, send ? '>' : '<');
- PUTBYTE_TO_STATUS(card, ':');
- }
-
- for (p = data, end = data + len; p < end; p++) {
- PUTBYTE_TO_STATUS(card, ' ');
- PUTBYTE_TO_STATUS(card, hex_asc_hi(*p));
- PUTBYTE_TO_STATUS(card, hex_asc_lo(*p));
- }
- PUTBYTE_TO_STATUS(card, '\n');
-
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = len * 3 + 5;
- card->interface.statcallb(&cmd);
-}
-
-/* ------------------------------------------------------------------- */
-
-static _cmsg cmdcmsg;
-
-static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card)
-{
- switch (c->arg) {
- case 1:
- debugmode = (int)(*((unsigned int *)c->parm.num));
- printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
- card->contrnr, debugmode);
- return 0;
- default:
- printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
- card->contrnr, c->arg);
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-/*
- * Handle leased lines (CAPI-Bundling)
- */
-
-struct internal_bchannelinfo {
- unsigned short channelalloc;
- unsigned short operation;
- unsigned char cmask[31];
-};
-
-static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
-{
- unsigned long bmask = 0;
- int active = !0;
- char *s;
- int i;
-
- if (strncmp(teln, "FV:", 3) != 0)
- return 1;
- s = teln + 3;
- while (*s && *s == ' ') s++;
- if (!*s) return -2;
- if (*s == 'p' || *s == 'P') {
- active = 0;
- s++;
- }
- if (*s == 'a' || *s == 'A') {
- active = !0;
- s++;
- }
- while (*s) {
- int digit1 = 0;
- int digit2 = 0;
- char *endp;
-
- digit1 = simple_strtoul(s, &endp, 10);
- if (s == endp)
- return -3;
- s = endp;
-
- if (digit1 <= 0 || digit1 > 30) return -4;
- if (*s == 0 || *s == ',' || *s == ' ') {
- bmask |= (1 << digit1);
- digit1 = 0;
- if (*s) s++;
- continue;
- }
- if (*s != '-') return -5;
- s++;
-
- digit2 = simple_strtoul(s, &endp, 10);
- if (s == endp)
- return -3;
- s = endp;
-
- if (digit2 <= 0 || digit2 > 30) return -4;
- if (*s == 0 || *s == ',' || *s == ' ') {
- if (digit1 > digit2)
- for (i = digit2; i <= digit1; i++)
- bmask |= (1 << i);
- else
- for (i = digit1; i <= digit2; i++)
- bmask |= (1 << i);
- digit1 = digit2 = 0;
- if (*s) s++;
- continue;
- }
- return -6;
- }
- if (activep) *activep = active;
- if (bmaskp) *bmaskp = bmask;
- return 0;
-}
-
-static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31])
-{
- unsigned long bmask;
- int active;
- int rc, i;
-
- rc = decodeFVteln(teln, &bmask, &active);
- if (rc) return rc;
- /* Length */
- AdditionalInfo[0] = 2 + 2 + 31;
- /* Channel: 3 => use channel allocation */
- AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
- /* Operation: 0 => DTE mode, 1 => DCE mode */
- if (active) {
- AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
- } else {
- AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
- }
- /* Channel mask array */
- AdditionalInfo[5] = 0; /* no D-Channel */
- for (i = 1; i <= 30; i++)
- AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0;
- return 0;
-}
-
-static int capidrv_command(isdn_ctrl *c, capidrv_contr *card)
-{
- isdn_ctrl cmd;
- struct capidrv_bchan *bchan;
- struct capidrv_plci *plcip;
- u8 AdditionalInfo[1 + 2 + 2 + 31];
- int rc, isleasedline = 0;
-
- if (c->command == ISDN_CMD_IOCTL)
- return capidrv_ioctl(c, card);
-
- switch (c->command) {
- case ISDN_CMD_DIAL: {
- u8 calling[ISDN_MSNLEN + 3];
- u8 called[ISDN_MSNLEN + 2];
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
- card->contrnr,
- c->arg,
- c->parm.setup.phone,
- c->parm.setup.si1,
- c->parm.setup.si2,
- c->parm.setup.eazmsn);
-
- bchan = &card->bchans[c->arg % card->nbchan];
-
- if (bchan->plcip) {
- printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
- card->contrnr,
- c->arg,
- c->parm.setup.phone,
- c->parm.setup.si1,
- c->parm.setup.si2,
- c->parm.setup.eazmsn,
- bchan->plcip->plci);
- return 0;
- }
- bchan->si1 = c->parm.setup.si1;
- bchan->si2 = c->parm.setup.si2;
-
- strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
- strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
- rc = FVteln2capi20(bchan->num, AdditionalInfo);
- isleasedline = (rc == 0);
- if (rc < 0)
- printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
-
- if (isleasedline) {
- calling[0] = 0;
- called[0] = 0;
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
- } else {
- calling[0] = strlen(bchan->mynum) + 2;
- calling[1] = 0;
- calling[2] = 0x80;
- strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
- called[0] = strlen(bchan->num) + 1;
- called[1] = 0x80;
- strncpy(called + 2, bchan->num, ISDN_MSNLEN);
- }
-
- capi_fill_CONNECT_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- card->contrnr, /* adr */
- si2cip(bchan->si1, bchan->si2), /* cipvalue */
- called, /* CalledPartyNumber */
- calling, /* CallingPartyNumber */
- NULL, /* CalledPartySubaddress */
- NULL, /* CallingPartySubaddress */
- b1prot(bchan->l2, bchan->l3), /* B1protocol */
- b2prot(bchan->l2, bchan->l3), /* B2protocol */
- b3prot(bchan->l2, bchan->l3), /* B3protocol */
- b1config(bchan->l2, bchan->l3), /* B1configuration */
- NULL, /* B2configuration */
- NULL, /* B3configuration */
- NULL, /* BC */
- NULL, /* LLC */
- NULL, /* HLC */
- /* BChannelinformation */
- isleasedline ? AdditionalInfo : NULL,
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) {
- cmd.command = ISDN_STAT_DHUP;
- cmd.driver = card->myid;
- cmd.arg = (c->arg % card->nbchan);
- card->interface.statcallb(&cmd);
- return -1;
- }
- plcip->msgid = cmdcmsg.Messagenumber;
- plcip->leasedline = isleasedline;
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- }
-
- case ISDN_CMD_ACCEPTD:
-
- bchan = &card->bchans[c->arg % card->nbchan];
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
- card->contrnr,
- c->arg, bchan->l2, bchan->l3);
-
- capi_fill_CONNECT_RESP(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->plcip->plci, /* adr */
- 0, /* Reject */
- b1prot(bchan->l2, bchan->l3), /* B1protocol */
- b2prot(bchan->l2, bchan->l3), /* B2protocol */
- b3prot(bchan->l2, bchan->l3), /* B3protocol */
- b1config(bchan->l2, bchan->l3), /* B1configuration */
- NULL, /* B2configuration */
- NULL, /* B3configuration */
- NULL, /* ConnectedNumber */
- NULL, /* ConnectedSubaddress */
- NULL, /* LLC */
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- if (capi_cmsg2message(&cmdcmsg, cmdcmsg.buf)) {
- printk(KERN_ERR "capidrv-%d: capidrv_command: parser failure\n",
- card->contrnr);
- return -EINVAL;
- }
- plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
- send_message(card, &cmdcmsg);
- return 0;
-
- case ISDN_CMD_ACCEPTB:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
- card->contrnr,
- c->arg);
- return -ENOSYS;
-
- case ISDN_CMD_HANGUP:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
- card->contrnr,
- c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
-
- if (bchan->disconnecting) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
- card->contrnr,
- c->arg);
- return 0;
- }
- if (bchan->nccip) {
- bchan->disconnecting = 1;
- capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->nccip->ncci,
- NULL /* NCPI */
- );
- ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- } else if (bchan->plcip) {
- if (bchan->plcip->state == ST_PLCI_INCOMING) {
- /*
- * just ignore, we a called from
- * isdn_status_callback(),
- * which will return 0 or 2, this is handled
- * by the CONNECT_IND handler
- */
- bchan->disconnecting = 1;
- return 0;
- } else if (bchan->plcip->plci) {
- bchan->disconnecting = 1;
- capi_fill_DISCONNECT_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->plcip->plci,
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- } else {
- printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
- card->contrnr,
- c->arg);
- return -EINVAL;
- }
- }
- printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
- card->contrnr,
- c->arg);
- return -EINVAL;
-/* ready */
-
- case ISDN_CMD_SETL2:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
- card->contrnr,
- (c->arg & 0xff), (c->arg >> 8));
- bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
- bchan->l2 = (c->arg >> 8);
- return 0;
-
- case ISDN_CMD_SETL3:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
- card->contrnr,
- (c->arg & 0xff), (c->arg >> 8));
- bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
- bchan->l3 = (c->arg >> 8);
- return 0;
-
- case ISDN_CMD_SETEAZ:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
- card->contrnr,
- c->parm.num, c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
- strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
- return 0;
-
- case ISDN_CMD_CLREAZ:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
- card->contrnr, c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
- bchan->msn[0] = 0;
- return 0;
-
- default:
- printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
- card->contrnr, c->command);
- return -EINVAL;
- }
- return 0;
-}
-
-static int if_command(isdn_ctrl *c)
-{
- capidrv_contr *card = findcontrbydriverid(c->driver);
-
- if (card)
- return capidrv_command(c, card);
-
- printk(KERN_ERR
- "capidrv: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
-}
-
-static _cmsg sendcmsg;
-
-static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
-{
- capidrv_contr *card = findcontrbydriverid(id);
- capidrv_bchan *bchan;
- capidrv_ncci *nccip;
- int len = skb->len;
- int msglen;
- u16 errcode;
- u16 datahandle;
- u32 data;
-
- if (!card) {
- printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
- id);
- return 0;
- }
- if (debugmode > 4)
- printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
- card->contrnr, len, skb, doack);
- bchan = &card->bchans[channel % card->nbchan];
- nccip = bchan->nccip;
- if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
- card->contrnr, card->name, channel);
- return 0;
- }
- datahandle = nccip->datahandle;
-
- /*
- * Here we copy pointer skb->data into the 32-bit 'Data' field.
- * The 'Data' field is not used in practice in linux kernel
- * (neither in 32 or 64 bit), but should have some value,
- * since a CAPI message trace will display it.
- *
- * The correct value in the 32 bit case is the address of the
- * data, in 64 bit it makes no sense, we use 0 there.
- */
-
-#ifdef CONFIG_64BIT
- data = 0;
-#else
- data = (unsigned long) skb->data;
-#endif
-
- capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
- nccip->ncci, /* adr */
- data, /* Data */
- skb->len, /* DataLength */
- datahandle, /* DataHandle */
- 0 /* Flags */
- );
-
- if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
- return 0;
-
- if (capi_cmsg2message(&sendcmsg, sendcmsg.buf)) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: parser failure\n",
- card->contrnr);
- return -EINVAL;
- }
- msglen = CAPIMSG_LEN(sendcmsg.buf);
- if (skb_headroom(skb) < msglen) {
- struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
- if (!nskb) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
- card->contrnr);
- (void)capidrv_del_ack(nccip, datahandle);
- return 0;
- }
- printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
- card->contrnr, skb_headroom(skb), msglen);
- memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
- errcode = capi20_put_message(&global.ap, nskb);
- if (errcode == CAPI_NOERROR) {
- dev_kfree_skb(skb);
- nccip->datahandle++;
- return len;
- }
- if (debugmode > 3)
- printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
- card->contrnr, errcode, capi_info2str(errcode));
- (void)capidrv_del_ack(nccip, datahandle);
- dev_kfree_skb(nskb);
- return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
- } else {
- memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
- errcode = capi20_put_message(&global.ap, skb);
- if (errcode == CAPI_NOERROR) {
- nccip->datahandle++;
- return len;
- }
- if (debugmode > 3)
- printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
- card->contrnr, errcode, capi_info2str(errcode));
- skb_pull(skb, msglen);
- (void)capidrv_del_ack(nccip, datahandle);
- return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
- }
-}
-
-static int if_readstat(u8 __user *buf, int len, int id, int channel)
-{
- capidrv_contr *card = findcontrbydriverid(id);
- int count;
- u8 __user *p;
-
- if (!card) {
- printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
- id);
- return -ENODEV;
- }
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (put_user(*card->q931_read++, p))
- return -EFAULT;
- if (card->q931_read > card->q931_end)
- card->q931_read = card->q931_buf;
- }
- return count;
-
-}
-
-static void enable_dchannel_trace(capidrv_contr *card)
-{
- u8 manufacturer[CAPI_MANUFACTURER_LEN];
- capi_version version;
- u16 contr = card->contrnr;
- u16 errcode;
- u16 avmversion[3];
-
- errcode = capi20_get_manufacturer(contr, manufacturer);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
- card->name, errcode);
- return;
- }
- if (strstr(manufacturer, "AVM") == NULL) {
- printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
- card->name, manufacturer);
- return;
- }
- errcode = capi20_get_version(contr, &version);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get version (0x%x)\n",
- card->name, errcode);
- return;
- }
- avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
- avmversion[1] = (version.majormanuversion << 4) & 0xf0;
- avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
- avmversion[2] |= version.minormanuversion & 0x0f;
-
- if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
- printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
- capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- contr,
- 0x214D5641, /* ManuID */
- 0, /* Class */
- 1, /* Function */
- (_cstruct)"\004\200\014\000\000");
- } else {
- printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
- capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- contr,
- 0x214D5641, /* ManuID */
- 0, /* Class */
- 1, /* Function */
- (_cstruct)"\004\002\003\000\000");
- }
- send_message(card, &cmdcmsg);
-}
-
-
-static void send_listen(capidrv_contr *card)
-{
- capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- card->contrnr, /* controller */
- 1 << 6, /* Infomask */
- card->cipmask,
- card->cipmask2,
- NULL, NULL);
- listen_change_state(card, EV_LISTEN_REQ);
- send_message(card, &cmdcmsg);
-}
-
-static void listentimerfunc(struct timer_list *t)
-{
- capidrv_contr *card = from_timer(card, t, listentimer);
- if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
- printk(KERN_ERR "%s: controller dead ??\n", card->name);
- send_listen(card);
- mod_timer(&card->listentimer, jiffies + 60 * HZ);
-}
-
-
-static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
-{
- capidrv_contr *card;
- unsigned long flags;
- isdn_ctrl cmd;
- char id[20];
- int i;
-
- sprintf(id, "capidrv-%d", contr);
- if (!try_module_get(THIS_MODULE)) {
- printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
- return -1;
- }
- if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
- printk(KERN_WARNING
- "capidrv: (%s) Could not allocate contr-struct.\n", id);
- return -1;
- }
- card->owner = THIS_MODULE;
- timer_setup(&card->listentimer, listentimerfunc, 0);
- strcpy(card->name, id);
- card->contrnr = contr;
- card->nbchan = profp->nbchannel;
- card->bchans = kmalloc_array(card->nbchan, sizeof(capidrv_bchan),
- GFP_ATOMIC);
- if (!card->bchans) {
- printk(KERN_WARNING
- "capidrv: (%s) Could not allocate bchan-structs.\n", id);
- module_put(card->owner);
- kfree(card);
- return -1;
- }
- card->interface.channels = profp->nbchannel;
- card->interface.maxbufsize = 2048;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = NULL;
- card->interface.readstat = if_readstat;
- card->interface.features =
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN |
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_X75UI |
- ISDN_FEATURE_L2_X75BUI;
- if (profp->support1 & (1 << 2))
- card->interface.features |=
- ISDN_FEATURE_L2_V11096 |
- ISDN_FEATURE_L2_V11019 |
- ISDN_FEATURE_L2_V11038;
- if (profp->support1 & (1 << 8))
- card->interface.features |= ISDN_FEATURE_L2_MODEM;
- card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
- strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
-
-
- card->q931_read = card->q931_buf;
- card->q931_write = card->q931_buf;
- card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
-
- if (!register_isdn(&card->interface)) {
- printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
- kfree(card->bchans);
- module_put(card->owner);
- kfree(card);
- return -1;
- }
- card->myid = card->interface.channels;
- memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
- for (i = 0; i < card->nbchan; i++) {
- card->bchans[i].contr = card;
- }
-
- spin_lock_irqsave(&global_lock, flags);
- card->next = global.contr_list;
- global.contr_list = card;
- global.ncontr++;
- spin_unlock_irqrestore(&global_lock, flags);
-
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- card->cipmask = 0x1FFF03FF; /* any */
- card->cipmask2 = 0;
-
- send_listen(card);
- mod_timer(&card->listentimer, jiffies + 60 * HZ);
-
- printk(KERN_INFO "%s: now up (%d B channels)\n",
- card->name, card->nbchan);
-
- enable_dchannel_trace(card);
-
- return 0;
-}
-
-static int capidrv_delcontr(u16 contr)
-{
- capidrv_contr **pp, *card;
- unsigned long flags;
- isdn_ctrl cmd;
-
- spin_lock_irqsave(&global_lock, flags);
- for (card = global.contr_list; card; card = card->next) {
- if (card->contrnr == contr)
- break;
- }
- if (!card) {
- spin_unlock_irqrestore(&global_lock, flags);
- printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
- return -1;
- }
-
- /* FIXME: maybe a race condition the card should be removed
- * here from global list /kkeil
- */
- spin_unlock_irqrestore(&global_lock, flags);
-
- del_timer(&card->listentimer);
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
- card->contrnr, card->myid);
-
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- while (card->nbchan) {
-
- cmd.command = ISDN_STAT_DISCH;
- cmd.driver = card->myid;
- cmd.arg = card->nbchan - 1;
- cmd.parm.num[0] = 0;
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
- card->contrnr, card->myid, cmd.arg);
- card->interface.statcallb(&cmd);
-
- if (card->bchans[card->nbchan - 1].nccip)
- free_ncci(card, card->bchans[card->nbchan - 1].nccip);
- if (card->bchans[card->nbchan - 1].plcip)
- free_plci(card, card->bchans[card->nbchan - 1].plcip);
- if (card->plci_list)
- printk(KERN_ERR "capidrv: bug in free_plci()\n");
- card->nbchan--;
- }
- kfree(card->bchans);
- card->bchans = NULL;
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
- card->contrnr, card->myid);
-
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
- card->contrnr, card->myid);
-
- spin_lock_irqsave(&global_lock, flags);
- for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
- if (*pp == card) {
- *pp = (*pp)->next;
- card->next = NULL;
- global.ncontr--;
- break;
- }
- }
- spin_unlock_irqrestore(&global_lock, flags);
-
- module_put(card->owner);
- printk(KERN_INFO "%s: now down.\n", card->name);
- kfree(card);
- return 0;
-}
-
-
-static int
-lower_callback(struct notifier_block *nb, unsigned long val, void *v)
-{
- capi_profile profile;
- u32 contr = (long)v;
-
- switch (val) {
- case CAPICTR_UP:
- printk(KERN_INFO "capidrv: controller %hu up\n", contr);
- if (capi20_get_profile(contr, &profile) == CAPI_NOERROR)
- (void) capidrv_addcontr(contr, &profile);
- break;
- case CAPICTR_DOWN:
- printk(KERN_INFO "capidrv: controller %hu down\n", contr);
- (void) capidrv_delcontr(contr);
- break;
- }
- return NOTIFY_OK;
-}
-
-/*
- * /proc/capi/capidrv:
- * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
- */
-static int __maybe_unused capidrv_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%lu %lu %lu %lu\n",
- global.ap.nrecvctlpkt,
- global.ap.nrecvdatapkt,
- global.ap.nsentctlpkt,
- global.ap.nsentdatapkt);
- return 0;
-}
-
-static void __init proc_init(void)
-{
- proc_create_single("capi/capidrv", 0, NULL, capidrv_proc_show);
-}
-
-static void __exit proc_exit(void)
-{
- remove_proc_entry("capi/capidrv", NULL);
-}
-
-static struct notifier_block capictr_nb = {
- .notifier_call = lower_callback,
-};
-
-static int __init capidrv_init(void)
-{
- capi_profile profile;
- u32 ncontr, contr;
- u16 errcode;
-
- global.ap.rparam.level3cnt = -2; /* number of bchannels twice */
- global.ap.rparam.datablkcnt = 16;
- global.ap.rparam.datablklen = 2048;
-
- global.ap.recv_message = capidrv_recv_message;
- errcode = capi20_register(&global.ap);
- if (errcode) {
- return -EIO;
- }
-
- register_capictr_notifier(&capictr_nb);
-
- errcode = capi20_get_profile(0, &profile);
- if (errcode != CAPI_NOERROR) {
- unregister_capictr_notifier(&capictr_nb);
- capi20_release(&global.ap);
- return -EIO;
- }
-
- ncontr = profile.ncontroller;
- for (contr = 1; contr <= ncontr; contr++) {
- errcode = capi20_get_profile(contr, &profile);
- if (errcode != CAPI_NOERROR)
- continue;
- (void) capidrv_addcontr(contr, &profile);
- }
- proc_init();
-
- return 0;
-}
-
-static void __exit capidrv_exit(void)
-{
- unregister_capictr_notifier(&capictr_nb);
- capi20_release(&global.ap);
-
- proc_exit();
-}
-
-module_init(capidrv_init);
-module_exit(capidrv_exit);
+++ /dev/null
-/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
- *
- * ISDN4Linux Driver, using capi20 interface (kernelcapi)
- *
- * Copyright 1997 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __CAPIDRV_H__
-#define __CAPIDRV_H__
-
-/*
- * LISTEN state machine
- */
-#define ST_LISTEN_NONE 0 /* L-0 */
-#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
-#define ST_LISTEN_ACTIVE 2 /* L-1 */
-#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
-
-
-#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
- L-1 -> L-1.1 */
-#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
- L-1.1 -> L-1 */
-#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
- L-1.1 -> L-0 */
-#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
- L-1.1 -> L.1 */
-
-/*
- * per plci state machine
- */
-#define ST_PLCI_NONE 0 /* P-0 */
-#define ST_PLCI_OUTGOING 1 /* P-0.1 */
-#define ST_PLCI_ALLOCATED 2 /* P-1 */
-#define ST_PLCI_ACTIVE 3 /* P-ACT */
-#define ST_PLCI_INCOMING 4 /* P-2 */
-#define ST_PLCI_FACILITY_IND 5 /* P-3 */
-#define ST_PLCI_ACCEPTING 6 /* P-4 */
-#define ST_PLCI_DISCONNECTING 7 /* P-5 */
-#define ST_PLCI_DISCONNECTED 8 /* P-6 */
-#define ST_PLCI_RESUMEING 9 /* P-0.Res */
-#define ST_PLCI_RESUME 10 /* P-Res */
-#define ST_PLCI_HELD 11 /* P-HELD */
-
-#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
- */
-#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
- */
-#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
- */
-#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
- */
-#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
- */
-#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
- */
-#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
- P-3 -> P-5
- */
-#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
- P-2 -> P-5
- P-3 -> P-5
- P-4 -> P-5
- P-ACT -> P-5
- P-Res -> P-5 (*)
- P-HELD -> P-5 (*)
- */
-#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
- P-2 -> P-6
- P-3 -> P-6
- P-4 -> P-6
- P-5 -> P-6
- P-ACT -> P-6
- P-Res -> P-6 (*)
- P-HELD -> P-6 (*)
- */
-#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
- P-1 -> P-5
- P-ACT -> P-5
- P-2 -> P-5
- P-3 -> P-5
- P-4 -> P-5
- */
-#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
- */
-#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
- */
-
-#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
- */
-#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
- */
-#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
- */
-#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
- */
-#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
- */
-#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
- */
-#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
- */
-#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
- */
-
-/*
- * per ncci state machine
- */
-#define ST_NCCI_PREVIOUS -1
-#define ST_NCCI_NONE 0 /* N-0 */
-#define ST_NCCI_OUTGOING 1 /* N-0.1 */
-#define ST_NCCI_INCOMING 2 /* N-1 */
-#define ST_NCCI_ALLOCATED 3 /* N-2 */
-#define ST_NCCI_ACTIVE 4 /* N-ACT */
-#define ST_NCCI_RESETING 5 /* N-3 */
-#define ST_NCCI_DISCONNECTING 6 /* N-4 */
-#define ST_NCCI_DISCONNECTED 7 /* N-5 */
-
-#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
-#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
-#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
-#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
-#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
-#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
-#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
-#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
-#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
-#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
-#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
-#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
- N-2 -> N-4
- N-3 -> N-4
- N-ACT -> N-4 */
-#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
-
-#endif /* __CAPIDRV_H__ */
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the dss1_divert ISDN module
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
-
-# Multipart objects.
-
-dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
+++ /dev/null
-/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
- *
- * Module init for DSS1 diversion services for i4l.
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include "isdn_divert.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
-MODULE_AUTHOR("Werner Cornelius");
-MODULE_LICENSE("GPL");
-
-/****************************************/
-/* structure containing interface to hl */
-/****************************************/
-isdn_divert_if divert_if = {
- DIVERT_IF_MAGIC, /* magic value */
- DIVERT_CMD_REG, /* register cmd */
- ll_callback, /* callback routine from ll */
- NULL, /* command still not specified */
- NULL, /* drv_to_name */
- NULL, /* name_to_drv */
-};
-
-/*************************/
-/* Module interface code */
-/* no cmd line parms */
-/*************************/
-static int __init divert_init(void)
-{
- int i;
-
- if (divert_dev_init()) {
- printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
- return (-EIO);
- }
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
- divert_dev_deinit();
- printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
- return (-EIO);
- }
- printk(KERN_INFO "dss1_divert module successfully installed\n");
- return (0);
-}
-
-/**********************/
-/* Module deinit code */
-/**********************/
-static void __exit divert_exit(void)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&divert_lock, flags);
- divert_if.cmd = DIVERT_CMD_REL; /* release */
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
- printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
- spin_unlock_irqrestore(&divert_lock, flags);
- return;
- }
- if (divert_dev_deinit()) {
- printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
- spin_unlock_irqrestore(&divert_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&divert_lock, flags);
- deleterule(-1); /* delete all rules and free mem */
- deleteprocs();
- printk(KERN_INFO "dss1_divert module successfully removed \n");
-}
-
-module_init(divert_init);
-module_exit(divert_exit);
+++ /dev/null
-/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
- *
- * Filesystem handling for the diversion supplementary services.
- *
- * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#else
-#include <linux/fs.h>
-#endif
-#include <linux/sched.h>
-#include <linux/isdnif.h>
-#include <net/net_namespace.h>
-#include <linux/mutex.h>
-#include "isdn_divert.h"
-
-
-/*********************************/
-/* Variables for interface queue */
-/*********************************/
-ulong if_used = 0; /* number of interface users */
-static DEFINE_MUTEX(isdn_divert_mutex);
-static struct divert_info *divert_info_head = NULL; /* head of queue */
-static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
-static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
-static wait_queue_head_t rd_queue;
-
-/*********************************/
-/* put an info buffer into queue */
-/*********************************/
-void
-put_info_buffer(char *cp)
-{
- struct divert_info *ib;
- unsigned long flags;
-
- if (if_used <= 0)
- return;
- if (!cp)
- return;
- if (!*cp)
- return;
- if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
- return; /* no memory */
- strcpy(ib->info_start, cp); /* set output string */
- ib->next = NULL;
- spin_lock_irqsave(&divert_info_lock, flags);
- ib->usage_cnt = if_used;
- if (!divert_info_head)
- divert_info_head = ib; /* new head */
- else
- divert_info_tail->next = ib; /* follows existing messages */
- divert_info_tail = ib; /* new tail */
-
- /* delete old entrys */
- while (divert_info_head->next) {
- if ((divert_info_head->usage_cnt <= 0) &&
- (divert_info_head->next->usage_cnt <= 0)) {
- ib = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(ib);
- } else
- break;
- } /* divert_info_head->next */
- spin_unlock_irqrestore(&divert_info_lock, flags);
- wake_up_interruptible(&(rd_queue));
-} /* put_info_buffer */
-
-#ifdef CONFIG_PROC_FS
-
-/**********************************/
-/* deflection device read routine */
-/**********************************/
-static ssize_t
-isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- struct divert_info *inf;
- int len;
-
- if (!(inf = *((struct divert_info **) file->private_data))) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- wait_event_interruptible(rd_queue, (inf =
- *((struct divert_info **) file->private_data)));
- }
- if (!inf)
- return (0);
-
- inf->usage_cnt--; /* new usage count */
- file->private_data = &inf->next; /* next structure */
- if ((len = strlen(inf->info_start)) <= count) {
- if (copy_to_user(buf, inf->info_start, len))
- return -EFAULT;
- *off += len;
- return (len);
- }
- return (0);
-} /* isdn_divert_read */
-
-/**********************************/
-/* deflection device write routine */
-/**********************************/
-static ssize_t
-isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- return (-ENODEV);
-} /* isdn_divert_write */
-
-
-/***************************************/
-/* select routines for various kernels */
-/***************************************/
-static __poll_t
-isdn_divert_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask = 0;
-
- poll_wait(file, &(rd_queue), wait);
- /* mask = EPOLLOUT | EPOLLWRNORM; */
- if (*((struct divert_info **) file->private_data)) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- return mask;
-} /* isdn_divert_poll */
-
-/****************/
-/* Open routine */
-/****************/
-static int
-isdn_divert_open(struct inode *ino, struct file *filep)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&divert_info_lock, flags);
- if_used++;
- if (divert_info_head)
- filep->private_data = &(divert_info_tail->next);
- else
- filep->private_data = &divert_info_head;
- spin_unlock_irqrestore(&divert_info_lock, flags);
- /* start_divert(); */
- return nonseekable_open(ino, filep);
-} /* isdn_divert_open */
-
-/*******************/
-/* close routine */
-/*******************/
-static int
-isdn_divert_close(struct inode *ino, struct file *filep)
-{
- struct divert_info *inf;
- unsigned long flags;
-
- spin_lock_irqsave(&divert_info_lock, flags);
- if_used--;
- inf = *((struct divert_info **) filep->private_data);
- while (inf) {
- inf->usage_cnt--;
- inf = inf->next;
- }
- if (if_used <= 0)
- while (divert_info_head) {
- inf = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(inf);
- }
- spin_unlock_irqrestore(&divert_info_lock, flags);
- return (0);
-} /* isdn_divert_close */
-
-/*********/
-/* IOCTL */
-/*********/
-static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg)
-{
- divert_ioctl dioctl;
- int i;
- unsigned long flags;
- divert_rule *rulep;
- char *cp;
-
- if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
- return -EFAULT;
-
- switch (cmd) {
- case IIOCGETVER:
- dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
- break;
-
- case IIOCGETDRV:
- if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
- return (-EINVAL);
- break;
-
- case IIOCGETNAM:
- cp = divert_if.drv_to_name(dioctl.getid.drvid);
- if (!cp)
- return (-EINVAL);
- if (!*cp)
- return (-EINVAL);
- strcpy(dioctl.getid.drvnam, cp);
- break;
-
- case IIOCGETRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return (-EINVAL);
- dioctl.getsetrule.rule = *rulep; /* copy data */
- break;
-
- case IIOCMODRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return (-EINVAL);
- spin_lock_irqsave(&divert_lock, flags);
- *rulep = dioctl.getsetrule.rule; /* copy data */
- spin_unlock_irqrestore(&divert_lock, flags);
- return (0); /* no copy required */
- break;
-
- case IIOCINSRULE:
- return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
- break;
-
- case IIOCDELRULE:
- return (deleterule(dioctl.getsetrule.ruleidx));
- break;
-
- case IIOCDODFACT:
- return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
- dioctl.fwd_ctrl.callid,
- dioctl.fwd_ctrl.to_nr));
-
- case IIOCDOCFACT:
- case IIOCDOCFDIS:
- case IIOCDOCFINT:
- if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
- return (-EINVAL); /* invalid driver */
- if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) ==
- sizeof(dioctl.cf_ctrl.msn))
- return -EINVAL;
- if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) ==
- sizeof(dioctl.cf_ctrl.fwd_nr))
- return -EINVAL;
- if ((i = cf_command(dioctl.cf_ctrl.drvid,
- (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
- dioctl.cf_ctrl.cfproc,
- dioctl.cf_ctrl.msn,
- dioctl.cf_ctrl.service,
- dioctl.cf_ctrl.fwd_nr,
- &dioctl.cf_ctrl.procid)))
- return (i);
- break;
-
- default:
- return (-EINVAL);
- } /* switch cmd */
- return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
-} /* isdn_divert_ioctl */
-
-static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg)
-{
- long ret;
-
- mutex_lock(&isdn_divert_mutex);
- ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
- mutex_unlock(&isdn_divert_mutex);
-
- return ret;
-}
-
-static const struct file_operations isdn_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = isdn_divert_read,
- .write = isdn_divert_write,
- .poll = isdn_divert_poll,
- .unlocked_ioctl = isdn_divert_ioctl,
- .open = isdn_divert_open,
- .release = isdn_divert_close,
-};
-
-/****************************/
-/* isdn subdir in /proc/net */
-/****************************/
-static struct proc_dir_entry *isdn_proc_entry = NULL;
-static struct proc_dir_entry *isdn_divert_entry = NULL;
-#endif /* CONFIG_PROC_FS */
-
-/***************************************************************************/
-/* divert_dev_init must be called before the proc filesystem may be used */
-/***************************************************************************/
-int
-divert_dev_init(void)
-{
-
- init_waitqueue_head(&rd_queue);
-
-#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
- if (!isdn_proc_entry)
- return (-1);
- isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
- isdn_proc_entry, &isdn_fops);
- if (!isdn_divert_entry) {
- remove_proc_entry("isdn", init_net.proc_net);
- return (-1);
- }
-#endif /* CONFIG_PROC_FS */
-
- return (0);
-} /* divert_dev_init */
-
-/***************************************************************************/
-/* divert_dev_deinit must be called before leaving isdn when included as */
-/* a module. */
-/***************************************************************************/
-int
-divert_dev_deinit(void)
-{
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("divert", isdn_proc_entry);
- remove_proc_entry("isdn", init_net.proc_net);
-#endif /* CONFIG_PROC_FS */
-
- return (0);
-} /* divert_dev_deinit */
+++ /dev/null
-/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
- *
- * DSS1 main diversion supplementary handling for i4l.
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-
-#include "isdn_divert.h"
-
-/**********************************/
-/* structure keeping calling info */
-/**********************************/
-struct call_struc {
- isdn_ctrl ics; /* delivered setup + driver parameters */
- ulong divert_id; /* Id delivered to user */
- unsigned char akt_state; /* actual state */
- char deflect_dest[35]; /* deflection destination */
- struct timer_list timer; /* timer control structure */
- char info[90]; /* device info output */
- struct call_struc *next; /* pointer to next entry */
- struct call_struc *prev;
-};
-
-
-/********************************************/
-/* structure keeping deflection table entry */
-/********************************************/
-struct deflect_struc {
- struct deflect_struc *next, *prev;
- divert_rule rule; /* used rule */
-};
-
-
-/*****************************************/
-/* variables for main diversion services */
-/*****************************************/
-/* diversion/deflection processes */
-static struct call_struc *divert_head = NULL; /* head of remembered entrys */
-static ulong next_id = 1; /* next info id */
-static struct deflect_struc *table_head = NULL;
-static struct deflect_struc *table_tail = NULL;
-static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
-
-DEFINE_SPINLOCK(divert_lock);
-
-/***************************/
-/* timer callback function */
-/***************************/
-static void deflect_timer_expire(struct timer_list *t)
-{
- unsigned long flags;
- struct call_struc *cs = from_timer(cs, t, timer);
-
- spin_lock_irqsave(&divert_lock, flags);
- del_timer(&cs->timer); /* delete active timer */
- spin_unlock_irqrestore(&divert_lock, flags);
-
- switch (cs->akt_state) {
- case DEFLECT_PROCEED:
- cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
- divert_if.ll_cmd(&cs->ics);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case DEFLECT_ALERT:
- cs->ics.command = ISDN_CMD_REDIR; /* protocol */
- strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
- strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed");
- divert_if.ll_cmd(&cs->ics);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case DEFLECT_AUTODEL:
- default:
- spin_lock_irqsave(&divert_lock, flags);
- if (cs->prev)
- cs->prev->next = cs->next; /* forward link */
- else
- divert_head = cs->next;
- if (cs->next)
- cs->next->prev = cs->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs);
- return;
-
- } /* switch */
-} /* deflect_timer_func */
-
-
-/*****************************************/
-/* handle call forwarding de/activations */
-/* 0 = deact, 1 = act, 2 = interrogate */
-/*****************************************/
-int cf_command(int drvid, int mode,
- u_char proc, char *msn,
- u_char service, char *fwd_nr, ulong *procid)
-{
- unsigned long flags;
- int retval, msnlen;
- int fwd_len;
- char *p, *ielenp, tmp[60];
- struct call_struc *cs;
-
- if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */
- if ((proc & 0x7F) > 2) return (-EINVAL);
- proc &= 3;
- p = tmp;
- *p++ = 0x30; /* enumeration */
- ielenp = p++; /* remember total length position */
- *p++ = 0xa; /* proc tag */
- *p++ = 1; /* length */
- *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
- *p++ = 0xa; /* service tag */
- *p++ = 1; /* length */
- *p++ = service; /* service to handle */
-
- if (mode == 1) {
- if (!*fwd_nr) return (-EINVAL); /* destination missing */
- if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
- fwd_len = strlen(fwd_nr);
- *p++ = 0x30; /* number enumeration */
- *p++ = fwd_len + 2; /* complete forward to len */
- *p++ = 0x80; /* fwd to nr */
- *p++ = fwd_len; /* length of number */
- strcpy(p, fwd_nr); /* copy number */
- p += fwd_len; /* pointer beyond fwd */
- } /* activate */
-
- msnlen = strlen(msn);
- *p++ = 0x80; /* msn number */
- if (msnlen > 1) {
- *p++ = msnlen; /* length */
- strcpy(p, msn);
- p += msnlen;
- } else
- *p++ = 0;
-
- *ielenp = p - ielenp - 1; /* set total IE length */
-
- /* allocate mem for information struct */
- if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
- return (-ENOMEM); /* no memory */
- timer_setup(&cs->timer, deflect_timer_expire, 0);
- cs->info[0] = '\0';
- cs->ics.driver = drvid;
- cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
- cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
- cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */
- cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
- cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
- cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
-
- spin_lock_irqsave(&divert_lock, flags);
- cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
- spin_unlock_irqrestore(&divert_lock, flags);
- *procid = cs->ics.parm.dss1_io.ll_id;
-
- sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
- (!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
- cs->ics.parm.dss1_io.ll_id,
- (mode != 2) ? "" : "0 ",
- divert_if.drv_to_name(cs->ics.driver),
- msn,
- service & 0xFF,
- proc,
- (mode != 1) ? "" : " 0 ",
- (mode != 1) ? "" : fwd_nr);
-
- retval = divert_if.ll_cmd(&cs->ics); /* execute command */
-
- if (!retval) {
- cs->prev = NULL;
- spin_lock_irqsave(&divert_lock, flags);
- cs->next = divert_head;
- divert_head = cs;
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- kfree(cs);
- return (retval);
-} /* cf_command */
-
-
-/****************************************/
-/* handle a external deflection command */
-/****************************************/
-int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
-{
- struct call_struc *cs;
- isdn_ctrl ic;
- unsigned long flags;
- int i;
-
- if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
- cs = divert_head; /* start of parameter list */
- while (cs) {
- if (cs->divert_id == callid) break; /* found */
- cs = cs->next;
- } /* search entry */
- if (!cs) return (-EINVAL); /* invalid callid */
-
- ic.driver = cs->ics.driver;
- ic.arg = cs->ics.arg;
- i = -EINVAL;
- if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
- switch (cmd & 0x7F) {
- case 0: /* hangup */
- del_timer(&cs->timer);
- ic.command = ISDN_CMD_HANGUP;
- i = divert_if.ll_cmd(&ic);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case 1: /* alert */
- if (cs->akt_state == DEFLECT_ALERT) return (0);
- cmd &= 0x7F; /* never wait */
- del_timer(&cs->timer);
- ic.command = ISDN_CMD_ALERT;
- if ((i = divert_if.ll_cmd(&ic))) {
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- cs->akt_state = DEFLECT_ALERT;
- break;
-
- case 2: /* redir */
- del_timer(&cs->timer);
- strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
- strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
- ic.command = ISDN_CMD_REDIR;
- if ((i = divert_if.ll_cmd(&ic))) {
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- cs->akt_state = DEFLECT_ALERT;
- break;
-
- } /* switch */
- return (i);
-} /* deflect_extern_action */
-
-/********************************/
-/* insert a new rule before idx */
-/********************************/
-int insertrule(int idx, divert_rule *newrule)
-{
- struct deflect_struc *ds, *ds1 = NULL;
- unsigned long flags;
-
- if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
- return (-ENOMEM); /* no memory */
-
- ds->rule = *newrule; /* set rule */
-
- spin_lock_irqsave(&divert_lock, flags);
-
- if (idx >= 0) {
- ds1 = table_head;
- while ((ds1) && (idx > 0))
- { idx--;
- ds1 = ds1->next;
- }
- if (!ds1) idx = -1;
- }
-
- if (idx < 0) {
- ds->prev = table_tail; /* previous entry */
- ds->next = NULL; /* end of chain */
- if (ds->prev)
- ds->prev->next = ds; /* last forward */
- else
- table_head = ds; /* is first entry */
- table_tail = ds; /* end of queue */
- } else {
- ds->next = ds1; /* next entry */
- ds->prev = ds1->prev; /* prev entry */
- ds1->prev = ds; /* backward chain old element */
- if (!ds->prev)
- table_head = ds; /* first element */
- }
-
- spin_unlock_irqrestore(&divert_lock, flags);
- return (0);
-} /* insertrule */
-
-/***********************************/
-/* delete the rule at position idx */
-/***********************************/
-int deleterule(int idx)
-{
- struct deflect_struc *ds, *ds1;
- unsigned long flags;
-
- if (idx < 0) {
- spin_lock_irqsave(&divert_lock, flags);
- ds = table_head;
- table_head = NULL;
- table_tail = NULL;
- spin_unlock_irqrestore(&divert_lock, flags);
- while (ds) {
- ds1 = ds;
- ds = ds->next;
- kfree(ds1);
- }
- return (0);
- }
-
- spin_lock_irqsave(&divert_lock, flags);
- ds = table_head;
-
- while ((ds) && (idx > 0)) {
- idx--;
- ds = ds->next;
- }
-
- if (!ds) {
- spin_unlock_irqrestore(&divert_lock, flags);
- return (-EINVAL);
- }
-
- if (ds->next)
- ds->next->prev = ds->prev; /* backward chain */
- else
- table_tail = ds->prev; /* end of chain */
-
- if (ds->prev)
- ds->prev->next = ds->next; /* forward chain */
- else
- table_head = ds->next; /* start of chain */
-
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(ds);
- return (0);
-} /* deleterule */
-
-/*******************************************/
-/* get a pointer to a specific rule number */
-/*******************************************/
-divert_rule *getruleptr(int idx)
-{
- struct deflect_struc *ds = table_head;
-
- if (idx < 0) return (NULL);
- while ((ds) && (idx >= 0)) {
- if (!(idx--)) {
- return (&ds->rule);
- break;
- }
- ds = ds->next;
- }
- return (NULL);
-} /* getruleptr */
-
-/*************************************************/
-/* called from common module on an incoming call */
-/*************************************************/
-static int isdn_divert_icall(isdn_ctrl *ic)
-{
- int retval = 0;
- unsigned long flags;
- struct call_struc *cs = NULL;
- struct deflect_struc *dv;
- char *p, *p1;
- u_char accept;
-
- /* first check the internal deflection table */
- for (dv = table_head; dv; dv = dv->next) {
- /* scan table */
- if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
- ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
- continue; /* call option check */
- if (!(dv->rule.drvid & (1L << ic->driver)))
- continue; /* driver not matching */
- if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
- continue; /* si1 not matching */
- if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
- continue; /* si2 not matching */
-
- p = dv->rule.my_msn;
- p1 = ic->parm.setup.eazmsn;
- accept = 0;
- while (*p) {
- /* complete compare */
- if (*p == '-') {
- accept = 1; /* call accepted */
- break;
- }
- if (*p++ != *p1++)
- break; /* not accepted */
- if ((!*p) && (!*p1))
- accept = 1;
- } /* complete compare */
- if (!accept) continue; /* not accepted */
-
- if ((strcmp(dv->rule.caller, "0")) ||
- (ic->parm.setup.phone[0])) {
- p = dv->rule.caller;
- p1 = ic->parm.setup.phone;
- accept = 0;
- while (*p) {
- /* complete compare */
- if (*p == '-') {
- accept = 1; /* call accepted */
- break;
- }
- if (*p++ != *p1++)
- break; /* not accepted */
- if ((!*p) && (!*p1))
- accept = 1;
- } /* complete compare */
- if (!accept) continue; /* not accepted */
- }
-
- switch (dv->rule.action) {
- case DEFLECT_IGNORE:
- return 0;
-
- case DEFLECT_ALERT:
- case DEFLECT_PROCEED:
- case DEFLECT_REPORT:
- case DEFLECT_REJECT:
- if (dv->rule.action == DEFLECT_PROCEED)
- if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
- return (0); /* no external deflection needed */
- if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
- return (0); /* no memory */
- timer_setup(&cs->timer, deflect_timer_expire, 0);
- cs->info[0] = '\0';
-
- cs->ics = *ic; /* copy incoming data */
- if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
- if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0");
- cs->ics.parm.setup.screen = dv->rule.screen;
- if (dv->rule.waittime)
- cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
- else if (dv->rule.action == DEFLECT_PROCEED)
- cs->timer.expires = jiffies + (HZ * extern_wait_max);
- else
- cs->timer.expires = 0;
- cs->akt_state = dv->rule.action;
- spin_lock_irqsave(&divert_lock, flags);
- cs->divert_id = next_id++; /* new sequence number */
- spin_unlock_irqrestore(&divert_lock, flags);
- cs->prev = NULL;
- if (cs->akt_state == DEFLECT_ALERT) {
- strcpy(cs->deflect_dest, dv->rule.to_nr);
- if (!cs->timer.expires) {
- strcpy(ic->parm.setup.eazmsn,
- "Testtext direct");
- ic->parm.setup.screen = dv->rule.screen;
- strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- retval = 5;
- } else
- retval = 1; /* alerting */
- } else {
- cs->deflect_dest[0] = '\0';
- retval = 4; /* only proceed */
- }
- snprintf(cs->info, sizeof(cs->info),
- "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
- cs->akt_state,
- cs->divert_id,
- divert_if.drv_to_name(cs->ics.driver),
- (ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
- cs->ics.parm.setup.phone,
- cs->ics.parm.setup.eazmsn,
- cs->ics.parm.setup.si1,
- cs->ics.parm.setup.si2,
- cs->ics.parm.setup.screen,
- dv->rule.waittime,
- cs->deflect_dest);
- if ((dv->rule.action == DEFLECT_REPORT) ||
- (dv->rule.action == DEFLECT_REJECT)) {
- put_info_buffer(cs->info);
- kfree(cs); /* remove */
- return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
- }
- break;
-
- default:
- return 0; /* ignore call */
- } /* switch action */
- break; /* will break the 'for' looping */
- } /* scan_table */
-
- if (cs) {
- cs->prev = NULL;
- spin_lock_irqsave(&divert_lock, flags);
- cs->next = divert_head;
- divert_head = cs;
- if (cs->timer.expires) add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
-
- put_info_buffer(cs->info);
- return (retval);
- } else
- return (0);
-} /* isdn_divert_icall */
-
-
-void deleteprocs(void)
-{
- struct call_struc *cs, *cs1;
- unsigned long flags;
-
- spin_lock_irqsave(&divert_lock, flags);
- cs = divert_head;
- divert_head = NULL;
- while (cs) {
- del_timer(&cs->timer);
- cs1 = cs;
- cs = cs->next;
- kfree(cs1);
- }
- spin_unlock_irqrestore(&divert_lock, flags);
-} /* deleteprocs */
-
-/****************************************************/
-/* put a address including address type into buffer */
-/****************************************************/
-static int put_address(char *st, u_char *p, int len)
-{
- u_char retval = 0;
- u_char adr_typ = 0; /* network standard */
-
- if (len < 2) return (retval);
- if (*p == 0xA1) {
- retval = *(++p) + 2; /* total length */
- if (retval > len) return (0); /* too short */
- len = retval - 2; /* remaining length */
- if (len < 3) return (0);
- if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0);
- adr_typ = *(++p);
- len -= 3;
- p++;
- if (len < 2) return (0);
- if (*p++ != 0x12) return (0);
- if (*p > len) return (0); /* check number length */
- len = *p++;
- } else if (*p == 0x80) {
- retval = *(++p) + 2; /* total length */
- if (retval > len) return (0);
- len = retval - 2;
- p++;
- } else
- return (0); /* invalid address information */
-
- sprintf(st, "%d ", adr_typ);
- st += strlen(st);
- if (!len)
- *st++ = '-';
- else
- while (len--)
- *st++ = *p++;
- *st = '\0';
- return (retval);
-} /* put_address */
-
-/*************************************/
-/* report a successful interrogation */
-/*************************************/
-static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
-{
- char *src = ic->parm.dss1_io.data;
- int restlen = ic->parm.dss1_io.datalen;
- int cnt = 1;
- u_char n, n1;
- char st[90], *p, *stp;
-
- if (restlen < 2) return (-100); /* frame too short */
- if (*src++ != 0x30) return (-101);
- if ((n = *src++) > 0x81) return (-102); /* invalid length field */
- restlen -= 2; /* remaining bytes */
- if (n == 0x80) {
- if (restlen < 2) return (-103);
- if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
- restlen -= 2;
- } else if (n == 0x81) {
- n = *src++;
- restlen--;
- if (n > restlen) return (-105);
- restlen = n;
- } else if (n > restlen)
- return (-106);
- else
- restlen = n; /* standard format */
- if (restlen < 3) return (-107); /* no procedure */
- if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
- restlen -= 3;
- if (restlen < 2) return (-109); /* list missing */
- if (*src == 0x31) {
- src++;
- if ((n = *src++) > 0x81) return (-110); /* invalid length field */
- restlen -= 2; /* remaining bytes */
- if (n == 0x80) {
- if (restlen < 2) return (-111);
- if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
- restlen -= 2;
- } else if (n == 0x81) {
- n = *src++;
- restlen--;
- if (n > restlen) return (-113);
- restlen = n;
- } else if (n > restlen)
- return (-114);
- else
- restlen = n; /* standard format */
- } /* result list header */
-
- while (restlen >= 2) {
- stp = st;
- sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
- cnt++, divert_if.drv_to_name(ic->driver));
- stp += strlen(stp);
- if (*src++ != 0x30) return (-115); /* invalid enum */
- n = *src++;
- restlen -= 2;
- if (n > restlen) return (-116); /* enum length wrong */
- restlen -= n;
- p = src; /* one entry */
- src += n;
- if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
- stp += strlen(stp);
- p += n1;
- n -= n1;
- if (n < 6) continue; /* no service and proc */
- if ((*p++ != 0x0A) || (*p++ != 1)) continue;
- sprintf(stp, " 0x%02x ", (*p++) & 0xFF);
- stp += strlen(stp);
- if ((*p++ != 0x0A) || (*p++ != 1)) continue;
- sprintf(stp, "%d ", (*p++) & 0xFF);
- stp += strlen(stp);
- n -= 6;
- if (n > 2) {
- if (*p++ != 0x30) continue;
- if (*p > (n - 2)) continue;
- n = *p++;
- if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
- stp += strlen(stp);
- }
- sprintf(stp, "\n");
- put_info_buffer(st);
- } /* while restlen */
- if (restlen) return (-117);
- return (0);
-} /* interrogate_success */
-
-/*********************************************/
-/* callback for protocol specific extensions */
-/*********************************************/
-static int prot_stat_callback(isdn_ctrl *ic)
-{
- struct call_struc *cs, *cs1;
- int i;
- unsigned long flags;
-
- cs = divert_head; /* start of list */
- cs1 = NULL;
- while (cs) {
- if (ic->driver == cs->ics.driver) {
- switch (cs->ics.arg) {
- case DSS1_CMD_INVOKE:
- if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
- (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
- switch (ic->arg) {
- case DSS1_STAT_INVOKE_ERR:
- sprintf(cs->info, "128 0x%lx 0x%x\n",
- ic->parm.dss1_io.ll_id,
- ic->parm.dss1_io.timeout);
- put_info_buffer(cs->info);
- break;
-
- case DSS1_STAT_INVOKE_RES:
- switch (cs->ics.parm.dss1_io.proc) {
- case 7:
- case 8:
- put_info_buffer(cs->info);
- break;
-
- case 11:
- i = interrogate_success(ic, cs);
- if (i)
- sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
- ic->parm.dss1_io.ll_id, i);
- put_info_buffer(cs->info);
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
- break;
- }
-
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
- break;
- }
- cs1 = cs; /* remember structure */
- cs = NULL;
- continue; /* abort search */
- } /* id found */
- break;
-
- case DSS1_CMD_INVOKE_ABORT:
- printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg);
- break;
- } /* switch ics.arg */
- cs = cs->next;
- } /* driver ok */
- }
-
- if (!cs1) {
- printk(KERN_WARNING "dss1_divert unhandled process\n");
- return (0);
- }
-
- if (cs1->ics.driver == -1) {
- spin_lock_irqsave(&divert_lock, flags);
- del_timer(&cs1->timer);
- if (cs1->prev)
- cs1->prev->next = cs1->next; /* forward link */
- else
- divert_head = cs1->next;
- if (cs1->next)
- cs1->next->prev = cs1->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs1);
- }
-
- return (0);
-} /* prot_stat_callback */
-
-
-/***************************/
-/* status callback from HL */
-/***************************/
-static int isdn_divert_stat_callback(isdn_ctrl *ic)
-{
- struct call_struc *cs, *cs1;
- unsigned long flags;
- int retval;
-
- retval = -1;
- cs = divert_head; /* start of list */
- while (cs) {
- if ((ic->driver == cs->ics.driver) &&
- (ic->arg == cs->ics.arg)) {
- switch (ic->command) {
- case ISDN_STAT_DHUP:
- sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
- del_timer(&cs->timer);
- cs->ics.driver = -1;
- break;
-
- case ISDN_STAT_CAUSE:
- sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
- break;
-
- case ISDN_STAT_REDIR:
- sprintf(cs->info, "131 0x%lx\n", cs->divert_id);
- del_timer(&cs->timer);
- cs->ics.driver = -1;
- break;
-
- default:
- sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command));
- break;
- }
- put_info_buffer(cs->info);
- retval = 0;
- }
- cs1 = cs;
- cs = cs->next;
- if (cs1->ics.driver == -1) {
- spin_lock_irqsave(&divert_lock, flags);
- if (cs1->prev)
- cs1->prev->next = cs1->next; /* forward link */
- else
- divert_head = cs1->next;
- if (cs1->next)
- cs1->next->prev = cs1->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs1);
- }
- }
- return (retval); /* not found */
-} /* isdn_divert_stat_callback */
-
-
-/********************/
-/* callback from ll */
-/********************/
-int ll_callback(isdn_ctrl *ic)
-{
- switch (ic->command) {
- case ISDN_STAT_ICALL:
- case ISDN_STAT_ICALLW:
- return (isdn_divert_icall(ic));
- break;
-
- case ISDN_STAT_PROT:
- if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
- if (ic->arg != DSS1_STAT_INVOKE_BRD)
- return (prot_stat_callback(ic));
- else
- return (0); /* DSS1 invoke broadcast */
- } else
- return (-1); /* protocol not euro */
-
- default:
- return (isdn_divert_stat_callback(ic));
- }
-} /* ll_callback */
+++ /dev/null
-/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
- *
- * Header for the diversion supplementary ioctl interface.
- *
- * Copyright 1998 by Werner Cornelius (werner@ikt.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/******************************************/
-/* IOCTL codes for interface to user prog */
-/******************************************/
-#define DIVERT_IIOC_VERSION 0x01 /* actual version */
-#define IIOCGETVER _IO('I', 1) /* get version of interface */
-#define IIOCGETDRV _IO('I', 2) /* get driver number */
-#define IIOCGETNAM _IO('I', 3) /* get driver name */
-#define IIOCGETRULE _IO('I', 4) /* read one rule */
-#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
-#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
-#define IIOCDELRULE _IO('I', 7) /* delete a rule */
-#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
-#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
-#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */
-#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */
-
-/*************************************/
-/* states reported through interface */
-/*************************************/
-#define DEFLECT_IGNORE 0 /* ignore incoming call */
-#define DEFLECT_REPORT 1 /* only report */
-#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
-#define DEFLECT_ALERT 3 /* alert and deflect after delay */
-#define DEFLECT_REJECT 4 /* reject immediately */
-#define DIVERT_ACTIVATE 5 /* diversion activate */
-#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
-#define DIVERT_REPORT 7 /* interrogation result */
-#define DEFLECT_AUTODEL 255 /* only for internal use */
-
-#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
-
-typedef struct {
- ulong drvid; /* driver ids, bit mapped */
- char my_msn[35]; /* desired msn, subaddr allowed */
- char caller[35]; /* caller id, partial string with * + subaddr allowed */
- char to_nr[35]; /* deflected to number incl. subaddress */
- u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */
- u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
- u_char callopt; /* option for call handling:
- 0 = all calls
- 1 = only non waiting calls
- 2 = only waiting calls */
- u_char action; /* desired action:
- 0 = don't report call -> ignore
- 1 = report call, do not allow/proceed for deflection
- 2 = report call, send proceed, wait max waittime secs
- 3 = report call, alert and deflect after waittime
- 4 = report call, reject immediately
- actions 1-2 only take place if interface is opened
- */
- u_char waittime; /* maximum wait time for proceeding */
-} divert_rule;
-
-typedef union {
- int drv_version; /* return of driver version */
- struct {
- int drvid; /* id of driver */
- char drvnam[30]; /* name of driver */
- } getid;
- struct {
- int ruleidx; /* index of rule */
- divert_rule rule; /* rule parms */
- } getsetrule;
- struct {
- u_char subcmd; /* 0 = hangup/reject,
- 1 = alert,
- 2 = deflect */
- ulong callid; /* id of call delivered by ascii output */
- char to_nr[35]; /* destination when deflect,
- else uus1 string (maxlen 31),
- data from rule used if empty */
- } fwd_ctrl;
- struct {
- int drvid; /* id of driver */
- u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
- ulong procid; /* process id returned when no error */
- u_char service; /* basically coded service, 0 = all */
- char msn[25]; /* desired msn, empty = all */
- char fwd_nr[35];/* forwarded to number + subaddress */
- } cf_ctrl;
-} divert_ioctl;
-
-#ifdef __KERNEL__
-
-#include <linux/isdnif.h>
-#include <linux/isdn_divertif.h>
-
-#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
-
-/**************************************************/
-/* structure keeping ascii info for device output */
-/**************************************************/
-struct divert_info {
- struct divert_info *next;
- ulong usage_cnt; /* number of files still to work */
- char info_start[2]; /* info string start */
-};
-
-
-/**************/
-/* Prototypes */
-/**************/
-extern spinlock_t divert_lock;
-
-extern ulong if_used; /* number of interface users */
-extern int divert_dev_deinit(void);
-extern int divert_dev_init(void);
-extern void put_info_buffer(char *);
-extern int ll_callback(isdn_ctrl *);
-extern isdn_divert_if divert_if;
-extern divert_rule *getruleptr(int);
-extern int insertrule(int, divert_rule *);
-extern int deleterule(int);
-extern void deleteprocs(void);
-extern int deflect_extern_action(u_char, ulong, char *);
-extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
-
-#endif /* __KERNEL__ */
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Old ISDN4Linux config
-#
-
-if ISDN_I4L
-
-config ISDN_PPP
- bool "Support synchronous PPP"
- depends on INET
- select SLHC
- help
- Over digital connections such as ISDN, there is no need to
- synchronize sender and recipient's clocks with start and stop bits
- as is done over analog telephone lines. Instead, one can use
- "synchronous PPP". Saying Y here will include this protocol. This
- protocol is used by Cisco and Sun for example. So you want to say Y
- here if the other end of your ISDN connection supports it. You will
- need a special version of pppd (called ipppd) for using this
- feature. See <file:Documentation/isdn/README.syncppp> and
- <file:Documentation/isdn/syncPPP.FAQ> for more information.
-
-config ISDN_PPP_VJ
- bool "Use VJ-compression with synchronous PPP"
- depends on ISDN_PPP
- help
- This enables Van Jacobson header compression for synchronous PPP.
- Say Y if the other end of the connection supports it.
-
-config ISDN_MPP
- bool "Support generic MP (RFC 1717)"
- depends on ISDN_PPP
- help
- With synchronous PPP enabled, it is possible to increase throughput
- by bundling several ISDN-connections, using this protocol. See
- <file:Documentation/isdn/README.syncppp> for more information.
-
-config IPPP_FILTER
- bool "Filtering for synchronous PPP"
- depends on ISDN_PPP
- help
- Say Y here if you want to be able to filter the packets passing over
- IPPP interfaces. This allows you to control which packets count as
- activity (i.e. which packets will reset the idle timer or bring up
- a demand-dialled link) and which packets are to be dropped entirely.
- You need to say Y here if you wish to use the pass-filter and
- active-filter options to ipppd.
-
-config ISDN_PPP_BSDCOMP
- tristate "Support BSD compression"
- depends on ISDN_PPP
- help
- Support for the BSD-Compress compression method for PPP, which uses
- the LZW compression method to compress each PPP packet before it is
- sent over the wire. The machine at the other end of the PPP link
- (usually your ISP) has to support the BSD-Compress compression
- method as well for this to be useful. Even if they don't support it,
- it is safe to say Y here.
-
-config ISDN_AUDIO
- bool "Support audio via ISDN"
- help
- If you say Y here, the modem-emulator will support a subset of the
- EIA Class 8 Voice commands. Using a getty with voice-support
- (mgetty+sendfax by <gert@greenie.muc.de> with an extension, available
- with the ISDN utility package for example), you will be able to use
- your Linux box as an ISDN-answering machine. Of course, this must be
- supported by the lowlevel driver also. Currently, the HiSax driver
- is the only voice-supporting driver. See
- <file:Documentation/isdn/README.audio> for more information.
-
-config ISDN_TTY_FAX
- bool "Support AT-Fax Class 1 and 2 commands"
- depends on ISDN_AUDIO
- help
- If you say Y here, the modem-emulator will support a subset of the
- Fax Class 1 and 2 commands. Using a getty with fax-support
- (mgetty+sendfax, hylafax), you will be able to use your Linux box as
- an ISDN-fax-machine. This must be supported by the lowlevel driver
- also. See <file:Documentation/isdn/README.fax> for more information.
-
-config ISDN_X25
- bool "X.25 PLP on top of ISDN"
- depends on X25
- help
- This feature provides the X.25 protocol over ISDN connections.
- See <file:Documentation/isdn/README.x25> for more information
- if you are thinking about using this.
-
-
-menu "ISDN feature submodules"
-
-config ISDN_DRV_LOOP
- tristate "isdnloop support"
- depends on BROKEN_ON_SMP
- help
- This driver provides a virtual ISDN card. Its primary purpose is
- testing of linklevel features or configuration without getting
- charged by your service-provider for lots of phone calls.
- You need will need the loopctrl utility from the latest isdn4k-utils
- package to set up this driver.
-
-config ISDN_DIVERSION
- tristate "Support isdn diversion services"
- help
- This option allows you to use some supplementary diversion
- services in conjunction with the HiSax driver on an EURO/DSS1
- line.
-
- Supported options are CD (call deflection), CFU (Call forward
- unconditional), CFB (Call forward when busy) and CFNR (call forward
- not reachable). Additionally the actual CFU, CFB and CFNR state may
- be interrogated.
-
- The use of CFU, CFB, CFNR and interrogation may be limited to some
- countries. The keypad protocol is still not implemented. CD should
- work in all countries if the service has been subscribed to.
-
- Please read the file <file:Documentation/isdn/README.diversion>.
-
-endmenu
-
-comment "ISDN4Linux hardware drivers"
-
-# end ISDN_I4L
-endif
-
# Each configuration option enables a list of files.
-obj-$(CONFIG_ISDN_I4L) += isdn.o
-obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
-
-# Multipart objects.
-
-isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
-
-# Optional parts of multipart objects.
-
-isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
-isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
-isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
-isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
-
+++ /dev/null
-/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
- * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include "isdn_audio.h"
-#include "isdn_common.h"
-
-char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Misc. lookup-tables.
- */
-
-/* ulaw -> signed 16-bit */
-static short isdn_audio_ulaw_to_s16[] =
-{
- 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
- 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
- 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
- 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
- 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
- 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
- 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
- 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
- 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
- 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
- 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
- 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
- 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
- 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
- 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
- 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
- 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
- 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
- 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
- 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
- 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
- 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
- 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
- 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
- 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
- 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
- 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
- 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
- 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
- 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
- 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
- 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
-};
-
-/* alaw -> signed 16-bit */
-static short isdn_audio_alaw_to_s16[] =
-{
- 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
- 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
- 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
- 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
- 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
- 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
- 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
- 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
- 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
- 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
- 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
- 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
- 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
- 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
- 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
- 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
- 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
- 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
- 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
- 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
- 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
- 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
- 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
- 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
- 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
- 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
- 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
- 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
- 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
- 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
- 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
- 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
-};
-
-/* alaw -> ulaw */
-static char isdn_audio_alaw_to_ulaw[] =
-{
- 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
- 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
- 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
- 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
- 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
- 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
- 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
- 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
- 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
- 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
- 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
- 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
- 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
- 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
- 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
- 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
- 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
- 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
- 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
- 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
- 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
- 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
- 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
- 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
- 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
- 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
- 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
- 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
- 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
- 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
- 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
- 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
-};
-
-/* ulaw -> alaw */
-static char isdn_audio_ulaw_to_alaw[] =
-{
- 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
- 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
- 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
- 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
- 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
- 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
- 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
- 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
- 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
- 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
- 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
- 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
- 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
- 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
- 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
- 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
- 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
- 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
- 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
- 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
- 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
- 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
- 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
- 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
- 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
- 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
- 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
- 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
- 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
- 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
- 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
- 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
-};
-
-#define NCOEFF 8 /* number of frequencies to be analyzed */
-#define DTMF_TRESH 4000 /* above this is dtmf */
-#define SILENCE_TRESH 200 /* below this is silence */
-#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
-#define LOGRP 0
-#define HIGRP 1
-
-/* For DTMF recognition:
- * 2 * cos(2 * PI * k / N) precalculated for all k
- */
-static int cos2pik[NCOEFF] =
-{
- 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
-};
-
-static char dtmf_matrix[4][4] =
-{
- {'1', '2', '3', 'A'},
- {'4', '5', '6', 'B'},
- {'7', '8', '9', 'C'},
- {'*', '0', '#', 'D'}
-};
-
-static inline void
-isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
-{
-#ifdef __i386__
- unsigned long d0, d1, d2, d3;
- __asm__ __volatile__(
- "cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
- "loop 1b\n\t"
- : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
- : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
- : "memory", "ax");
-#else
- while (n--)
- *buff = table[*(unsigned char *)buff], buff++;
-#endif
-}
-
-void
-isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
-}
-
-void
-isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
-}
-
-/*
- * linear <-> adpcm conversion stuff
- * Most parts from the mgetty-package.
- * (C) by Gert Doering and Klaus Weidner
- * Used by permission of Gert Doering
- */
-
-
-#define ZEROTRAP /* turn on the trap as per the MIL-STD */
-#undef ZEROTRAP
-#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
-#define CLIP 32635
-
-static unsigned char
-isdn_audio_linear2ulaw(int sample)
-{
- static int exp_lut[256] =
- {
- 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
- };
- int sign,
- exponent,
- mantissa;
- unsigned char ulawbyte;
-
- /* Get the sample into sign-magnitude. */
- sign = (sample >> 8) & 0x80; /* set aside the sign */
- if (sign != 0)
- sample = -sample; /* get magnitude */
- if (sample > CLIP)
- sample = CLIP; /* clip the magnitude */
-
- /* Convert from 16 bit linear to ulaw. */
- sample = sample + BIAS;
- exponent = exp_lut[(sample >> 7) & 0xFF];
- mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulawbyte = ~(sign | (exponent << 4) | mantissa);
-#ifdef ZEROTRAP
- /* optional CCITT trap */
- if (ulawbyte == 0)
- ulawbyte = 0x02;
-#endif
- return (ulawbyte);
-}
-
-
-static int Mx[3][8] =
-{
- {0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
- {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
- {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
-};
-
-static int bitmask[9] =
-{
- 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
-};
-
-static int
-isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len)
-{
- while (s->nleft < s->nbits) {
- int d = *((*in)++);
- (*len)--;
- s->word = (s->word << 8) | d;
- s->nleft += 8;
- }
- s->nleft -= s->nbits;
- return (s->word >> s->nleft) & bitmask[s->nbits];
-}
-
-static void
-isdn_audio_put_bits(int data, int nbits, adpcm_state *s,
- unsigned char **out, int *len)
-{
- s->word = (s->word << nbits) | (data & bitmask[nbits]);
- s->nleft += nbits;
- while (s->nleft >= 8) {
- int d = (s->word >> (s->nleft - 8));
- *(out[0]++) = d & 255;
- (*len)++;
- s->nleft -= 8;
- }
-}
-
-adpcm_state *
-isdn_audio_adpcm_init(adpcm_state *s, int nbits)
-{
- if (!s)
- s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
- if (s) {
- s->a = 0;
- s->d = 5;
- s->word = 0;
- s->nleft = 0;
- s->nbits = nbits;
- }
- return s;
-}
-
-dtmf_state *
-isdn_audio_dtmf_init(dtmf_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->last = ' ';
- }
- return s;
-}
-
-/*
- * Decompression of adpcm data to a/u-law
- *
- */
-
-int
-isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len) {
- int e = isdn_audio_get_bits(s, &in, &len);
- int sign;
-
- if (nbits == 4 && e == 0)
- d = 4;
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- if (fmt)
- *out++ = isdn_audio_ulaw_to_alaw[
- isdn_audio_linear2ulaw(a << 2)];
- else
- *out++ = isdn_audio_linear2ulaw(a << 2);
- olen++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-int
-isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len--) {
- int e = 0,
- nmax = 1 << (nbits - 1);
- int sign,
- delta;
-
- if (fmt)
- delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
- else
- delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
- if (delta < 0) {
- e = nmax;
- delta = -delta;
- }
- while (--nmax && delta > d) {
- delta -= d;
- e++;
- }
- if (nbits == 4 && ((e & 0x0f) == 0))
- e = 8;
- isdn_audio_put_bits(e, nbits, s, &out, &olen);
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
-
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-/*
- * Goertzel algorithm.
- * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
- * for more info.
- * Result is stored into an sk_buff and queued up for later
- * evaluation.
- */
-static void
-isdn_audio_goertzel(int *sample, modem_info *info)
-{
- int sk,
- sk1,
- sk2;
- int k,
- n;
- struct sk_buff *skb;
- int *result;
-
- skb = dev_alloc_skb(sizeof(int) * NCOEFF);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
- info->line);
- return;
- }
- result = skb_put(skb, sizeof(int) * NCOEFF);
- for (k = 0; k < NCOEFF; k++) {
- sk = sk1 = sk2 = 0;
- for (n = 0; n < DTMF_NPOINTS; n++) {
- sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
- sk2 = sk1;
- sk1 = sk;
- }
- /* Avoid overflows */
- sk >>= 1;
- sk2 >>= 1;
- /* compute |X(k)|**2 */
- /* report overflows. This should not happen. */
- /* Comment this out if desired */
- if (sk < -32768 || sk > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
- if (sk2 < -32768 || sk2 > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
- result[k] =
- ((sk * sk) >> AMP_BITS) -
- ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
- ((sk2 * sk2) >> AMP_BITS);
- }
- skb_queue_tail(&info->dtmf_queue, skb);
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-}
-
-void
-isdn_audio_eval_dtmf(modem_info *info)
-{
- struct sk_buff *skb;
- int *result;
- dtmf_state *s;
- int silence;
- int i;
- int di;
- int ch;
- int grp[2];
- char what;
- char *p;
- int thresh;
-
- while ((skb = skb_dequeue(&info->dtmf_queue))) {
- result = (int *) skb->data;
- s = info->dtmf_state;
- grp[LOGRP] = grp[HIGRP] = -1;
- silence = 0;
- thresh = 0;
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] > DTMF_TRESH) {
- if (result[i] > thresh)
- thresh = result[i];
- }
- else if (result[i] < SILENCE_TRESH)
- silence++;
- }
- if (silence == NCOEFF)
- what = ' ';
- else {
- if (thresh > 0) {
- thresh = thresh >> 4; /* touchtones must match within 12 dB */
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] < thresh)
- continue; /* ignore */
- /* good level found. This is allowed only one time per group */
- if (i < NCOEFF / 2) {
- /* lowgroup*/
- if (grp[LOGRP] >= 0) {
- // Bad. Another tone found. */
- grp[LOGRP] = -1;
- break;
- }
- else
- grp[LOGRP] = i;
- }
- else { /* higroup */
- if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
- grp[HIGRP] = -1;
- break;
- }
- else
- grp[HIGRP] = i - NCOEFF/2;
- }
- }
- if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
- what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
- if (s->last != ' ' && s->last != '.')
- s->last = what; /* min. 1 non-DTMF between DTMF */
- } else
- what = '.';
- }
- else
- what = '.';
- }
- if ((what != s->last) && (what != ' ') && (what != '.')) {
- printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
- p = skb->data;
- *p++ = 0x10;
- *p = what;
- skb_trim(skb, 2);
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
- } else
- kfree_skb(skb);
- s->last = what;
- }
-}
-
-/*
- * Decode DTMF tones, queue result in separate sk_buf for
- * later examination.
- * Parameters:
- * s = pointer to state-struct.
- * buf = input audio data
- * len = size of audio data.
- * fmt = audio data format (0 = ulaw, 1 = alaw)
- */
-void
-isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- dtmf_state *s = info->dtmf_state;
- int i;
- int c;
-
- while (len) {
- c = DTMF_NPOINTS - s->idx;
- if (c > len)
- c = len;
- if (c <= 0)
- break;
- for (i = 0; i < c; i++) {
- if (fmt)
- s->buf[s->idx++] =
- isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
- else
- s->buf[s->idx++] =
- isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
- }
- if (s->idx == DTMF_NPOINTS) {
- isdn_audio_goertzel(s->buf, info);
- s->idx = 0;
- }
- len -= c;
- }
-}
-
-silence_state *
-isdn_audio_silence_init(silence_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->state = 0;
- }
- return s;
-}
-
-void
-isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- silence_state *s = info->silence_state;
- int i;
- signed char c;
-
- if (!info->emu.vpar[1]) return;
-
- for (i = 0; i < len; i++) {
- if (fmt)
- c = isdn_audio_alaw_to_ulaw[*buf++];
- else
- c = *buf++;
-
- if (c > 0) c -= 128;
- c = abs(c);
-
- if (c > (info->emu.vpar[1] * 4)) {
- s->idx = 0;
- s->state = 1;
- } else {
- if (s->idx < 210000) s->idx++;
- }
- }
-}
-
-void
-isdn_audio_put_dle_code(modem_info *info, u_char code)
-{
- struct sk_buff *skb;
- int di;
- int ch;
- char *p;
-
- skb = dev_alloc_skb(2);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc skb for ttyI%d\n",
- info->line);
- return;
- }
- p = skb_put(skb, 2);
- p[0] = 0x10;
- p[1] = code;
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
-}
-
-void
-isdn_audio_eval_silence(modem_info *info)
-{
- silence_state *s = info->silence_state;
- char what;
-
- what = ' ';
-
- if (s->idx > (info->emu.vpar[2] * 800)) {
- s->idx = 0;
- if (!s->state) { /* silence from beginning of rec */
- what = 's';
- } else {
- what = 'q';
- }
- }
- if ((what == 's') || (what == 'q')) {
- printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
- (what == 's') ? "silence" : "quiet");
- isdn_audio_put_dle_code(info, what);
- }
-}
+++ /dev/null
-/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
-typedef struct adpcm_state {
- int a;
- int d;
- int word;
- int nleft;
- int nbits;
-} adpcm_state;
-
-typedef struct dtmf_state {
- char last;
- char llast;
- int idx;
- int buf[DTMF_NPOINTS];
-} dtmf_state;
-
-typedef struct silence_state {
- int state;
- unsigned int idx;
-} silence_state;
-
-extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
-extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
-extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
-extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_dtmf(modem_info *);
-dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
-extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_silence(modem_info *);
-silence_state *isdn_audio_silence_init(silence_state *);
-extern void isdn_audio_put_dle_code(modem_info *, u_char);
+++ /dev/null
-/*
- * BSD compression module
- *
- * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
- * The whole module is now SKB based.
- *
- */
-
-/*
- * Update: The Berkeley copyright was changed, and the change
- * is retroactive to all "true" BSD software (ie everything
- * from UCB as opposed to other peoples code that just carried
- * the same license). The new copyright doesn't clash with the
- * GPL, so the module-only restriction has been removed..
- */
-
-/*
- * Original copyright notice:
- *
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/types.h>
-
-#include <linux/if.h>
-
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/inet.h>
-#include <linux/ioctl.h>
-#include <linux/vmalloc.h>
-
-#include <linux/ppp_defs.h>
-
-#include <linux/isdn.h>
-#include <linux/isdn_ppp.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/if_arp.h>
-#include <linux/ppp-comp.h>
-
-#include "isdn_ppp.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
-MODULE_LICENSE("Dual BSD/GPL");
-
-#define BSD_VERSION(x) ((x) >> 5)
-#define BSD_NBITS(x) ((x) & 0x1F)
-
-#define BSD_CURRENT_VERSION 1
-
-#define DEBUG 1
-
-/*
- * A dictionary for doing BSD compress.
- */
-
-struct bsd_dict {
- u32 fcode;
- u16 codem1; /* output of hash table -1 */
- u16 cptr; /* map code to hash table entry */
-};
-
-struct bsd_db {
- int totlen; /* length of this structure */
- unsigned int hsize; /* size of the hash table */
- unsigned char hshift; /* used in hash function */
- unsigned char n_bits; /* current bits/code */
- unsigned char maxbits; /* maximum bits/code */
- unsigned char debug; /* non-zero if debug desired */
- unsigned char unit; /* ppp unit number */
- u16 seqno; /* sequence # of next packet */
- unsigned int mru; /* size of receive (decompress) bufr */
- unsigned int maxmaxcode; /* largest valid code */
- unsigned int max_ent; /* largest code in use */
- unsigned int in_count; /* uncompressed bytes, aged */
- unsigned int bytes_out; /* compressed bytes, aged */
- unsigned int ratio; /* recent compression ratio */
- unsigned int checkpoint; /* when to next check the ratio */
- unsigned int clear_count; /* times dictionary cleared */
- unsigned int incomp_count; /* incompressible packets */
- unsigned int incomp_bytes; /* incompressible bytes */
- unsigned int uncomp_count; /* uncompressed packets */
- unsigned int uncomp_bytes; /* uncompressed bytes */
- unsigned int comp_count; /* compressed packets */
- unsigned int comp_bytes; /* compressed bytes */
- unsigned short *lens; /* array of lengths of codes */
- struct bsd_dict *dict; /* dictionary */
- int xmit;
-};
-
-#define BSD_OVHD 2 /* BSD compress overhead/packet */
-#define MIN_BSD_BITS 9
-#define BSD_INIT_BITS MIN_BSD_BITS
-#define MAX_BSD_BITS 15
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define CLEAR 256 /* table clear output code */
-#define FIRST 257 /* first free entry */
-#define LAST 255
-
-#define MAXCODE(b) ((1 << (b)) - 1)
-#define BADCODEM1 MAXCODE(MAX_BSD_BITS)
-
-#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \
- ^ (unsigned long)(prefix))
-#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \
- + (unsigned long)(prefix))
-
-#define CHECK_GAP 10000 /* Ratio check interval */
-
-#define RATIO_SCALE_LOG 8
-#define RATIO_SCALE (1 << RATIO_SCALE_LOG)
-#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
-
-/*
- * clear the dictionary
- */
-
-static void bsd_clear(struct bsd_db *db)
-{
- db->clear_count++;
- db->max_ent = FIRST - 1;
- db->n_bits = BSD_INIT_BITS;
- db->bytes_out = 0;
- db->in_count = 0;
- db->incomp_count = 0;
- db->ratio = 0;
- db->checkpoint = CHECK_GAP;
-}
-
-/*
- * If the dictionary is full, then see if it is time to reset it.
- *
- * Compute the compression ratio using fixed-point arithmetic
- * with 8 fractional bits.
- *
- * Since we have an infinite stream instead of a single file,
- * watch only the local compression ratio.
- *
- * Since both peers must reset the dictionary at the same time even in
- * the absence of CLEAR codes (while packets are incompressible), they
- * must compute the same ratio.
- */
-static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */
-{
- unsigned int new_ratio;
-
- if (db->in_count >= db->checkpoint)
- {
- /* age the ratio by limiting the size of the counts */
- if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
- {
- db->in_count -= (db->in_count >> 2);
- db->bytes_out -= (db->bytes_out >> 2);
- }
-
- db->checkpoint = db->in_count + CHECK_GAP;
-
- if (db->max_ent >= db->maxmaxcode)
- {
- /* Reset the dictionary only if the ratio is worse,
- * or if it looks as if it has been poisoned
- * by incompressible data.
- *
- * This does not overflow, because
- * db->in_count <= RATIO_MAX.
- */
-
- new_ratio = db->in_count << RATIO_SCALE_LOG;
- if (db->bytes_out != 0)
- {
- new_ratio /= db->bytes_out;
- }
-
- if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
- {
- bsd_clear(db);
- return 1;
- }
- db->ratio = new_ratio;
- }
- }
- return 0;
-}
-
-/*
- * Return statistics.
- */
-
-static void bsd_stats(void *state, struct compstat *stats)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- stats->unc_bytes = db->uncomp_bytes;
- stats->unc_packets = db->uncomp_count;
- stats->comp_bytes = db->comp_bytes;
- stats->comp_packets = db->comp_count;
- stats->inc_bytes = db->incomp_bytes;
- stats->inc_packets = db->incomp_count;
- stats->in_count = db->in_count;
- stats->bytes_out = db->bytes_out;
-}
-
-/*
- * Reset state, as on a CCP ResetReq.
- */
-static void bsd_reset(void *state, unsigned char code, unsigned char id,
- unsigned char *data, unsigned len,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- bsd_clear(db);
- db->seqno = 0;
- db->clear_count = 0;
-}
-
-/*
- * Release the compression structure
- */
-static void bsd_free(void *state)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- if (db) {
- /*
- * Release the dictionary
- */
- vfree(db->dict);
- db->dict = NULL;
-
- /*
- * Release the string buffer
- */
- vfree(db->lens);
- db->lens = NULL;
-
- /*
- * Finally release the structure itself.
- */
- kfree(db);
- }
-}
-
-
-/*
- * Allocate space for a (de) compressor.
- */
-static void *bsd_alloc(struct isdn_ppp_comp_data *data)
-{
- int bits;
- unsigned int hsize, hshift, maxmaxcode;
- struct bsd_db *db;
- int decomp;
-
- static unsigned int htab[][2] = {
- { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
- { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
- };
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- return NULL;
-
- bits = BSD_NBITS(data->options[0]);
-
- if (bits < 9 || bits > 15)
- return NULL;
-
- hsize = htab[bits - 9][0];
- hshift = htab[bits - 9][1];
-
- /*
- * Allocate the main control structure for this instance.
- */
- maxmaxcode = MAXCODE(bits);
- db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL);
- if (!db)
- return NULL;
-
- db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
- decomp = db->xmit ? 0 : 1;
-
- /*
- * Allocate space for the dictionary. This may be more than one page in
- * length.
- */
- db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict)));
- if (!db->dict) {
- bsd_free(db);
- return NULL;
- }
-
- /*
- * If this is the compression buffer then there is no length data.
- * For decompression, the length information is needed as well.
- */
- if (!decomp)
- db->lens = NULL;
- else {
- db->lens = vmalloc(array_size(sizeof(db->lens[0]),
- maxmaxcode + 1));
- if (!db->lens) {
- bsd_free(db);
- return (NULL);
- }
- }
-
- /*
- * Initialize the data information for the compression code
- */
- db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize);
- db->hsize = hsize;
- db->hshift = hshift;
- db->maxmaxcode = maxmaxcode;
- db->maxbits = bits;
-
- return (void *)db;
-}
-
-/*
- * Initialize the database.
- */
-static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
-{
- struct bsd_db *db = state;
- int indx;
- int decomp;
-
- if (!state || !data) {
- printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data);
- return 0;
- }
-
- decomp = db->xmit ? 0 : 1;
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- || (BSD_NBITS(data->options[0]) != db->maxbits)
- || (decomp && db->lens == NULL)) {
- printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens);
- return 0;
- }
-
- if (decomp)
- for (indx = LAST; indx >= 0; indx--)
- db->lens[indx] = 1;
-
- indx = db->hsize;
- while (indx-- != 0) {
- db->dict[indx].codem1 = BADCODEM1;
- db->dict[indx].cptr = 0;
- }
-
- db->unit = unit;
- db->mru = 0;
-
- db->debug = 1;
-
- bsd_reset(db, 0, 0, NULL, 0, NULL);
-
- return 1;
-}
-
-/*
- * Obtain pointers to the various structures in the compression tables
- */
-
-#define dict_ptrx(p, idx) &(p->dict[idx])
-#define lens_ptrx(p, idx) &(p->lens[idx])
-
-#ifdef DEBUG
-static unsigned short *lens_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
- printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return lens_ptrx(db, idx);
-}
-
-static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx >= (unsigned int) db->hsize) {
- printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return dict_ptrx(db, idx);
-}
-
-#else
-#define lens_ptr(db, idx) lens_ptrx(db, idx)
-#define dict_ptr(db, idx) dict_ptrx(db, idx)
-#endif
-
-/*
- * compress a packet
- */
-static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto)
-{
- struct bsd_db *db;
- int hshift;
- unsigned int max_ent;
- unsigned int n_bits;
- unsigned int bitno;
- unsigned long accm;
- int ent;
- unsigned long fcode;
- struct bsd_dict *dictp;
- unsigned char c;
- int hval, disp, ilen, mxcode;
- unsigned char *rptr = skb_in->data;
- int isize = skb_in->len;
-
-#define OUTPUT(ent) \
- { \
- bitno -= n_bits; \
- accm |= ((ent) << bitno); \
- do { \
- if (skb_out && skb_tailroom(skb_out) > 0) \
- skb_put_u8(skb_out, (u8)(accm >> 24)); \
- accm <<= 8; \
- bitno += 8; \
- } while (bitno <= 24); \
- }
-
- /*
- * If the protocol is not in the range we're interested in,
- * just return without compressing the packet. If it is,
- * the protocol becomes the first byte to compress.
- */
- printk(KERN_DEBUG "bsd_compress called with %x\n", proto);
-
- ent = proto;
- if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1))
- return 0;
-
- db = (struct bsd_db *) state;
- hshift = db->hshift;
- max_ent = db->max_ent;
- n_bits = db->n_bits;
- bitno = 32;
- accm = 0;
- mxcode = MAXCODE(n_bits);
-
- /* This is the PPP header information */
- if (skb_out && skb_tailroom(skb_out) >= 2) {
- char *v = skb_put(skb_out, 2);
- /* we only push our own data on the header,
- AC,PC and protos is pushed by caller */
- v[0] = db->seqno >> 8;
- v[1] = db->seqno;
- }
-
- ilen = ++isize; /* This is off by one, but that is what is in draft! */
-
- while (--ilen > 0) {
- c = *rptr++;
- fcode = BSD_KEY(ent, c);
- hval = BSD_HASH(ent, c, hshift);
- dictp = dict_ptr(db, hval);
-
- /* Validate and then check the entry. */
- if (dictp->codem1 >= max_ent)
- goto nomatch;
-
- if (dictp->fcode == fcode) {
- ent = dictp->codem1 + 1;
- continue; /* found (prefix,suffix) */
- }
-
- /* continue probing until a match or invalid entry */
- disp = (hval == 0) ? 1 : hval;
-
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- if (dictp->codem1 >= max_ent)
- goto nomatch;
- } while (dictp->fcode != fcode);
-
- ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
- continue;
-
- nomatch:
- OUTPUT(ent); /* output the prefix */
-
- /* code -> hashtable */
- if (max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2;
- struct bsd_dict *dictp3;
- int indx;
-
- /* expand code size if needed */
- if (max_ent >= mxcode) {
- db->n_bits = ++n_bits;
- mxcode = MAXCODE(n_bits);
- }
-
- /*
- * Invalidate old hash table entry using
- * this code, and then take it over.
- */
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- if (db->lens) {
- unsigned short *len1 = lens_ptr(db, max_ent);
- unsigned short *len2 = lens_ptr(db, ent);
- *len1 = *len2 + 1;
- }
- }
- ent = c;
- }
-
- OUTPUT(ent); /* output the last code */
-
- if (skb_out)
- db->bytes_out += skb_out->len; /* Do not count bytes from here */
- db->uncomp_bytes += isize;
- db->in_count += isize;
- ++db->uncomp_count;
- ++db->seqno;
-
- if (bitno < 32)
- ++db->bytes_out; /* must be set before calling bsd_check */
-
- /*
- * Generate the clear command if needed
- */
-
- if (bsd_check(db))
- OUTPUT(CLEAR);
-
- /*
- * Pad dribble bits of last code with ones.
- * Do not emit a completely useless byte of ones.
- */
- if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out,
- (unsigned char)((accm | (0xff << (bitno - 8))) >> 24));
-
- /*
- * Increase code size if we would have without the packet
- * boundary because the decompressor will do so.
- */
- if (max_ent >= mxcode && max_ent < db->maxmaxcode)
- db->n_bits++;
-
- /* If output length is too large then this is an incompressible frame. */
- if (!skb_out || skb_out->len >= skb_in->len) {
- ++db->incomp_count;
- db->incomp_bytes += isize;
- return 0;
- }
-
- /* Count the number of compressed frames */
- ++db->comp_count;
- db->comp_bytes += skb_out->len;
- return skb_out->len;
-
-#undef OUTPUT
-}
-
-/*
- * Update the "BSD Compress" dictionary on the receiver for
- * incompressible data by pretending to compress the incoming data.
- */
-static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto)
-{
- bsd_compress(state, skb_in, NULL, proto);
-}
-
-/*
- * Decompress "BSD Compress".
- */
-static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db;
- unsigned int max_ent;
- unsigned long accm;
- unsigned int bitno; /* 1st valid bit in accm */
- unsigned int n_bits;
- unsigned int tgtbitno; /* bitno when we have a code */
- struct bsd_dict *dictp;
- int seq;
- unsigned int incode;
- unsigned int oldcode;
- unsigned int finchar;
- unsigned char *p, *ibuf;
- int ilen;
- int codelen;
- int extra;
-
- db = (struct bsd_db *) state;
- max_ent = db->max_ent;
- accm = 0;
- bitno = 32; /* 1st valid bit in accm */
- n_bits = db->n_bits;
- tgtbitno = 32 - n_bits; /* bitno when we have a code */
-
- printk(KERN_DEBUG "bsd_decompress called\n");
-
- if (!skb_in || !skb_out) {
- printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
- return DECOMP_ERROR;
- }
-
- /*
- * Get the sequence number.
- */
- if ((p = skb_pull(skb_in, 2)) == NULL) {
- return DECOMP_ERROR;
- }
- p -= 2;
- seq = (p[0] << 8) + p[1];
- ilen = skb_in->len;
- ibuf = skb_in->data;
-
- /*
- * Check the sequence number and give up if it differs from
- * the value we're expecting.
- */
- if (seq != db->seqno) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
- db->unit, seq, db->seqno - 1);
- }
- return DECOMP_ERROR;
- }
-
- ++db->seqno;
- db->bytes_out += ilen;
-
- if (skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out, 0);
- else
- return DECOMP_ERR_NOMEM;
-
- oldcode = CLEAR;
-
- /*
- * Keep the checkpoint correctly so that incompressible packets
- * clear the dictionary at the proper times.
- */
-
- for (;;) {
- if (ilen-- <= 0) {
- db->in_count += (skb_out->len - 1); /* don't count the header */
- break;
- }
-
- /*
- * Accumulate bytes until we have a complete code.
- * Then get the next code, relying on the 32-bit,
- * unsigned accm to mask the result.
- */
-
- bitno -= 8;
- accm |= *ibuf++ << bitno;
- if (tgtbitno < bitno)
- continue;
-
- incode = accm >> tgtbitno;
- accm <<= n_bits;
- bitno += n_bits;
-
- /*
- * The dictionary must only be cleared at the end of a packet.
- */
-
- if (incode == CLEAR) {
- if (ilen > 0) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
- return DECOMP_FATALERROR; /* probably a bug */
- }
- bsd_clear(db);
- break;
- }
-
- if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
- || (incode > max_ent && oldcode == CLEAR)) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
- db->unit, incode, oldcode);
- printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
- max_ent, skb_out->len, db->seqno);
- }
- return DECOMP_FATALERROR; /* probably a bug */
- }
-
- /* Special case for KwKwK string. */
- if (incode > max_ent) {
- finchar = oldcode;
- extra = 1;
- } else {
- finchar = incode;
- extra = 0;
- }
-
- codelen = *(lens_ptr(db, finchar));
- if (skb_tailroom(skb_out) < codelen + extra) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
-#ifdef DEBUG
- printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
- ilen, finchar, codelen, skb_out->len);
-#endif
- }
- return DECOMP_FATALERROR;
- }
-
- /*
- * Decode this code and install it in the decompressed buffer.
- */
-
- p = skb_put(skb_out, codelen);
- p += codelen;
- while (finchar > LAST) {
- struct bsd_dict *dictp2 = dict_ptr(db, finchar);
-
- dictp = dict_ptr(db, dictp2->cptr);
-
-#ifdef DEBUG
- if (--codelen <= 0 || dictp->codem1 != finchar - 1) {
- if (codelen <= 0) {
- printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
- printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
- } else {
- if (dictp->codem1 != finchar - 1) {
- printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar);
- printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
- }
- }
- return DECOMP_FATALERROR;
- }
-#endif
-
- {
- u32 fcode = dictp->fcode;
- *--p = (fcode >> 16) & 0xff;
- finchar = fcode & 0xffff;
- }
- }
- *--p = finchar;
-
-#ifdef DEBUG
- if (--codelen != 0)
- printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
-#endif
-
- if (extra) /* the KwKwK case again */
- skb_put_u8(skb_out, finchar);
-
- /*
- * If not first code in a packet, and
- * if not out of code space, then allocate a new code.
- *
- * Keep the hash table correct so it can be used
- * with uncompressed packets.
- */
- if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2, *dictp3;
- u16 *lens1, *lens2;
- unsigned long fcode;
- int hval, disp, indx;
-
- fcode = BSD_KEY(oldcode, finchar);
- hval = BSD_HASH(oldcode, finchar, db->hshift);
- dictp = dict_ptr(db, hval);
-
- /* look for a free hash table entry */
- if (dictp->codem1 < max_ent) {
- disp = (hval == 0) ? 1 : hval;
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- } while (dictp->codem1 < max_ent);
- }
-
- /*
- * Invalidate previous hash table entry
- * assigned this code, and then take it over
- */
-
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- /* Update the length of this string. */
- lens1 = lens_ptr(db, max_ent);
- lens2 = lens_ptr(db, oldcode);
- *lens1 = *lens2 + 1;
-
- /* Expand code size if needed. */
- if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
- db->n_bits = ++n_bits;
- tgtbitno = 32-n_bits;
- }
- }
- oldcode = incode;
- }
-
- ++db->comp_count;
- ++db->uncomp_count;
- db->comp_bytes += skb_in->len - BSD_OVHD;
- db->uncomp_bytes += skb_out->len;
-
- if (bsd_check(db)) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
- db->unit, db->seqno - 1);
- }
- return skb_out->len;
-}
-
-/*************************************************************
- * Table of addresses for the BSD compression module
- *************************************************************/
-
-static struct isdn_ppp_compressor ippp_bsd_compress = {
- .owner = THIS_MODULE,
- .num = CI_BSD_COMPRESS,
- .alloc = bsd_alloc,
- .free = bsd_free,
- .init = bsd_init,
- .reset = bsd_reset,
- .compress = bsd_compress,
- .decompress = bsd_decompress,
- .incomp = bsd_incomp,
- .stat = bsd_stats,
-};
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static int __init isdn_bsdcomp_init(void)
-{
- int answer = isdn_ppp_register_compressor(&ippp_bsd_compress);
- if (answer == 0)
- printk(KERN_INFO "PPP BSD Compression module registered\n");
- return answer;
-}
-
-static void __exit isdn_bsdcomp_exit(void)
-{
- isdn_ppp_unregister_compressor(&ippp_bsd_compress);
-}
-
-module_init(isdn_bsdcomp_init);
-module_exit(isdn_bsdcomp_exit);
+++ /dev/null
-/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, common used functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/isdn.h>
-#include <linux/mutex.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_net.h"
-#include "isdn_ppp.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#endif
-#ifdef CONFIG_ISDN_DIVERSION_MODULE
-#define CONFIG_ISDN_DIVERSION
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
-#include <linux/isdn_divertif.h>
-#endif /* CONFIG_ISDN_DIVERSION */
-#include "isdn_v110.h"
-
-/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-
-MODULE_DESCRIPTION("ISDN4Linux: link layer");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-
-isdn_dev *dev;
-
-static DEFINE_MUTEX(isdn_mutex);
-static char *isdn_revision = "$Revision: 1.1.2.3 $";
-
-extern char *isdn_net_revision;
-#ifdef CONFIG_ISDN_PPP
-extern char *isdn_ppp_revision;
-#else
-static char *isdn_ppp_revision = ": none $";
-#endif
-#ifdef CONFIG_ISDN_AUDIO
-extern char *isdn_audio_revision;
-#else
-static char *isdn_audio_revision = ": none $";
-#endif
-extern char *isdn_v110_revision;
-
-#ifdef CONFIG_ISDN_DIVERSION
-static isdn_divert_if *divert_if; /* = NULL */
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-static int isdn_writebuf_stub(int, int, const u_char __user *, int);
-static void set_global_features(void);
-static int isdn_wildmat(char *s, char *p);
-static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
-
-static inline void
-isdn_lock_driver(isdn_driver_t *drv)
-{
- try_module_get(drv->interface->owner);
- drv->locks++;
-}
-
-void
-isdn_lock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_lock_driver(dev->drv[i]);
- }
-}
-
-static inline void
-isdn_unlock_driver(isdn_driver_t *drv)
-{
- if (drv->locks > 0) {
- drv->locks--;
- module_put(drv->interface->owner);
- }
-}
-
-void
-isdn_unlock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_unlock_driver(dev->drv[i]);
- }
-}
-
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void
-isdn_dumppkt(char *s, u_char *p, int len, int dumplen)
-{
- int dumpc;
-
- printk(KERN_DEBUG "%s(%d) ", s, len);
- for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
- printk(" %02x", *p++);
- printk("\n");
-}
-#endif
-
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-static int
-isdn_star(char *s, char *p)
-{
- while (isdn_wildmat(s, p)) {
- if (*++s == '\0')
- return (2);
- }
- return (0);
-}
-
-/*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p.
- *
- * Return:
- * 0 = match.
- * 1 = no match.
- * 2 = no match. Would eventually match, if s would be longer.
- *
- * Possible Patterns:
- *
- * '?' matches one character
- * '*' matches zero or more characters
- * [xyz] matches the set of characters in brackets.
- * [^xyz] matches any single character not in the set of characters
- */
-
-static int
-isdn_wildmat(char *s, char *p)
-{
- register int last;
- register int matched;
- register int reverse;
- register int nostar = 1;
-
- if (!(*s) && !(*p))
- return (1);
- for (; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* fall through */
- default:
- if (*s != *p)
- return (*s == '\0') ? 2 : 1;
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return (2);
- continue;
- case '*':
- nostar = 0;
- /* Trailing star matches everything. */
- return (*++p ? isdn_star(s, p) : 0);
- case '[':
- /* [^....] means inverse character class. */
- if ((reverse = (p[1] == '^')))
- p++;
- for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = 1;
- if (matched == reverse)
- return (1);
- continue;
- }
- return (*s == '\0') ? 0 : nostar;
-}
-
-int isdn_msncmp(const char *msn1, const char *msn2)
-{
- char TmpMsn1[ISDN_MSNLEN];
- char TmpMsn2[ISDN_MSNLEN];
- char *p;
-
- for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID
- *p++ = *msn1++;
- *p = '\0';
-
- for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID
- *p++ = *msn2++;
- *p = '\0';
-
- return isdn_wildmat(TmpMsn1, TmpMsn2);
-}
-
-int
-isdn_dc2minor(int di, int ch)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
- return i;
- return -1;
-}
-
-static int isdn_timer_cnt1 = 0;
-static int isdn_timer_cnt2 = 0;
-static int isdn_timer_cnt3 = 0;
-
-static void
-isdn_timer_funct(struct timer_list *unused)
-{
- int tf = dev->tflags;
- if (tf & ISDN_TIMER_FAST) {
- if (tf & ISDN_TIMER_MODEMREAD)
- isdn_tty_readmodem();
- if (tf & ISDN_TIMER_MODEMPLUS)
- isdn_tty_modem_escape();
- if (tf & ISDN_TIMER_MODEMXMIT)
- isdn_tty_modem_xmit();
- }
- if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
- isdn_timer_cnt1 = 0;
- if (tf & ISDN_TIMER_NETDIAL)
- isdn_net_dial();
- }
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (tf & ISDN_TIMER_NETHANGUP)
- isdn_net_autohup();
- if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
- isdn_timer_cnt3 = 0;
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
- }
- if (tf & ISDN_TIMER_CARRIER)
- isdn_tty_carrier_timeout();
- }
- }
- if (tf)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
-}
-
-void
-isdn_timer_ctrl(int tf, int onoff)
-{
- unsigned long flags;
- int old_tflags;
-
- spin_lock_irqsave(&dev->timerlock, flags);
- if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
- /* If the slow-timer wasn't activated until now */
- isdn_timer_cnt1 = 0;
- isdn_timer_cnt2 = 0;
- }
- old_tflags = dev->tflags;
- if (onoff)
- dev->tflags |= tf;
- else
- dev->tflags &= ~tf;
- if (dev->tflags && !old_tflags)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
- spin_unlock_irqrestore(&dev->timerlock, flags);
-}
-
-/*
- * Receive a packet from B-Channel. (Called from low-level-module)
- */
-static void
-isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
-{
- int i;
-
- if ((i = isdn_dc2minor(di, channel)) == -1) {
- dev_kfree_skb(skb);
- return;
- }
- /* Update statistics */
- dev->ibytes[i] += skb->len;
-
- /* First, try to deliver data to network-device */
- if (isdn_net_rcv_skb(i, skb))
- return;
-
- /* V.110 handling
- * makes sense for async streams only, so it is
- * called after possible net-device delivery.
- */
- if (dev->v110[i]) {
- atomic_inc(&dev->v110use[i]);
- skb = isdn_v110_decode(dev->v110[i], skb);
- atomic_dec(&dev->v110use[i]);
- if (!skb)
- return;
- }
-
- /* No network-device found, deliver to tty or raw-channel */
- if (skb->len) {
- if (isdn_tty_rcv_skb(i, di, channel, skb))
- return;
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Intercept command from Linklevel to Lowlevel.
- * If layer 2 protocol is V.110 and this is not supported by current
- * lowlevel-driver, use driver's transparent mode and handle V.110 in
- * linklevel instead.
- */
-int
-isdn_command(isdn_ctrl *cmd)
-{
- if (cmd->driver == -1) {
- printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
- return (1);
- }
- if (!dev->drv[cmd->driver]) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (!dev->drv[cmd->driver]->interface) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (cmd->command == ISDN_CMD_SETL2) {
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- dev->v110emu[idx] = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- dev->v110emu[idx] = 0;
- }
- }
- return dev->drv[cmd->driver]->interface->command(cmd);
-}
-
-void
-isdn_all_eaz(int di, int ch)
-{
- isdn_ctrl cmd;
-
- if (di < 0)
- return;
- cmd.driver = di;
- cmd.arg = ch;
- cmd.command = ISDN_CMD_SETEAZ;
- cmd.parm.num[0] = '\0';
- isdn_command(&cmd);
-}
-
-/*
- * Begin of a CAPI like LL<->HL interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-
-static int
-isdn_capi_rec_hl_msg(capi_msg *cm)
-{
- switch (cm->Command) {
- case CAPI_FACILITY:
- /* in the moment only handled in tty */
- return (isdn_tty_capi_facility(cm));
- default:
- return (-1);
- }
-}
-
-static int
-isdn_status_callback(isdn_ctrl *c)
-{
- int di;
- u_long flags;
- int i;
- int r;
- int retval = 0;
- isdn_ctrl cmd;
- isdn_net_dev *p;
-
- di = c->driver;
- i = isdn_dc2minor(di, c->arg);
- switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i < 0)
- return -1;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- return 0;
- if (isdn_v110_stat_callback(i, c))
- return 0;
- if (isdn_tty_stat_callback(i, c))
- return 0;
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- dev->drv[di]->stavail += c->arg;
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->flags |= DRV_FLAG_RUNNING;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- set_global_features();
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
- break;
- case ISDN_STAT_ICALL:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- return 0;
- }
- /* Try to find a network-interface which will accept incoming call */
- r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
- switch (r) {
- case 0:
- /* No network-device replies.
- * Try ttyI's.
- * These return 0 on no match, 1 on match and
- * 3 on eventually match, if CID is longer.
- */
- if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- if ((retval = divert_if->stat_callback(c)))
- return (retval); /* processed */
-#endif /* CONFIG_ISDN_DIVERSION */
- if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
- /* No tty responding */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- retval = 2;
- }
- break;
- case 1:
- /* Schedule connection-setup */
- isdn_net_dial();
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTD;
- for (p = dev->netdev; p; p = p->next)
- if (p->local->isdn_channel == cmd.arg)
- {
- strcpy(cmd.parm.setup.eazmsn, p->local->msn);
- isdn_command(&cmd);
- retval = 1;
- break;
- }
- break;
-
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval = 2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- break;
- case 5:
- /* Number would eventually match, if longer */
- retval = 3;
- break;
- }
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
-#endif
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c);
- isdn_tty_stat_callback(i, c);
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
-#endif
- printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
- dev->drvid[di], c->arg, c->parm.num);
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
-#endif
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- /* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- /* Find any ttyI, waiting for D-channel setup */
- if (isdn_tty_stat_callback(i, c)) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- break;
- }
- break;
- case ISDN_STAT_DHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- break;
- case ISDN_STAT_BCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
-#endif
- /* Signal B-channel-connect to network-devices */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_BHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
-#ifdef CONFIG_ISDN_X25
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
-#endif
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_NODCH:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- break;
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_ADDCH:
- spin_lock_irqsave(&dev->lock, flags);
- if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_DISCH:
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == c->arg)) {
- if (c->parm.num[0])
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- else
- if (USG_NONE(dev->usage[i])) {
- dev->usage[i] |= ISDN_USAGE_DISABLED;
- }
- else
- retval = -1;
- break;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_UNLOAD:
- while (dev->drv[di]->locks > 0) {
- isdn_unlock_driver(dev->drv[di]);
- }
- spin_lock_irqsave(&dev->lock, flags);
- isdn_tty_stat_callback(i, c);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- skb_queue_purge(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- case ISDN_STAT_L1ERR:
- break;
- case CAPI_PUT_MESSAGE:
- return (isdn_capi_rec_hl_msg(&c->parm.cmsg));
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
- case ISDN_STAT_PROT:
- case ISDN_STAT_REDIR:
- if (divert_if)
- return (divert_if->stat_callback(c));
-#endif /* CONFIG_ISDN_DIVERSION */
- /* fall through */
- default:
- return -1;
- }
- return 0;
-}
-
-/*
- * Get integer from char-pointer, set pointer to end of number
- */
-int
-isdn_getnum(char **p)
-{
- int v = -1;
-
- while (*p[0] >= '0' && *p[0] <= '9')
- v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
- return v;
-}
-
-#define DLE 0x10
-
-/*
- * isdn_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- u_char *cp;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
- if (sleep)
- wait_event_interruptible(*sleep,
- !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
- else
- return 0;
- }
- if (len > dev->drv[di]->rcvcount[channel])
- len = dev->drv[di]->rcvcount[channel];
- cp = buf;
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- skb_copy_from_linear_data(skb, cp, count_put);
- cp += count_put;
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (fp)
- *(fp - 1) = 0xff;
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-/*
- * isdn_readbchan_tty() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- char last = 0;
- int len;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- return 0;
-
- len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
- if (len == 0)
- return len;
-
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- /* push every character but the last to the tty buffer directly */
- if (count_put)
- tty_insert_flip_char(port, last, TTY_NORMAL);
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- last = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- last = *p;
- if (last == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- if (count_put > 1)
- tty_insert_flip_string(port, skb->data, count_put - 1);
- last = skb->data[count_put - 1];
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (cisco_hack)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- tty_insert_flip_char(port, last, TTY_NORMAL);
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-
-static inline int
-isdn_minor2drv(int minor)
-{
- return (dev->drvmap[minor]);
-}
-
-static inline int
-isdn_minor2chan(int minor)
-{
- return (dev->chanmap[minor]);
-}
-
-static char *
-isdn_statstr(void)
-{
- static char istatbuf[2048];
- char *p;
- int i;
-
- sprintf(istatbuf, "idmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nchmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->chanmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\ndrmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->drvmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nusage:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->usage[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nflags:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (dev->drv[i]) {
- sprintf(p, "%ld ", dev->drv[i]->online);
- p = istatbuf + strlen(istatbuf);
- } else {
- sprintf(p, "? ");
- p = istatbuf + strlen(istatbuf);
- }
- }
- sprintf(p, "\nphone:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", dev->num[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\n");
- return istatbuf;
-}
-
-/* Module interface-code */
-
-void
-isdn_info_update(void)
-{
- infostruct *p = dev->infochain;
-
- while (p) {
- *(p->private) = 1;
- p = (infostruct *) p->next;
- }
- wake_up_interruptible(&(dev->info_waitq));
-}
-
-static ssize_t
-isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int len = 0;
- int drvidx;
- int chidx;
- int retval;
- char *p;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->info_waitq,
- file->private_data);
- }
- p = isdn_statstr();
- file->private_data = NULL;
- if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len)) {
- retval = -EFAULT;
- goto out;
- }
- *off += len;
- retval = len;
- goto out;
- }
- retval = 0;
- goto out;
- }
- if (!dev->drivers) {
- retval = -ENODEV;
- goto out;
- }
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- if (!(p = kmalloc(count, GFP_KERNEL))) {
- retval = -ENOMEM;
- goto out;
- }
- len = isdn_readbchan(drvidx, chidx, p, NULL, count,
- &dev->drv[drvidx]->rcv_waitq[chidx]);
- *off += len;
- if (copy_to_user(buf, p, len))
- len = -EFAULT;
- kfree(p);
- retval = len;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->drv[drvidx]->st_waitq,
- dev->drv[drvidx]->stavail);
- }
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->readstat(buf, count,
- drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- if (len < 0) {
- retval = len;
- goto out;
- }
- } else {
- len = 0;
- }
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- *off += len;
- retval = len;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static ssize_t
-isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int drvidx;
- int chidx;
- int retval;
-
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
- if (!dev->drivers)
- return -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
- (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- /*
- * We want to use the isdnctrl device to load the firmware
- *
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- */
- if (dev->drv[drvidx]->interface->writecmd)
- retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, drvidx,
- isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- else
- retval = count;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static __poll_t
-isdn_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask = 0;
- unsigned int minor = iminor(file_inode(file));
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- poll_wait(file, &(dev->info_waitq), wait);
- /* mask = EPOLLOUT | EPOLLWRNORM; */
- if (file->private_data) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0) {
- /* driver deregistered while file open */
- mask = EPOLLHUP;
- goto out;
- }
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
- mask = EPOLLOUT | EPOLLWRNORM;
- if (dev->drv[drvidx]->stavail) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- mask = isdn_ppp_poll(file, wait);
- goto out;
- }
-#endif
- mask = EPOLLERR;
-out:
- mutex_unlock(&isdn_mutex);
- return mask;
-}
-
-
-static int
-isdn_ioctl(struct file *file, uint cmd, ulong arg)
-{
- uint minor = iminor(file_inode(file));
- isdn_ctrl c;
- int drvidx;
- int ret;
- int i;
- char __user *p;
- char *s;
- union iocpar {
- char name[10];
- char bname[22];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
- } iocpar;
- void __user *argp = (void __user *)arg;
-
-#define name iocpar.name
-#define bname iocpar.bname
-#define iocts iocpar.iocts
-#define phone iocpar.phone
-#define cfg iocpar.cfg
-
- if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return (TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong __user *p = argp;
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- put_user(dev->ibytes[i], p++);
- put_user(dev->obytes[i], p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCNETGPN:
- /* Get peer phone number of a connected
- * isdn network interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- return isdn_net_getpeer(&phone, argp);
- } else
- return -EINVAL;
- default:
- return -EINVAL;
- }
- }
- if (!dev->drivers)
- return -ENODEV;
- if (minor <= ISDN_MINOR_BMAX) {
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- return 0;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
-/*
- * isdn net devices manage lots of configuration variables as linked lists.
- * Those lists must only be manipulated from user space. Some of the ioctl's
- * service routines access user space and are not atomic. Therefore, ioctl's
- * manipulating the lists and ioctl's sleeping while accessing the lists
- * are serialized by means of a semaphore.
- */
- switch (cmd) {
- case IIOCNETDWRSET:
- printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
- return (-EINVAL);
- case IIOCNETLCR:
- printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
- return -ENODEV;
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- s = name;
- } else {
- s = NULL;
- }
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_new(s, NULL))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if (copy_from_user(bname, argp, sizeof(bname) - 1))
- return -EFAULT;
- bname[sizeof(bname)-1] = 0;
- } else
- return -EINVAL;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_newslave(bname))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_rm(name);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if (copy_to_user(argp, &cfg, sizeof(cfg)))
- return -EFAULT;
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_addphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_getphones(&phone, argp);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_delphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_hangup_slave(name);
-#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_hangup(name);
- break;
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
- drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- if (iocts.arg)
- dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
- else
- dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
- return 0;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- }
- return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
-
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- int loop = 1;
-
- p = (char __user *) iocts.arg;
- i = 0;
- while (loop) {
- int j = 0;
-
- while (1) {
- get_user(bname[j], p++);
- switch (bname[j]) {
- case '\0':
- loop = 0;
- /* Fall through */
- case ',':
- bname[j] = '\0';
- strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
- j = ISDN_MSNLEN;
- break;
- default:
- j++;
- }
- if (j >= ISDN_MSNLEN)
- break;
- }
- if (++i > 9)
- break;
- }
- } else {
- p = (char __user *) iocts.arg;
- for (i = 0; i < 10; i++) {
- snprintf(bname, sizeof(bname), "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "_",
- (i < 9) ? "," : "\0");
- if (copy_to_user(p, bname, strlen(bname) + 1))
- return -EFAULT;
- p += strlen(bname);
- }
- }
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- return -EINVAL;
- default:
- if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
- cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
- else
- return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.parm.num, &iocts.arg, sizeof(ulong));
- ret = isdn_command(&c);
- memcpy(&iocts.arg, c.parm.num, sizeof(ulong));
- if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- return ret;
- } else
- return -EINVAL;
- }
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
- return -ENODEV;
-
-#undef name
-#undef bname
-#undef iocts
-#undef phone
-#undef cfg
-}
-
-static long
-isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&isdn_mutex);
- ret = isdn_ioctl(file, cmd, arg);
- mutex_unlock(&isdn_mutex);
-
- return ret;
-}
-
-/*
- * Open the device code.
- */
-static int
-isdn_open(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
- int drvidx;
- int chidx;
- int retval = -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p;
-
- if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
- p->next = (char *) dev->infochain;
- p->private = (char *) &(filep->private_data);
- dev->infochain = p;
- /* At opening we allow a single update */
- filep->private_data = (char *) 1;
- retval = 0;
- goto out;
- } else {
- retval = -ENOMEM;
- goto out;
- }
- }
- if (!dev->channels)
- goto out;
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- goto out;
- chidx = isdn_minor2chan(minor);
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- goto out;
- if (!(dev->drv[drvidx]->online & (1 << chidx)))
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
- if (retval == 0)
- isdn_lock_drivers();
- goto out;
- }
-#endif
-out:
- nonseekable_open(ino, filep);
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static int
-isdn_close(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p = dev->infochain;
- infostruct *q = NULL;
-
- while (p) {
- if (p->private == (char *) &(filep->private_data)) {
- if (q)
- q->next = p->next;
- else
- dev->infochain = (infostruct *) (p->next);
- kfree(p);
- goto out;
- }
- q = p;
- p = (infostruct *) (p->next);
- }
- printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- goto out;
- }
- isdn_unlock_drivers();
- if (minor <= ISDN_MINOR_BMAX)
- goto out;
- if (minor <= ISDN_MINOR_CTRLMAX) {
- if (dev->profd == current)
- dev->profd = NULL;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
-#endif
-
-out:
- mutex_unlock(&isdn_mutex);
- return 0;
-}
-
-static const struct file_operations isdn_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = isdn_read,
- .write = isdn_write,
- .poll = isdn_poll,
- .unlocked_ioctl = isdn_unlocked_ioctl,
- .open = isdn_open,
- .release = isdn_close,
-};
-
-char *
-isdn_map_eaz2msn(char *msn, int di)
-{
- isdn_driver_t *this = dev->drv[di];
- int i;
-
- if (strlen(msn) == 1) {
- i = msn[0] - '0';
- if ((i >= 0) && (i <= 9))
- if (strlen(this->msn2eaz[i]))
- return (this->msn2eaz[i]);
- }
- return (msn);
-}
-
-/*
- * Find an unused ISDN-channel, whose feature-flags match the
- * given L2- and L3-protocols.
- */
-#define L2V (~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038))
-
-/*
- * This function must be called with holding the dev->lock.
- */
-int
-isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- , int pre_chan, char *msn)
-{
- int i;
- ulong features;
- ulong vfeatures;
-
- features = ((1 << l2_proto) | (0x10000 << l3_proto));
- vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
- ~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038));
- /* If Layer-2 protocol is V.110, accept drivers with
- * transparent feature even if these don't support V.110
- * because we can emulate this in linklevel.
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_NONE(dev->usage[i]) &&
- (dev->drvmap[i] != -1)) {
- int d = dev->drvmap[i];
- if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
- ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
- continue;
- if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
- continue;
- if (dev->usage[i] & ISDN_USAGE_DISABLED)
- continue; /* usage not allowed */
- if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
- if (((dev->drv[d]->interface->features & features) == features) ||
- (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
- (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
- if ((pre_dev < 0) || (pre_chan < 0)) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- } else {
- if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- }
- }
- }
- }
- }
- return -1;
-}
-
-/*
- * Set state of ISDN-channel to 'unused'
- */
-void
-isdn_free_channel(int di, int ch, int usage)
-{
- int i;
-
- if ((di < 0) || (ch < 0)) {
- printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
- __func__, di, ch);
- return;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
- (dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
- strcpy(dev->num[i], "???");
- dev->ibytes[i] = 0;
- dev->obytes[i] = 0;
-// 20.10.99 JIM, try to reinitialize v110 !
- dev->v110emu[i] = 0;
- atomic_set(&(dev->v110use[i]), 0);
- isdn_v110_close(dev->v110[i]);
- dev->v110[i] = NULL;
-// 20.10.99 JIM, try to reinitialize v110 !
- isdn_info_update();
- if (dev->drv[di])
- skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
- }
-}
-
-/*
- * Cancel Exclusive-Flag for ISDN-channel
- */
-void
-isdn_unexclusive_channel(int di, int ch)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- return;
- }
-}
-
-/*
- * writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char __user *buf, int len)
-{
- int ret;
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
- struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, hl);
- if (copy_from_user(skb_put(skb, len), buf, len)) {
- dev_kfree_skb(skb);
- return -EFAULT;
- }
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
- if (ret <= 0)
- dev_kfree_skb(skb);
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
- return ret;
-}
-
-/*
- * Return: length of data on success, -ERRcode on failure.
- */
-int
-isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
-{
- int ret;
- struct sk_buff *nskb = NULL;
- int v110_ret = skb->len;
- int idx = isdn_dc2minor(drvidx, chan);
-
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- nskb = isdn_v110_encode(dev->v110[idx], skb);
- atomic_dec(&dev->v110use[idx]);
- if (!nskb)
- return 0;
- v110_ret = *((int *)nskb->data);
- skb_pull(nskb, sizeof(int));
- if (!nskb->len) {
- dev_kfree_skb(nskb);
- return v110_ret;
- }
- /* V.110 must always be acknowledged */
- ack = 1;
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
- } else {
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-
- if (skb_headroom(skb) < hl) {
- /*
- * This should only occur when new HL driver with
- * increased hl_hdrlen was loaded after netdevice
- * was created and connected to the new driver.
- *
- * The V.110 branch (re-allocates on its own) does
- * not need this
- */
- struct sk_buff *skb_tmp;
-
- skb_tmp = skb_realloc_headroom(skb, hl);
- printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
- if (!skb_tmp) return -ENOMEM; /* 0 better? */
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
- if (ret > 0) {
- dev_kfree_skb(skb);
- } else {
- dev_kfree_skb(skb_tmp);
- }
- } else {
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
- }
- }
- if (ret > 0) {
- dev->obytes[idx] += ret;
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- dev->v110[idx]->skbuser++;
- atomic_dec(&dev->v110use[idx]);
- /* For V.110 return unencoded data length */
- ret = v110_ret;
- /* if the complete frame was send we free the skb;
- if not upper function will requeue the skb */
- if (ret == skb->len)
- dev_kfree_skb(skb);
- }
- } else
- if (dev->v110[idx])
- dev_kfree_skb(nskb);
- return ret;
-}
-
-static int
-isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
-{
- int j, k, m;
-
- init_waitqueue_head(&d->st_waitq);
- if (d->flags & DRV_FLAG_RUNNING)
- return -1;
- if (n < 1) return 0;
-
- m = (adding) ? d->channels + n : n;
-
- if (dev->channels + n > ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
- ISDN_MAX_CHANNELS);
- return -1;
- }
-
- if ((adding) && (d->rcverr))
- kfree(d->rcverr);
- if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
- return -1;
- }
-
- if ((adding) && (d->rcvcount))
- kfree(d->rcvcount);
- if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
- if (!adding)
- kfree(d->rcverr);
- return -1;
- }
-
- if ((adding) && (d->rpqueue)) {
- for (j = 0; j < d->channels; j++)
- skb_queue_purge(&d->rpqueue[j]);
- kfree(d->rpqueue);
- }
- d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC);
- if (!d->rpqueue) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- if (!adding) {
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- for (j = 0; j < m; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
-
- if ((adding) && (d->rcv_waitq))
- kfree(d->rcv_waitq);
- d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m),
- GFP_ATOMIC);
- if (!d->rcv_waitq) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
- if (!adding) {
- kfree(d->rpqueue);
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- d->snd_waitq = d->rcv_waitq + m;
- for (j = 0; j < m; j++) {
- init_waitqueue_head(&d->rcv_waitq[j]);
- init_waitqueue_head(&d->snd_waitq[j]);
- }
-
- dev->channels += n;
- for (j = d->channels; j < m; j++)
- for (k = 0; k < ISDN_MAX_CHANNELS; k++)
- if (dev->chanmap[k] < 0) {
- dev->chanmap[k] = j;
- dev->drvmap[k] = drvidx;
- break;
- }
- d->channels = m;
- return 0;
-}
-
-/*
- * Low-level-driver registration
- */
-
-static void
-set_global_features(void)
-{
- int drvidx;
-
- dev->global_features = 0;
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
- if (!dev->drv[drvidx])
- continue;
- if (dev->drv[drvidx]->interface)
- dev->global_features |= dev->drv[drvidx]->interface->features;
- }
-}
-
-#ifdef CONFIG_ISDN_DIVERSION
-
-static char *map_drvname(int di)
-{
- if ((di < 0) || (di >= ISDN_MAX_DRIVERS))
- return (NULL);
- return (dev->drvid[di]); /* driver name */
-} /* map_drvname */
-
-static int map_namedrv(char *id)
-{ int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- { if (!strcmp(dev->drvid[i], id))
- return (i);
- }
- return (-1);
-} /* map_namedrv */
-
-int DIVERT_REG_NAME(isdn_divert_if *i_div)
-{
- if (i_div->if_magic != DIVERT_IF_MAGIC)
- return (DIVERT_VER_ERR);
- switch (i_div->cmd)
- {
- case DIVERT_CMD_REL:
- if (divert_if != i_div)
- return (DIVERT_REL_ERR);
- divert_if = NULL; /* free interface */
- return (DIVERT_NO_ERR);
-
- case DIVERT_CMD_REG:
- if (divert_if)
- return (DIVERT_REG_ERR);
- i_div->ll_cmd = isdn_command; /* set command function */
- i_div->drv_to_name = map_drvname;
- i_div->name_to_drv = map_namedrv;
- divert_if = i_div; /* remember interface */
- return (DIVERT_NO_ERR);
-
- default:
- return (DIVERT_CMD_ERR);
- }
-} /* DIVERT_REG_NAME */
-
-EXPORT_SYMBOL(DIVERT_REG_NAME);
-
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-EXPORT_SYMBOL(register_isdn);
-#ifdef CONFIG_ISDN_PPP
-EXPORT_SYMBOL(isdn_ppp_register_compressor);
-EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
-#endif
-
-int
-register_isdn(isdn_if *i)
-{
- isdn_driver_t *d;
- int j;
- ulong flags;
- int drvidx;
-
- if (dev->drivers >= ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
- ISDN_MAX_DRIVERS);
- return 0;
- }
- if (!i->writebuf_skb) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
- if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
- return 0;
- }
-
- d->maxbufsize = i->maxbufsize;
- d->pktcount = 0;
- d->stavail = 0;
- d->flags = DRV_FLAG_LOADED;
- d->online = 0;
- d->interface = i;
- d->channels = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (!dev->drv[drvidx])
- break;
- if (isdn_add_channels(d, drvidx, i->channels, 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- kfree(d);
- return 0;
- }
- i->channels = drvidx;
- i->rcvcallb_skb = isdn_receive_skb_callback;
- i->statcallb = isdn_status_callback;
- if (!strlen(i->id))
- sprintf(i->id, "line%d", drvidx);
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id, dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
- dev->drv[drvidx] = d;
- strcpy(dev->drvid[drvidx], i->id);
- isdn_info_update();
- dev->drivers++;
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
-}
-
-/*
-*****************************************************************************
-* And now the modules code.
-*****************************************************************************
-*/
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Allocate and initialize all data, register modem-devices
- */
-static int __init isdn_init(void)
-{
- int i;
- char tmprev[50];
-
- dev = vzalloc(sizeof(isdn_dev));
- if (!dev) {
- printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
- return -EIO;
- }
- timer_setup(&dev->timer, isdn_timer_funct, 0);
- spin_lock_init(&dev->lock);
- spin_lock_init(&dev->timerlock);
-#ifdef MODULE
- dev->owner = THIS_MODULE;
-#endif
- mutex_init(&dev->mtx);
- init_waitqueue_head(&dev->info_waitq);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->m_idx[i] = -1;
- strcpy(dev->num[i], "???");
- }
- if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
- printk(KERN_WARNING "isdn: Could not register control devices\n");
- vfree(dev);
- return -EIO;
- }
- if ((isdn_tty_modem_init()) < 0) {
- printk(KERN_WARNING "isdn: Could not register tty devices\n");
- vfree(dev);
- unregister_chrdev(ISDN_MAJOR, "isdn");
- return -EIO;
- }
-#ifdef CONFIG_ISDN_PPP
- if (isdn_ppp_init() < 0) {
- printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- vfree(dev);
- return -EIO;
- }
-#endif /* CONFIG_ISDN_PPP */
-
- strcpy(tmprev, isdn_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_net_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_ppp_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_audio_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_v110_revision);
- printk("%s", isdn_getrev(tmprev));
-
-#ifdef MODULE
- printk(" loaded\n");
-#else
- printk("\n");
-#endif
- isdn_info_update();
- return 0;
-}
-
-/*
- * Unload module
- */
-static void __exit isdn_exit(void)
-{
-#ifdef CONFIG_ISDN_PPP
- isdn_ppp_cleanup();
-#endif
- if (isdn_net_rmall() < 0) {
- printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
- return;
- }
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- del_timer_sync(&dev->timer);
- /* call vfree with interrupts enabled, else it will hang */
- vfree(dev);
- printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
-}
-
-module_init(isdn_init);
-module_exit(isdn_exit);
+++ /dev/null
-/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem
- * common used functions and debugging-switches (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_DEBUG_MODEM_OPEN
-#undef ISDN_DEBUG_MODEM_IOCTL
-#undef ISDN_DEBUG_MODEM_WAITSENT
-#undef ISDN_DEBUG_MODEM_HUP
-#undef ISDN_DEBUG_MODEM_ICALL
-#undef ISDN_DEBUG_MODEM_DUMP
-#undef ISDN_DEBUG_MODEM_VOICE
-#undef ISDN_DEBUG_AT
-#undef ISDN_DEBUG_NET_DUMP
-#undef ISDN_DEBUG_NET_DIAL
-#undef ISDN_DEBUG_NET_ICALL
-
-/* Prototypes */
-extern void isdn_lock_drivers(void);
-extern void isdn_unlock_drivers(void);
-extern void isdn_free_channel(int di, int ch, int usage);
-extern void isdn_all_eaz(int di, int ch);
-extern int isdn_command(isdn_ctrl *);
-extern int isdn_dc2minor(int di, int ch);
-extern void isdn_info_update(void);
-extern char *isdn_map_eaz2msn(char *msn, int di);
-extern void isdn_timer_ctrl(int tf, int onoff);
-extern void isdn_unexclusive_channel(int di, int ch);
-extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
-extern int isdn_get_free_channel(int, int, int, int, int, char *);
-extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
-extern int register_isdn(isdn_if *i);
-extern int isdn_msncmp(const char *, const char *);
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-extern void isdn_dumppkt(char *, u_char *, int, int);
-#endif
+++ /dev/null
-/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
- * stuff goes here. Stuff that depends only on the concap protocol goes to
- * another -- protocol specific -- source file.
- *
- */
-
-
-#include <linux/isdn.h>
-#include "isdn_x25iface.h"
-#include "isdn_net.h"
-#include <linux/concap.h>
-#include "isdn_concap.h"
-
-
-/* The following set of device service operations are for encapsulation
- protocols that require for reliable datalink semantics. That means:
-
- - before any data is to be submitted the connection must explicitly
- be set up.
- - after the successful set up of the connection is signalled the
- connection is considered to be reliably up.
-
- Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
- is completely bypassed.
-
- It might be possible to implement a (non standardized) datalink protocol
- that provides a reliable data link service while using some auto dialing
- mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
- signaling on the D-channel) while the B-channel is down.
-*/
-
-
-static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- isdn_net_local *lp = isdn_net_get_locked_lp(nd);
-
- IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
- if (!lp) {
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1);
- return 1;
- }
- lp->huptimer = 0;
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0);
- return 0;
-}
-
-
-static int isdn_concap_dl_connect_req(struct concap_proto *concap)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_local *lp = netdev_priv(ndev);
- int ret;
- IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name);
-
- /* dial ... */
- ret = isdn_net_dial_req(lp);
- if (ret) IX25DEBUG("dialing failed\n");
- return ret;
-}
-
-static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
-{
- IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name);
-
- isdn_net_hangup(concap->net_dev);
- return 0;
-}
-
-struct concap_device_ops isdn_concap_reliable_dl_dops = {
- .data_req = &isdn_concap_dl_data_req,
- .connect_req = &isdn_concap_dl_connect_req,
- .disconn_req = &isdn_concap_dl_disconn_req
-};
-
-/* The following should better go into a dedicated source file such that
- this sourcefile does not need to include any protocol specific header
- files. For now:
-*/
-struct concap_proto *isdn_concap_new(int encap)
-{
- switch (encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- return isdn_x25iface_proto_new();
- }
- return NULL;
-}
+++ /dev/null
-/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-extern struct concap_device_ops isdn_concap_reliable_dl_dops;
-extern struct concap_proto *isdn_concap_new(int);
+++ /dev/null
-/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, network interfaces and related functions (linklevel).
- *
- * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
- * guy@traverse.com.au
- * Outgoing calls - looks for a 'V' in first char of dialed number
- * Incoming calls - checks first character of eaz as follows:
- * Numeric - accept DATA only - original functionality
- * 'V' - accept VOICE (DOV) only
- * 'B' - accept BOTH DATA and DOV types
- *
- * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
- * for info on the protocol, see
- * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-#include <net/dst.h>
-#include <net/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include "isdn_common.h"
-#include "isdn_net.h"
-#ifdef CONFIG_ISDN_PPP
-#include "isdn_ppp.h"
-#endif
-#ifdef CONFIG_ISDN_X25
-#include <linux/concap.h>
-#include "isdn_concap.h"
-#endif
-
-
-/*
- * Outline of new tbusy handling:
- *
- * Old method, roughly spoken, consisted of setting tbusy when entering
- * isdn_net_start_xmit() and at several other locations and clearing
- * it from isdn_net_start_xmit() thread when sending was successful.
- *
- * With 2.3.x multithreaded network core, to prevent problems, tbusy should
- * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
- * condition is detected. Other threads (in particular isdn_net_stat_callb())
- * are only allowed to clear tbusy.
- *
- * -HE
- */
-
-/*
- * About SOFTNET:
- * Most of the changes were pretty obvious and basically done by HE already.
- *
- * One problem of the isdn net device code is that it uses struct net_device
- * for masters and slaves. However, only master interface are registered to
- * the network layer, and therefore, it only makes sense to call netif_*
- * functions on them.
- *
- * --KG
- */
-
-/*
- * Find out if the netdevice has been ifup-ed yet.
- * For slaves, look at the corresponding master.
- */
-static __inline__ int isdn_net_device_started(isdn_net_dev *n)
-{
- isdn_net_local *lp = n->local;
- struct net_device *dev;
-
- if (lp->master)
- dev = lp->master;
- else
- dev = n->dev;
- return netif_running(dev);
-}
-
-/*
- * wake up the network -> net_device queue.
- * For slaves, wake the corresponding master interface.
- */
-static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_wake_queue(lp->master);
- else
- netif_wake_queue(lp->netdev->dev);
-}
-
-/*
- * stop the network -> net_device queue.
- * For slaves, stop the corresponding master interface.
- */
-static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_stop_queue(lp->master);
- else
- netif_stop_queue(lp->netdev->dev);
-}
-
-/*
- * find out if the net_device which this lp belongs to (lp can be
- * master or slave) is busy. It's busy iff all (master and slave)
- * queues are busy
- */
-static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
-{
- isdn_net_local *nlp;
- isdn_net_dev *nd;
- unsigned long flags;
-
- if (!isdn_net_lp_busy(lp))
- return 0;
-
- if (lp->master)
- nd = ISDN_MASTER_PRIV(lp)->netdev;
- else
- nd = lp->netdev;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- nlp = lp->next;
- while (nlp != lp) {
- if (!isdn_net_lp_busy(nlp)) {
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 0;
- }
- nlp = nlp->next;
- }
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 1;
-}
-
-static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
-{
- atomic_inc(&lp->frame_cnt);
- if (isdn_net_device_busy(lp))
- isdn_net_device_stop_queue(lp);
-}
-
-static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
-{
- atomic_dec(&lp->frame_cnt);
-
- if (!(isdn_net_device_busy(lp))) {
- if (!skb_queue_empty(&lp->super_tx_queue)) {
- schedule_work(&lp->tqueue);
- } else {
- isdn_net_device_wake_queue(lp);
- }
- }
-}
-
-static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
-{
- atomic_set(&lp->frame_cnt, 0);
-}
-
-/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
- * to be safe.
- * For 2.3.x we push it up to 20 secs, because call establishment
- * (in particular callback) may take such a long time, and we
- * don't want confusing messages in the log. However, there is a slight
- * possibility that this large timeout will break other things like MPPP,
- * which might rely on the tx timeout. If so, we'll find out this way...
- */
-
-#define ISDN_NET_TX_TIMEOUT (20 * HZ)
-
-/* Prototypes */
-
-static int isdn_net_force_dial_lp(isdn_net_local *);
-static netdev_tx_t isdn_net_start_xmit(struct sk_buff *,
- struct net_device *);
-
-static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
-static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
-
-char *isdn_net_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Code for raw-networking over ISDN
- */
-
-static void
-isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
-{
- if (skb) {
-
- u_short proto = ntohs(skb->protocol);
-
- printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
- dev->name,
- (reason != NULL) ? reason : "unknown",
- (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
-
- dst_link_failure(skb);
- }
- else { /* dial not triggered by rawIP packet */
- printk(KERN_DEBUG "isdn_net: %s: %s\n",
- dev->name,
- (reason != NULL) ? reason : "reason unknown");
- }
-}
-
-static void
-isdn_net_reset(struct net_device *dev)
-{
-#ifdef CONFIG_ISDN_X25
- struct concap_device_ops *dops =
- ((isdn_net_local *)netdev_priv(dev))->dops;
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
-#endif
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops && dops)
- cprot->pops->restart(cprot, dev, dops);
-#endif
-}
-
-/* Open/initialize the board. */
-static int
-isdn_net_open(struct net_device *dev)
-{
- int i;
- struct net_device *p;
- struct in_device *in_dev;
-
- /* moved here from isdn_net_reset, because only the master has an
- interface associated which is supposed to be started. BTW:
- we need to call netif_start_queue, not netif_wake_queue here */
- netif_start_queue(dev);
-
- isdn_net_reset(dev);
- /* Fill in the MAC-level header (not needed, but for compatibility... */
- for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
- dev->dev_addr[i] = 0xfc;
- if ((in_dev = dev->ip_ptr) != NULL) {
- /*
- * Any address will do - we take the first
- */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL)
- memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4);
- }
-
- /* If this interface has slaves, start them also */
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- while (p) {
- isdn_net_reset(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_lock_drivers();
- return 0;
-}
-
-/*
- * Assign an ISDN-channel to a net-interface
- */
-static void
-isdn_net_bind_channel(isdn_net_local *lp, int idx)
-{
- lp->flags |= ISDN_NET_CONNECTED;
- lp->isdn_device = dev->drvmap[idx];
- lp->isdn_channel = dev->chanmap[idx];
- dev->rx_netdev[idx] = lp->netdev;
- dev->st_netdev[idx] = lp->netdev;
-}
-
-/*
- * unbind a net-interface (resets interface after an error)
- */
-static void
-isdn_net_unbind_channel(isdn_net_local *lp)
-{
- skb_queue_purge(&lp->super_tx_queue);
-
- if (!lp->master) { /* reset only master device */
- /* Moral equivalent of dev_purge_queues():
- BEWARE! This chunk of code cannot be called from hardware
- interrupt handler. I hope it is true. --ANK
- */
- qdisc_reset_all_tx(lp->netdev->dev);
- }
- lp->dialstate = 0;
- dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- if (lp->isdn_device != -1 && lp->isdn_channel != -1)
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- lp->flags &= ~ISDN_NET_CONNECTED;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
-}
-
-/*
- * Perform auto-hangup and cps-calculation for net-interfaces.
- *
- * auto-hangup:
- * Increment idle-counter (this counter is reset on any incoming or
- * outgoing packet), if counter exceeds configured limit either do a
- * hangup immediately or - if configured - wait until just before the next
- * charge-info.
- *
- * cps-calculation (needed for dynamic channel-bundling):
- * Since this function is called every second, simply reset the
- * byte-counter of the interface after copying it to the cps-variable.
- */
-static unsigned long last_jiffies = -HZ;
-
-void
-isdn_net_autohup(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore;
-
- anymore = 0;
- while (p) {
- isdn_net_local *l = p->local;
- if (jiffies == last_jiffies)
- l->cps = l->transcount;
- else
- l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
- l->transcount = 0;
- if (dev->net_verbose > 3)
- printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
- if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
- anymore = 1;
- l->huptimer++;
- /*
- * if there is some dialmode where timeout-hangup
- * should _not_ be done, check for that here
- */
- if ((l->onhtime) &&
- (l->huptimer > l->onhtime))
- {
- if (l->hupflags & ISDN_MANCHARGE &&
- l->hupflags & ISDN_CHARGEHUP) {
- while (time_after(jiffies, l->chargetime + l->chargeint))
- l->chargetime += l->chargeint;
- if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
- if (l->outgoing || l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- } else if (l->outgoing) {
- if (l->hupflags & ISDN_CHARGEHUP) {
- if (l->hupflags & ISDN_WAITCHARGE) {
- printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
- p->dev->name, l->hupflags);
- isdn_net_hangup(p->dev);
- } else if (time_after(jiffies, l->chargetime + l->chargeint)) {
- printk(KERN_DEBUG
- "isdn_net: %s: chtime = %lu, chint = %d\n",
- p->dev->name, l->chargetime, l->chargeint);
- isdn_net_hangup(p->dev);
- }
- } else
- isdn_net_hangup(p->dev);
- } else if (l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- }
-
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
- isdn_net_hangup(p->dev);
- break;
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- last_jiffies = jiffies;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
-}
-
-static void isdn_net_lp_disconnected(isdn_net_local *lp)
-{
- isdn_net_rm_from_bundle(lp);
-}
-
-/*
- * Handle status-messages from ISDN-interfacecard.
- * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the low-level driver.
- * Return: 1 = Event handled, 0 = not for us or unknown Event.
- */
-int
-isdn_net_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_net_dev *p = dev->st_netdev[idx];
- int cmd = c->command;
-
- if (p) {
- isdn_net_local *lp = p->local;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
- switch (cmd) {
- case ISDN_STAT_BSENT:
- /* A packet has successfully been sent out */
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_dec_frame_cnt(lp);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += c->parm.length;
- }
- return 1;
- case ISDN_STAT_DCONN:
- /* D-Channel is up */
- switch (lp->dialstate) {
- case 4:
- case 7:
- case 8:
- lp->dialstate++;
- return 1;
- case 12:
- lp->dialstate = 5;
- return 1;
- }
- break;
- case ISDN_STAT_DHUP:
- /* Either D-Channel-hangup or error during dialout */
-#ifdef CONFIG_ISDN_X25
- /* If we are not connencted then dialing had
- failed. If there are generic encap protocol
- receiver routines signal the closure of
- the link*/
-
- if (!(lp->flags & ISDN_NET_CONNECTED)
- && pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_disconnected(lp);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- printk(KERN_INFO "%s: remote hangup\n", p->dev->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name,
- lp->charge);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_STAT_BHUP:
- /* B-Channel-hangup */
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind) {
- pops->disconn_ind(cprot);
- return 1;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- case ISDN_STAT_BCONN:
- /* B-Channel is up */
- isdn_net_zero_frame_cnt(lp);
- switch (lp->dialstate) {
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 12:
- if (lp->dialstate <= 6) {
- dev->usage[idx] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- } else
- dev->rx_netdev[idx] = p;
- lp->dialstate = 0;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_connected(lp);
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
- if (lp->master) { /* is lp a slave? */
- isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev;
- isdn_net_add_to_bundle(nd, lp);
- }
- }
- printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- lp->chargetime = jiffies;
-
- /* reset dial-timeout */
- lp->dialstarted = 0;
- lp->dialwait_timer = 0;
-
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_wakeup_daemon(lp);
-#endif
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic concap receiver routines */
- if (pops)
- if (pops->connect_ind)
- pops->connect_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- /* ppp needs to do negotiations first */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- isdn_net_device_wake_queue(lp);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
- /* No D-Channel avail. */
- if (lp->dialstate == 4) {
- lp->dialstate--;
- return 1;
- }
- break;
- case ISDN_STAT_CINF:
- /* Charge-info from TelCo. Calculate interval between
- * charge-infos and set timestamp for last info for
- * usage by isdn_net_autohup()
- */
- lp->charge++;
- if (lp->hupflags & ISDN_HAVECHARGE) {
- lp->hupflags &= ~ISDN_WAITCHARGE;
- lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
- }
- if (lp->hupflags & ISDN_WAITCHARGE)
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
- p->dev->name, lp->chargetime);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Perform dialout for net-interfaces and timeout-handling for
- * D-Channel-up and B-Channel-up Messages.
- * This function is initially called from within isdn_net_start_xmit() or
- * or isdn_net_find_icall() after initializing the dialstate for an
- * interface. If further calls are needed, the function schedules itself
- * for a timer-callback via isdn_timer_function().
- * The dialstate is also affected by incoming status-messages from
- * the ISDN-Channel which are handled in isdn_net_stat_callback() above.
- */
-void
-isdn_net_dial(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore = 0;
- int i;
- isdn_ctrl cmd;
- u_char *phone_number;
-
- while (p) {
- isdn_net_local *lp = p->local;
-
-#ifdef ISDN_DEBUG_NET_DIAL
- if (lp->dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate);
-#endif
- switch (lp->dialstate) {
- case 0:
- /* Nothing to do for this interface */
- break;
- case 1:
- /* Initiate dialout. Set phone-number-pointer to first number
- * of interface.
- */
- lp->dial = lp->phone[1];
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- anymore = 1;
-
- if (lp->dialtimeout > 0)
- if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
- lp->dialstarted = jiffies;
- lp->dialwait_timer = 0;
- }
-
- lp->dialstate++;
- /* Fall through */
- case 2:
- /* Prepare dialing. Clear EAZ, then set EAZ. */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- lp->dialretry = 0;
- anymore = 1;
- lp->dialstate++;
- /* Fall through */
- case 3:
- /* Setup interface, dial current phone-number, switch to next number.
- * If list of phone-numbers is exhausted, increment
- * retry-counter.
- */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
- char *s;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- s = "dial suppressed: isdn system stopped";
- else
- s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(p->dev, NULL, s);
- isdn_net_hangup(p->dev);
- break;
- }
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
- lp->dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name);
- } else {
- if (lp->dialtimeout > 0)
- if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: timed out");
- isdn_net_hangup(p->dev);
- break;
- }
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_DIAL;
- cmd.parm.setup.si2 = 0;
-
- /* check for DOV */
- phone_number = lp->dial->num;
- if ((*phone_number == 'v') ||
- (*phone_number == 'V')) { /* DOV call */
- cmd.parm.setup.si1 = 1;
- } else { /* DATA call */
- cmd.parm.setup.si1 = 7;
- }
-
- strcpy(cmd.parm.setup.phone, phone_number);
- /*
- * Switch to next number or back to start if at end of list.
- */
- if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
- lp->dial = lp->phone[1];
- lp->dialretry++;
-
- if (lp->dialretry > lp->dialmax) {
- if (lp->dialtimeout == 0) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
- }
- isdn_net_hangup(p->dev);
- break;
- }
- }
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(lp->msn, cmd.driver));
- i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
- if (i >= 0) {
- strcpy(dev->num[i], cmd.parm.setup.phone);
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- }
- printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name,
- lp->dialretry, cmd.parm.setup.phone,
- (cmd.parm.setup.si1 == 1) ? "DOV" : "");
- lp->dtimer = 0;
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
- lp->isdn_channel);
-#endif
- isdn_command(&cmd);
- }
- lp->huptimer = 0;
- lp->outgoing = 1;
- if (lp->chargeint) {
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->hupflags &= ~ISDN_WAITCHARGE;
- } else {
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
- }
- anymore = 1;
- lp->dialstate =
- (lp->cbdelay &&
- (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
- break;
- case 4:
- /* Wait for D-Channel-connect.
- * If timeout, switch back to state 3.
- * Dialmax-handling moved to state 3.
- */
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 5:
- /* Got D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- isdn_command(&cmd);
- break;
- case 6:
- /* Wait for B- or D-Channel-connect. If timeout,
- * switch back to state 3.
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 7:
- /* Got incoming Call, setup L2 and L3 protocols,
- * then wait for D-Channel-connect
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(p->dev);
- else {
- anymore = 1;
- lp->dialstate++;
- }
- break;
- case 9:
- /* Got incoming D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- break;
- case 8:
- case 10:
- /* Wait for B- or D-channel-connect */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(p->dev);
- else
- anymore = 1;
- break;
- case 11:
- /* Callback Delay */
- if (lp->dtimer++ > lp->cbdelay)
- lp->dialstate = 1;
- anymore = 1;
- break;
- case 12:
- /* Remote does callback. Hangup after cbdelay, then wait for incoming
- * call (in state 4).
- */
- if (lp->dtimer++ > lp->cbdelay)
- {
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name);
- lp->dtimer = 0;
- lp->dialstate = 4;
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- anymore = 1;
- break;
- default:
- printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- lp->dialstate, p->dev->name);
- }
- p = (isdn_net_dev *) p->next;
- }
- isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
-}
-
-/*
- * Perform hangup for a net-interface.
- */
-void
-isdn_net_hangup(struct net_device *d)
-{
- isdn_net_local *lp = netdev_priv(d);
- isdn_ctrl cmd;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
-
- if (lp->flags & ISDN_NET_CONNECTED) {
- if (lp->slave != NULL) {
- isdn_net_local *slp = ISDN_SLAVE_PRIV(lp);
- if (slp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_INFO
- "isdn_net: hang up slave %s before %s\n",
- lp->slave->name, d->name);
- isdn_net_hangup(lp->slave);
- }
- }
- printk(KERN_INFO "isdn_net: local hangup %s\n", d->name);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- isdn_net_unbind_channel(lp);
-}
-
-typedef struct {
- __be16 source;
- __be16 dest;
-} ip_ports;
-
-static void
-isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp)
-{
- /* hopefully, this was set correctly */
- const u_char *p = skb_network_header(skb);
- unsigned short proto = ntohs(skb->protocol);
- int data_ofs;
- ip_ports *ipp;
- char addinfo[100];
-
- addinfo[0] = '\0';
- /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) {
- /* fall back to old isdn_net_log_packet method() */
- char *buf = skb->data;
-
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name);
- p = buf;
- proto = ETH_P_IP;
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(__be16 *)&buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(__be16 *)&buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(__be16 *)&buf[2]);
- p = &buf[4];
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- proto = ntohs(skb->protocol);
- p = &buf[IPPP_MAX_HEADER];
- break;
-#endif
- }
- }
- data_ofs = ((p[0] & 15) * 4);
- switch (proto) {
- case ETH_P_IP:
- switch (p[9]) {
- case 1:
- strcpy(addinfo, " ICMP");
- break;
- case 2:
- strcpy(addinfo, " IGMP");
- break;
- case 4:
- strcpy(addinfo, " IPIP");
- break;
- case 6:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 8:
- strcpy(addinfo, " EGP");
- break;
- case 12:
- strcpy(addinfo, " PUP");
- break;
- case 17:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 22:
- strcpy(addinfo, " IDP");
- break;
- }
- printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n",
- p + 12, p + 16, addinfo);
- break;
- case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n",
- p + 14, p + 24);
- break;
- }
-}
-
-/*
- * this function is used to send supervisory data, i.e. data which was
- * not received from the network layer, but e.g. frames from ipppd, CCP
- * reset frames etc.
- */
-void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
-{
- if (in_irq()) {
- // we can't grab the lock from irq context,
- // so we just queue the packet
- skb_queue_tail(&lp->super_tx_queue, skb);
- schedule_work(&lp->tqueue);
- return;
- }
-
- spin_lock_bh(&lp->xmit_lock);
- if (!isdn_net_lp_busy(lp)) {
- isdn_net_writebuf_skb(lp, skb);
- } else {
- skb_queue_tail(&lp->super_tx_queue, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * called from tq_immediate
- */
-static void isdn_net_softint(struct work_struct *work)
-{
- isdn_net_local *lp = container_of(work, isdn_net_local, tqueue);
- struct sk_buff *skb;
-
- spin_lock_bh(&lp->xmit_lock);
- while (!isdn_net_lp_busy(lp)) {
- skb = skb_dequeue(&lp->super_tx_queue);
- if (!skb)
- break;
- isdn_net_writebuf_skb(lp, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * all frames sent from the (net) LL to a HL driver should go via this function
- * it's serialized by the caller holding the lp->xmit_lock spinlock
- */
-void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
-{
- int ret;
- int len = skb->len; /* save len */
-
- /* before obtaining the lock the caller should have checked that
- the lp isn't busy */
- if (isdn_net_lp_busy(lp)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
- if (ret != len) {
- /* we should never get here */
- printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
- goto error;
- }
-
- lp->transcount += len;
- isdn_net_inc_frame_cnt(lp);
- return;
-
-error:
- dev_kfree_skb(skb);
- lp->stats.tx_errors++;
-
-}
-
-
-/*
- * Helper function for isdn_net_start_xmit.
- * When called, the connection is already established.
- * Based on cps-calculation, check if device is overloaded.
- * If so, and if a slave exists, trigger dialing for it.
- * If any slave is online, deliver packets using a simple round robin
- * scheme.
- *
- * Return: 0 on success, !0 on failure.
- */
-
-static int
-isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_dev *nd;
- isdn_net_local *slp;
- isdn_net_local *lp = netdev_priv(ndev);
- int retv = NETDEV_TX_OK;
-
- if (((isdn_net_local *) netdev_priv(ndev))->master) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- /* For the other encaps the header has already been built */
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- return isdn_ppp_xmit(skb, ndev);
- }
-#endif
- nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
- return NETDEV_TX_BUSY;
- }
- /* we have our lp locked from now on */
-
- /* Reset hangup-timeout */
- lp->huptimer = 0; // FIXME?
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
-
- /* the following stuff is here for backwards compatibility.
- * in future, start-up and hangup of slaves (based on current load)
- * should move to userspace and get based on an overall cps
- * calculation
- */
- if (lp->cps > lp->triggercps) {
- if (lp->slave) {
- if (!lp->sqfull) {
- /* First time overload: set timestamp only */
- lp->sqfull = 1;
- lp->sqfull_stamp = jiffies;
- } else {
- /* subsequent overload: if slavedelay exceeded, start dialing */
- if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
- slp = ISDN_SLAVE_PRIV(lp);
- if (!(slp->flags & ISDN_NET_CONNECTED)) {
- isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp));
- }
- }
- }
- }
- } else {
- if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
- lp->sqfull = 0;
- }
- /* this is a hack to allow auto-hangup for slaves on moderate loads */
- nd->queue = nd->local;
- }
-
- return retv;
-
-}
-
-static void
-isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (!skb)
- return;
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- const int pullsize = skb_network_offset(skb) - ETH_HLEN;
- if (pullsize > 0) {
- printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
- skb_pull(skb, pullsize);
- }
- }
-}
-
-
-static void isdn_net_tx_timeout(struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-
- printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
- if (!lp->dialstate) {
- lp->stats.tx_errors++;
- /*
- * There is a certain probability that this currently
- * works at all because if we always wake up the interface,
- * then upper layer will try to send the next packet
- * immediately. And then, the old clean_up logic in the
- * driver will hopefully continue to work as it used to do.
- *
- * This is rather primitive right know, we better should
- * clean internal queues here, in particular for multilink and
- * ppp, and reset HL driver's channel, too. --HE
- *
- * actually, this may not matter at all, because ISDN hardware
- * should not see transmitter hangs at all IMO
- * changed KERN_DEBUG to KERN_WARNING to find out if this is
- * ever called --KG
- */
- }
- netif_trans_update(ndev);
- netif_wake_queue(ndev);
-}
-
-/*
- * Try sending a packet.
- * If this interface isn't connected to a ISDN-Channel, find a free channel,
- * and start dialing.
- */
-static netdev_tx_t
-isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-/* At this point hard_start_xmit() passes control to the encapsulation
- protocol (if present).
- For X.25 auto-dialing is completly bypassed because:
- - It does not conform with the semantics of a reliable datalink
- service as needed by X.25 PLP.
- - I don't want that the interface starts dialing when the network layer
- sends a message which requests to disconnect the lapb link (or if it
- sends any other message not resulting in data transmission).
- Instead, dialing will be initiated by the encapsulation protocol entity
- when a dl_establish request is received from the upper layer.
-*/
- if (cprot && cprot->pops) {
- int ret = cprot->pops->encap_and_xmit(cprot, skb);
-
- if (ret)
- netif_stop_queue(ndev);
- return ret;
- } else
-#endif
- /* auto-dialing xmit function */
- {
-#ifdef ISDN_DEBUG_NET_DUMP
- u_char *buf;
-#endif
- isdn_net_adjust_hdr(skb, ndev);
-#ifdef ISDN_DEBUG_NET_DUMP
- buf = skb->data;
- isdn_dumppkt("S:", buf, skb->len, 40);
-#endif
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- int chi;
- /* only do autodial if allowed by config */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (lp->phone[1]) {
- ulong flags;
-
- if (lp->dialwait_timer <= 0)
- if (lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
- lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
-
- if (lp->dialwait_timer > 0) {
- if (time_before(jiffies, lp->dialwait_timer)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- lp->dialwait_timer = 0;
- }
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if (((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) &&
- ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel^1,
- lp->msn)
- ) < 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb,
- "No channel");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* Log packet, which triggered dialing */
- if (dev->net_verbose)
- isdn_net_log_skb(skb, lp);
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- /* no 'first_skb' handling for syncPPP */
- if (isdn_ppp_bind(lp) < 0) {
- dev_kfree_skb(skb);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */
- }
-#ifdef CONFIG_IPPP_FILTER
- if (isdn_ppp_autodial_filter(skb, lp)) {
- isdn_ppp_free(lp);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial(); /* Initiate dialing */
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- isdn_net_device_stop_queue(lp);
- return NETDEV_TX_BUSY;
- } else {
- isdn_net_unreachable(ndev, skb,
- "No phone number");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- } else {
- /* Device is connected to an ISDN channel */
- netif_trans_update(ndev);
- if (!lp->dialstate) {
- /* ISDN connection is established, try sending */
- int ret;
- ret = (isdn_net_xmit(ndev, skb));
- if (ret) netif_stop_queue(ndev);
- return ret;
- } else
- netif_stop_queue(ndev);
- }
- }
- return NETDEV_TX_BUSY;
-}
-
-/*
- * Shutdown a net-interface.
- */
-static int
-isdn_net_close(struct net_device *dev)
-{
- struct net_device *p;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
- /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name); */
-#endif
-
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops) cprot->pops->close(cprot);
-#endif
- netif_stop_queue(dev);
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- /* If this interface has slaves, stop them also */
- while (p) {
-#ifdef CONFIG_ISDN_X25
- cprot = ((isdn_net_local *)netdev_priv(p))
- ->netdev->cprot;
- if (cprot && cprot->pops)
- cprot->pops->close(cprot);
-#endif
- isdn_net_hangup(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_net_hangup(dev);
- isdn_unlock_drivers();
- return 0;
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *
-isdn_net_get_stats(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
- * instead of dev->hard_header_len off. This is done because the
- * lowlevel-driver has already pulled off its stuff when we get
- * here and this routine only gets called with p_encap == ETHER.
- * Determine the packet's protocol ID. The rule here is that we
- * assume 802.3 if the type field is short enough to be a length.
- * This is normal practice and works for any 'now in use' protocol.
- */
-
-static __be16
-isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct ethhdr *eth;
- unsigned char *rawp;
-
- skb_reset_mac_header(skb);
- skb_pull(skb, ETH_HLEN);
- eth = eth_hdr(skb);
-
- if (*eth->h_dest & 1) {
- if (ether_addr_equal(eth->h_dest, dev->broadcast))
- skb->pkt_type = PACKET_BROADCAST;
- else
- skb->pkt_type = PACKET_MULTICAST;
- }
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- */
-
- else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
- if (!ether_addr_equal(eth->h_dest, dev->dev_addr))
- skb->pkt_type = PACKET_OTHERHOST;
- }
- if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
- return eth->h_proto;
-
- rawp = skb->data;
-
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *) rawp == 0xFFFF)
- return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
-}
-
-
-/*
- * CISCO HDLC keepalive specific stuff
- */
-static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
-{
- unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- struct sk_buff *skb;
-
- skb = alloc_skb(hl + len, GFP_ATOMIC);
- if (skb)
- skb_reserve(skb, hl);
- else
- printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
- return skb;
-}
-
-/* cisco hdlck device private ioctls */
-static int
-isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned long len = 0;
- unsigned long expires = 0;
- int tmp = 0;
- int period = lp->cisco_keepalive_period;
- s8 debserint = lp->cisco_debserint;
- int rc = 0;
-
- if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
- return -EINVAL;
-
- switch (cmd) {
- /* get/set keepalive period */
- case SIOCGKEEPPERIOD:
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_keepalive_period, len))
- rc = -EFAULT;
- break;
- case SIOCSKEEPPERIOD:
- tmp = lp->cisco_keepalive_period;
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_from_user(&period, ifr->ifr_data, len))
- rc = -EFAULT;
- if ((period > 0) && (period <= 32767))
- lp->cisco_keepalive_period = period;
- else
- rc = -EINVAL;
- if (!rc && (tmp != lp->cisco_keepalive_period)) {
- expires = (unsigned long)(jiffies +
- lp->cisco_keepalive_period * HZ);
- mod_timer(&lp->cisco_timer, expires);
- printk(KERN_INFO "%s: Keepalive period set "
- "to %d seconds.\n",
- dev->name, lp->cisco_keepalive_period);
- }
- break;
-
- /* get/set debugging */
- case SIOCGDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_debserint, len))
- rc = -EFAULT;
- break;
- case SIOCSDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_from_user(&debserint,
- ifr->ifr_data, len))
- rc = -EFAULT;
- if ((debserint >= 0) && (debserint <= 64))
- lp->cisco_debserint = debserint;
- else
- rc = -EINVAL;
- break;
-
- default:
- rc = -EINVAL;
- break;
- }
- return (rc);
-}
-
-
-static int isdn_net_ioctl(struct net_device *dev,
- struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- switch (lp->p_encap) {
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- return isdn_ppp_dev_ioctl(dev, ifr, cmd);
-#endif
- case ISDN_NET_ENCAP_CISCOHDLCK:
- return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd);
- default:
- return -EINVAL;
- }
-}
-
-/* called via cisco_timer.function */
-static void
-isdn_net_ciscohdlck_slarp_send_keepalive(struct timer_list *t)
-{
- isdn_net_local *lp = from_timer(lp, t, cisco_timer);
- struct sk_buff *skb;
- unsigned char *p;
- unsigned long last_cisco_myseq = lp->cisco_myseq;
- int myseq_diff = 0;
-
- if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- return;
- }
- lp->cisco_myseq++;
-
- myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
- if ((lp->cisco_line_state) && ((myseq_diff >= 3) || (myseq_diff <= -3))) {
- /* line up -> down */
- lp->cisco_line_state = 0;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to down\n", lp->netdev->dev->name);
- /* should stop routing higher-level data across */
- } else if ((!lp->cisco_line_state) &&
- (myseq_diff >= 0) && (myseq_diff <= 2)) {
- /* line down -> up */
- lp->cisco_line_state = 1;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to up\n", lp->netdev->dev->name);
- /* restart routing higher-level data across */
- }
-
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: HDLC "
- "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen,
- ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
- lp->cisco_yourseq,
- ((lp->cisco_line_state) ? "line up" : "line down"));
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp keepalive */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
- *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq);
- *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
- *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff
- p += 18;
-
- isdn_net_write_super(lp, skb);
-
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp request */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST);
- *(__be32 *)(p + 8) = cpu_to_be32(0); // address
- *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_connected(isdn_net_local *lp)
-{
- lp->cisco_myseq = 0;
- lp->cisco_mineseen = 0;
- lp->cisco_yourseq = 0;
- lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
- lp->cisco_last_slarp_in = 0;
- lp->cisco_line_state = 0;
- lp->cisco_debserint = 0;
-
- /* send slarp request because interface/seq.no.s reset */
- isdn_net_ciscohdlck_slarp_send_request(lp);
-
- timer_setup(&lp->cisco_timer,
- isdn_net_ciscohdlck_slarp_send_keepalive, 0);
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
-{
- del_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
- struct in_device *in_dev = NULL;
- __be32 addr = 0; /* local ipv4 address */
- __be32 mask = 0; /* local netmask */
-
- if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
- /* take primary(first) address of interface */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL) {
- addr = ifa->ifa_local;
- mask = ifa->ifa_mask;
- }
- }
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp reply, send own ip/netmask; if values are nonsense remote
- * should think we are unable to provide it with an address via SLARP */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY);
- *(__be32 *)(p + 8) = addr; // address
- *(__be32 *)(p + 12) = mask; // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- int period;
- u32 code;
- u32 my_seq;
- u32 your_seq;
- __be32 local;
- __be32 *addr, *mask;
-
- if (skb->len < 14)
- return;
-
- p = skb->data;
- code = be32_to_cpup((__be32 *)p);
- p += 4;
-
- switch (code) {
- case CISCO_SLARP_REQUEST:
- lp->cisco_yourseq = 0;
- isdn_net_ciscohdlck_slarp_send_reply(lp);
- break;
- case CISCO_SLARP_REPLY:
- addr = (__be32 *)p;
- mask = (__be32 *)(p + 4);
- if (*mask != cpu_to_be32(0xfffffffc))
- goto slarp_reply_out;
- if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) ||
- (*addr & cpu_to_be32(3)) == cpu_to_be32(3))
- goto slarp_reply_out;
- local = *addr ^ cpu_to_be32(3);
- printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n",
- lp->netdev->dev->name, addr, &local, mask);
- break;
- slarp_reply_out:
- printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n",
- lp->netdev->dev->name, addr, mask);
- break;
- case CISCO_SLARP_KEEPALIVE:
- period = (int)((jiffies - lp->cisco_last_slarp_in
- + HZ / 2 - 1) / HZ);
- if (lp->cisco_debserint &&
- (period != lp->cisco_keepalive_period) &&
- lp->cisco_last_slarp_in) {
- printk(KERN_DEBUG "%s: Keepalive period mismatch - "
- "is %d but should be %d.\n",
- lp->netdev->dev->name, period,
- lp->cisco_keepalive_period);
- }
- lp->cisco_last_slarp_in = jiffies;
- my_seq = be32_to_cpup((__be32 *)(p + 0));
- your_seq = be32_to_cpup((__be32 *)(p + 4));
- p += 10;
- lp->cisco_yourseq = my_seq;
- lp->cisco_mineseen = your_seq;
- break;
- }
-}
-
-static void
-isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- u8 addr;
- u8 ctrl;
- u16 type;
-
- if (skb->len < 4)
- goto out_free;
-
- p = skb->data;
- addr = *(u8 *)(p + 0);
- ctrl = *(u8 *)(p + 1);
- type = be16_to_cpup((__be16 *)(p + 2));
- p += 4;
- skb_pull(skb, 4);
-
- if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
- printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
- lp->netdev->dev->name, addr);
- goto out_free;
- }
- if (ctrl != CISCO_CTRL) {
- printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
- lp->netdev->dev->name, ctrl);
- goto out_free;
- }
-
- switch (type) {
- case CISCO_TYPE_SLARP:
- isdn_net_ciscohdlck_slarp_in(lp, skb);
- goto out_free;
- case CISCO_TYPE_CDP:
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: Received CDP packet. use "
- "\"no cdp enable\" on cisco.\n",
- lp->netdev->dev->name);
- goto out_free;
- default:
- /* no special cisco protocol */
- skb->protocol = htons(type);
- netif_rx(skb);
- return;
- }
-
-out_free:
- kfree_skb(skb);
-}
-
-/*
- * Got a packet from ISDN-Channel.
- */
-static void
-isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_local *lp = netdev_priv(ndev);
- isdn_net_local *olp = lp; /* original 'lp' */
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-#endif
- lp->transcount += skb->len;
-
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- if (lp->master) {
- /* Bundling: If device is a slave-device, deliver to master, also
- * handle master's statistics and hangup-timeout
- */
- ndev = lp->master;
- lp = netdev_priv(ndev);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- }
- skb->dev = ndev;
- skb->pkt_type = PACKET_HOST;
- skb_reset_mac_header(skb);
-#ifdef ISDN_DEBUG_NET_DUMP
- isdn_dumppkt("R:", skb->data, skb->len, 40);
-#endif
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- /* Ethernet over ISDN */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = isdn_net_type_trans(skb, ndev);
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-frame (for ispa with -h1 option) */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_RAWIP:
- /* RAW-IP without MAC-Header */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = htons(ETH_P_IP);
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- isdn_net_ciscohdlck_receive(lp, skb);
- return;
- case ISDN_NET_ENCAP_CISCOHDLC:
- /* CISCO-HDLC IP with type field and fake I-frame-header */
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_IPTYP:
- /* IP with type field */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = *(__be16 *)&(skb->data[0]);
- skb_pull(skb, 2);
- if (*(unsigned short *) skb->data == 0xFFFF)
- skb->protocol = htons(ETH_P_802_3);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* huptimer is done in isdn_ppp_push_higher */
- isdn_ppp_receive(lp->netdev, olp, skb);
- return;
-#endif
-
- default:
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic sync_device receiver routines */
- if (cprot) if (cprot->pops)
- if (cprot->pops->data_ind) {
- cprot->pops->data_ind(cprot, skb);
- return;
- };
-#endif /* CONFIG_ISDN_X25 */
- printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->netdev->dev->name);
- kfree_skb(skb);
- return;
- }
-
- netif_rx(skb);
- return;
-}
-
-/*
- * A packet arrived via ISDN. Search interface-chain for a corresponding
- * interface. If found, deliver packet to receiver-function and return 1,
- * else return 0.
- */
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb)
-{
- isdn_net_dev *p = dev->rx_netdev[idx];
-
- if (p) {
- isdn_net_local *lp = p->local;
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_receive(p->dev, skb);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * build an header
- * depends on encaps that is being used.
- */
-
-static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned plen)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned char *p;
- int len = 0;
-
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- len = eth_header(skb, dev, type, daddr, saddr, plen);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* stick on a fake header to keep fragmentation code happy. */
- len = IPPP_MAX_HEADER;
- skb_push(skb, len);
- break;
-#endif
- case ISDN_NET_ENCAP_RAWIP:
- printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
- len = 0;
- break;
- case ISDN_NET_ENCAP_IPTYP:
- /* ethernet type field */
- *((__be16 *)skb_push(skb, 2)) = htons(type);
- len = 2;
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-Frames (for ispa with -h1 option) */
- *((__be16 *)skb_push(skb, 2)) = htons(0x0103);
- len = 2;
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- case ISDN_NET_ENCAP_CISCOHDLCK:
- p = skb_push(skb, 4);
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(type);
- p += 4;
- len = 4;
- break;
-#ifdef CONFIG_ISDN_X25
- default:
- /* try if there are generic concap protocol routines */
- if (lp->netdev->cprot) {
- printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
- len = 0;
- break;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- }
- return len;
-}
-
-static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
- __be16 type)
-{
- const struct net_device *dev = neigh->dev;
- isdn_net_local *lp = netdev_priv(dev);
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- return eth_header_cache(neigh, hh, type);
- return -1;
-}
-
-static void isdn_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char *haddr)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- eth_header_cache_update(hh, dev, haddr);
-}
-
-static const struct header_ops isdn_header_ops = {
- .create = isdn_net_header,
- .cache = isdn_header_cache,
- .cache_update = isdn_header_cache_update,
-};
-
-/*
- * Interface-setup. (just after registering a new interface)
- */
-static int
-isdn_net_init(struct net_device *ndev)
-{
- ushort max_hlhdr_len = 0;
- int drvidx;
-
- /*
- * up till binding we ask the protocol layer to reserve as much
- * as we might need for HL layer
- */
-
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (dev->drv[drvidx])
- if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
- max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
-
- ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
- return 0;
-}
-
-static void
-isdn_net_swapbind(int drvidx)
-{
- isdn_net_dev *p;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
-#endif
- p = dev->netdev;
- while (p) {
- if (p->local->pre_device == drvidx)
- switch (p->local->pre_channel) {
- case 0:
- p->local->pre_channel = 1;
- break;
- case 1:
- p->local->pre_channel = 0;
- break;
- }
- p = (isdn_net_dev *) p->next;
- }
-}
-
-static void
-isdn_net_swap_usage(int i1, int i2)
-{
- int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
- int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
-#endif
- dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i1] |= u2;
- dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i2] |= u1;
- isdn_info_update();
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the interface-chain for an appropriate interface.
- * If found, connect the interface to the ISDN-channel and initiate
- * D- and B-Channel-setup. If secure-flag is set, accept only
- * configured phone-numbers. If callback-flag is set, initiate
- * callback-dialing.
- *
- * Return-Value: 0 = No appropriate interface for this call.
- * 1 = Call accepted
- * 2 = Reject call, wait cbdelay, then call back
- * 3 = Reject call
- * 4 = Wait cbdelay, then call back
- * 5 = No appropriate interface for this call,
- * would eventually match if CID was longer.
- */
-
-int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
-{
- char *eaz;
- int si1;
- int si2;
- int ematch;
- int wret;
- int swapped;
- int sidx = 0;
- u_long flags;
- isdn_net_dev *p;
- isdn_net_phone *n;
- char nr[ISDN_MSNLEN];
- char *my_eaz;
-
- /* Search name in netdev-chain */
- if (!setup->phone[0]) {
- nr[0] = '0';
- nr[1] = '\0';
- printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
- } else
- strlcpy(nr, setup->phone, ISDN_MSNLEN);
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
- /* Accept DATA and VOICE calls at this stage
- * local eaz is checked later for allowed call types
- */
- if ((si1 != 7) && (si1 != 1)) {
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
- return 0;
- }
- n = (isdn_net_phone *) 0;
- p = dev->netdev;
- ematch = wret = swapped = 0;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
- dev->usage[idx]);
-#endif
- while (p) {
- int matchret;
- isdn_net_local *lp = p->local;
-
- /* If last check has triggered as binding-swap, revert it */
- switch (swapped) {
- case 2:
- isdn_net_swap_usage(idx, sidx);
- /* fall through */
- case 1:
- isdn_net_swapbind(di);
- break;
- }
- swapped = 0;
- /* check acceptable call types for DOV */
- my_eaz = isdn_map_eaz2msn(lp->msn, di);
- if (si1 == 1) { /* it's a DOV call, check if we allow it */
- if (*my_eaz == 'v' || *my_eaz == 'V' ||
- *my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- else
- my_eaz = NULL; /* force non match */
- } else { /* it's a DATA call, check if we allow it */
- if (*my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- }
- if (my_eaz)
- matchret = isdn_msncmp(eaz, my_eaz);
- else
- matchret = 1;
- if (!matchret)
- ematch = 1;
-
- /* Remember if more numbers eventually can match */
- if (matchret > wret)
- wret = matchret;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- p->dev->name, lp->msn, lp->flags, lp->dialstate);
-#endif
- if ((!matchret) && /* EAZ is matching */
- (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
- (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
- (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
- )))
- {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
- lp->pre_device, lp->pre_channel);
-#endif
- if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
- if ((lp->pre_channel != ch) ||
- (lp->pre_device != di)) {
- /* Here we got a problem:
- * If using an ICN-Card, an incoming call is always signaled on
- * on the first channel of the card, if both channels are
- * down. However this channel may be bound exclusive. If the
- * second channel is free, this call should be accepted.
- * The solution is horribly but it runs, so what:
- * We exchange the exclusive bindings of the two channels, the
- * corresponding variables in the interface-structs.
- */
- if (ch == 0) {
- sidx = isdn_dc2minor(di, 1);
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: ch is 0\n");
-#endif
- if (USG_NONE(dev->usage[sidx])) {
- /* Second Channel is free, now see if it is bound
- * exclusive too. */
- if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
-#endif
- /* Yes, swap bindings only, if the original
- * binding is bound to channel 1 of this driver */
- if ((lp->pre_device == di) &&
- (lp->pre_channel == 1)) {
- isdn_net_swapbind(di);
- swapped = 1;
- } else {
- /* ... else iterate next device */
- p = (isdn_net_dev *) p->next;
- continue;
- }
- } else {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
-#endif
- /* No, swap always and swap excl-usage also */
- isdn_net_swap_usage(idx, sidx);
- isdn_net_swapbind(di);
- swapped = 2;
- }
- /* Now check for exclusive binding again */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check\n");
-#endif
- if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
- ((lp->pre_channel != ch) ||
- (lp->pre_device != di))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check failed\n");
-#endif
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- } else {
- /* We are already on the second channel, so nothing to do */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
-#endif
- }
- }
- }
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match2\n");
-#endif
- n = lp->phone[0];
- if (lp->flags & ISDN_NET_SECURE) {
- while (n) {
- if (!isdn_msncmp(nr, n->num))
- break;
- n = (isdn_net_phone *) n->next;
- }
- }
- if (n || (!(lp->flags & ISDN_NET_SECURE))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match3\n");
-#endif
- /* matching interface found */
-
- /*
- * Is the state STOPPED?
- * If so, no dialin is allowed,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
- p->dev->name);
- return 3;
- }
- /*
- * Is the interface up?
- * If not, reject the call actively.
- */
- if (!isdn_net_device_started(p)) {
- printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
- p->dev->name);
- return 3;
- }
- /* Interface is up, now see if it's a slave. If so, see if
- * it's master and parent slave is online. If not, reject the call.
- */
- if (lp->master) {
- isdn_net_local *mlp = ISDN_MASTER_PRIV(lp);
- printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
- printk(KERN_DEBUG "master=%s\n", lp->master->name);
- if (mlp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_DEBUG "master online\n");
- /* Master is online, find parent-slave (master if first slave) */
- while (mlp->slave) {
- if (ISDN_SLAVE_PRIV(mlp) == lp)
- break;
- mlp = ISDN_SLAVE_PRIV(mlp);
- }
- } else
- printk(KERN_DEBUG "master offline\n");
- /* Found parent, if it's offline iterate next device */
- printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
- if (!(mlp->flags & ISDN_NET_CONNECTED)) {
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- if (lp->flags & ISDN_NET_CALLBACK) {
- int chi;
- /*
- * Is the state MANUAL?
- * If so, no callback can be made,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- p->dev->name);
- return 3;
- }
- printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
- p->dev->name, nr, eaz);
- if (lp->phone[1]) {
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) {
-
- printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n",
- p->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- /* Setup dialstate. */
- lp->dtimer = 0;
- lp->dialstate = 11;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unbind_channel(lp);
- return 0;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- /* Initiate dialing by returning 2 or 4 */
- return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
- } else
- printk(KERN_WARNING "isdn_net: %s: No phone number\n",
- p->dev->name);
- return 0;
- } else {
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
- p->dev->name, nr, eaz);
- /* if this interface is dialing, it does it probably on a different
- device, so free this device */
- if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- }
- spin_lock_irqsave(&dev->lock, flags);
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= ISDN_USAGE_NET;
- strcpy(dev->num[idx], nr);
- isdn_info_update();
- dev->st_netdev[idx] = lp->netdev;
- lp->isdn_device = di;
- lp->isdn_channel = ch;
- lp->ppp_slot = -1;
- lp->flags |= ISDN_NET_CONNECTED;
- lp->dialstate = 7;
- lp->dtimer = 0;
- lp->outgoing = 0;
- lp->huptimer = 0;
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
- }
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- /* If none of configured EAZ/MSN matched and not verbose, be silent */
- if (!ematch || dev->net_verbose)
- printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
- return (wret == 2) ? 5 : 0;
-}
-
-/*
- * Search list of net-interfaces for an interface with given name.
- */
-isdn_net_dev *
-isdn_net_findif(char *name)
-{
- isdn_net_dev *p = dev->netdev;
-
- while (p) {
- if (!strcmp(p->dev->name, name))
- return p;
- p = (isdn_net_dev *) p->next;
- }
- return (isdn_net_dev *) NULL;
-}
-
-/*
- * Force a net-interface to dial out.
- * This is called from the userlevel-routine below or
- * from isdn_net_start_xmit().
- */
-static int
-isdn_net_force_dial_lp(isdn_net_local *lp)
-{
- if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
- int chi;
- if (lp->phone[1]) {
- ulong flags;
-
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi = isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)) < 0) {
- printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n",
- lp->netdev->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- return 0;
- } else
- return -EINVAL;
- } else
- return -EBUSY;
-}
-
-/*
- * This is called from certain upper protocol layers (multilink ppp
- * and x25iface encapsulation module) that want to initiate dialing
- * themselves.
- */
-int
-isdn_net_dial_req(isdn_net_local *lp)
-{
- /* is there a better error code? */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
-
- return isdn_net_force_dial_lp(lp);
-}
-
-/*
- * Force a net-interface to dial out.
- * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
- */
-int
-isdn_net_force_dial(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
-
- if (!p)
- return -ENODEV;
- return (isdn_net_force_dial_lp(p->local));
-}
-
-/* The ISDN-specific entries in the device structure. */
-static const struct net_device_ops isdn_netdev_ops = {
- .ndo_init = isdn_net_init,
- .ndo_open = isdn_net_open,
- .ndo_stop = isdn_net_close,
- .ndo_do_ioctl = isdn_net_ioctl,
-
- .ndo_start_xmit = isdn_net_start_xmit,
- .ndo_get_stats = isdn_net_get_stats,
- .ndo_tx_timeout = isdn_net_tx_timeout,
-};
-
-/*
- * Helper for alloc_netdev()
- */
-static void _isdn_setup(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- ether_setup(dev);
-
- /* Setup the generic properties */
- dev->flags = IFF_NOARP | IFF_POINTOPOINT;
-
- /* isdn prepends a header in the tx path, can't share skbs */
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->header_ops = NULL;
- dev->netdev_ops = &isdn_netdev_ops;
-
- /* for clients with MPPP maybe higher values better */
- dev->tx_queue_len = 30;
-
- lp->p_encap = ISDN_NET_ENCAP_RAWIP;
- lp->magic = ISDN_NET_MAGIC;
- lp->last = lp;
- lp->next = lp;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
- lp->pre_device = -1;
- lp->pre_channel = -1;
- lp->exclusive = -1;
- lp->ppp_slot = -1;
- lp->pppbind = -1;
- skb_queue_head_init(&lp->super_tx_queue);
- lp->l2_proto = ISDN_PROTO_L2_X75I;
- lp->l3_proto = ISDN_PROTO_L3_TRANS;
- lp->triggercps = 6000;
- lp->slavedelay = 10 * HZ;
- lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- lp->onhtime = 10; /* Default hangup-time for saving costs */
- lp->dialmax = 1;
- /* Hangup before Callback, manual dial */
- lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
- lp->cbdelay = 25; /* Wait 5 secs before Callback */
- lp->dialtimeout = -1; /* Infinite Dial-Timeout */
- lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- lp->dialstarted = 0; /* Jiffies of last dial-start */
- lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-}
-
-/*
- * Allocate a new network-interface and initialize its data structures.
- */
-char *
-isdn_net_new(char *name, struct net_device *master)
-{
- isdn_net_dev *netdev;
-
- /* Avoid creating an existing interface */
- if (isdn_net_findif(name)) {
- printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
- return NULL;
- }
- if (name == NULL)
- return NULL;
- if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
- return NULL;
- }
- netdev->dev = alloc_netdev(sizeof(isdn_net_local), name,
- NET_NAME_UNKNOWN, _isdn_setup);
- if (!netdev->dev) {
- printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
- kfree(netdev);
- return NULL;
- }
- netdev->local = netdev_priv(netdev->dev);
-
- if (master) {
- /* Device shall be a slave */
- struct net_device *p = MASTER_TO_SLAVE(master);
- struct net_device *q = master;
-
- netdev->local->master = master;
- /* Put device at end of slave-chain */
- while (p) {
- q = p;
- p = MASTER_TO_SLAVE(p);
- }
- MASTER_TO_SLAVE(q) = netdev->dev;
- } else {
- /* Device shall be a master */
- /*
- * Watchdog timer (currently) for master only.
- */
- netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- if (register_netdev(netdev->dev) != 0) {
- printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- free_netdev(netdev->dev);
- kfree(netdev);
- return NULL;
- }
- }
- netdev->queue = netdev->local;
- spin_lock_init(&netdev->queue_lock);
-
- netdev->local->netdev = netdev;
-
- INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
- spin_lock_init(&netdev->local->xmit_lock);
-
- /* Put into to netdev-chain */
- netdev->next = (void *) dev->netdev;
- dev->netdev = netdev;
- return netdev->dev->name;
-}
-
-char *
-isdn_net_newslave(char *parm)
-{
- char *p = strchr(parm, ',');
- isdn_net_dev *n;
- char newname[10];
-
- if (p) {
- /* Slave-Name MUST not be empty or overflow 'newname' */
- if (strscpy(newname, p + 1, sizeof(newname)) <= 0)
- return NULL;
- *p = 0;
- /* Master must already exist */
- if (!(n = isdn_net_findif(parm)))
- return NULL;
- /* Master must be a real interface, not a slave */
- if (n->local->master)
- return NULL;
- /* Master must not be started yet */
- if (isdn_net_device_started(n))
- return NULL;
- return (isdn_net_new(newname, n->dev));
- }
- return NULL;
-}
-
-/*
- * Set interface-parameters.
- * Always set all parameters, so the user-level application is responsible
- * for not overwriting existing setups. It has to get the current
- * setup first, if only selected parameters are to be changed.
- */
-int
-isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
- ulong features;
- int i;
- int drvidx;
- int chidx;
- char drvid[25];
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- /* See if any registered driver supports the features we want */
- features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
- ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (dev->drv[i])
- if ((dev->drv[i]->interface->features & features) == features)
- break;
- if (i == ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "isdn_net: No driver with selected features\n");
- return -ENODEV;
- }
- if (lp->p_encap != cfg->p_encap) {
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = p->cprot;
-#endif
- if (isdn_net_device_started(p)) {
- printk(KERN_WARNING "%s: cannot change encap when if is up\n",
- p->dev->name);
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops)
- cprot->pops->proto_del(cprot);
- p->cprot = NULL;
- lp->dops = NULL;
- /* ... , prepare for configuration of new one ... */
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- lp->dops = &isdn_concap_reliable_dl_dops;
- }
- /* ... and allocate new one ... */
- p->cprot = isdn_concap_new(cfg->p_encap);
- /* p -> cprot == NULL now if p_encap is not supported
- by means of the concap_proto mechanism */
- /* the protocol is not configured yet; this will
- happen later when isdn_net_reset() is called */
-#endif
- }
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_SYNCPPP:
-#ifndef CONFIG_ISDN_PPP
- printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_PPP; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_X25IFACE:
-#ifndef CONFIG_ISDN_X25
- printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_X25; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- break;
- default:
- if (cfg->p_encap >= 0 &&
- cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP)
- break;
- printk(KERN_WARNING
- "%s: encapsulation protocol %d not supported\n",
- p->dev->name, cfg->p_encap);
- return -EINVAL;
- }
- if (strlen(cfg->drvid)) {
- /* A bind has been requested ... */
- char *c,
- *e;
-
- if (strnlen(cfg->drvid, sizeof(cfg->drvid)) ==
- sizeof(cfg->drvid))
- return -EINVAL;
- drvidx = -1;
- chidx = -1;
- strcpy(drvid, cfg->drvid);
- if ((c = strchr(drvid, ','))) {
- /* The channel-number is appended to the driver-Id with a comma */
- chidx = (int) simple_strtoul(c + 1, &e, 10);
- if (e == c)
- chidx = -1;
- *c = '\0';
- }
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- /* Lookup driver-Id in array */
- if (!(strcmp(dev->drvid[i], drvid))) {
- drvidx = i;
- break;
- }
- if ((drvidx == -1) || (chidx == -1))
- /* Either driver-Id or channel-number invalid */
- return -ENODEV;
- } else {
- /* Parameters are valid, so get them */
- drvidx = lp->pre_device;
- chidx = lp->pre_channel;
- }
- if (cfg->exclusive > 0) {
- unsigned long flags;
-
- /* If binding is exclusive, try to grab the channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
- lp->l2_proto, lp->l3_proto, drvidx,
- chidx, lp->msn)) < 0) {
- /* Grab failed, because desired channel is in use */
- lp->exclusive = -1;
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EBUSY;
- }
- /* All went ok, so update isdninfo */
- dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- lp->exclusive = i;
- } else {
- /* Non-exclusive binding or unbind. */
- lp->exclusive = -1;
- if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
- isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
- isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
- drvidx = -1;
- chidx = -1;
- }
- }
- strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn));
- lp->pre_device = drvidx;
- lp->pre_channel = chidx;
- lp->onhtime = cfg->onhtime;
- lp->charge = cfg->charge;
- lp->l2_proto = cfg->l2_proto;
- lp->l3_proto = cfg->l3_proto;
- lp->cbdelay = cfg->cbdelay;
- lp->dialmax = cfg->dialmax;
- lp->triggercps = cfg->triggercps;
- lp->slavedelay = cfg->slavedelay * HZ;
- lp->pppbind = cfg->pppbind;
- lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
- lp->dialwait = cfg->dialwait * HZ;
- if (cfg->secure)
- lp->flags |= ISDN_NET_SECURE;
- else
- lp->flags &= ~ISDN_NET_SECURE;
- if (cfg->cbhup)
- lp->flags |= ISDN_NET_CBHUP;
- else
- lp->flags &= ~ISDN_NET_CBHUP;
- switch (cfg->callback) {
- case 0:
- lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
- break;
- case 1:
- lp->flags |= ISDN_NET_CALLBACK;
- lp->flags &= ~ISDN_NET_CBOUT;
- break;
- case 2:
- lp->flags |= ISDN_NET_CBOUT;
- lp->flags &= ~ISDN_NET_CALLBACK;
- break;
- }
- lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
- if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
- /* old isdnctrl version, where only 0 or 1 is given */
- printk(KERN_WARNING
- "Old isdnctrl version detected! Please update.\n");
- lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
- }
- else {
- lp->flags |= cfg->dialmode; /* turn on selected bits */
- }
- if (cfg->chargehup)
- lp->hupflags |= ISDN_CHARGEHUP;
- else
- lp->hupflags &= ~ISDN_CHARGEHUP;
- if (cfg->ihup)
- lp->hupflags |= ISDN_INHUP;
- else
- lp->hupflags &= ~ISDN_INHUP;
- if (cfg->chargeint > 10) {
- lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
- lp->chargeint = cfg->chargeint * HZ;
- }
- if (cfg->p_encap != lp->p_encap) {
- if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev->header_ops = NULL;
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- } else {
- p->dev->header_ops = &isdn_header_ops;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
- p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- else
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- }
- }
- lp->p_encap = cfg->p_encap;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Perform get-interface-parameters.ioctl
- */
-int
-isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- strcpy(cfg->eaz, lp->msn);
- cfg->exclusive = lp->exclusive;
- if (lp->pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
- lp->pre_channel);
- } else
- cfg->drvid[0] = '\0';
- cfg->onhtime = lp->onhtime;
- cfg->charge = lp->charge;
- cfg->l2_proto = lp->l2_proto;
- cfg->l3_proto = lp->l3_proto;
- cfg->p_encap = lp->p_encap;
- cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg->callback = 0;
- if (lp->flags & ISDN_NET_CALLBACK)
- cfg->callback = 1;
- if (lp->flags & ISDN_NET_CBOUT)
- cfg->callback = 2;
- cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
- cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
- cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
- cfg->cbdelay = lp->cbdelay;
- cfg->dialmax = lp->dialmax;
- cfg->triggercps = lp->triggercps;
- cfg->slavedelay = lp->slavedelay / HZ;
- cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
- (lp->chargeint / HZ) : 0;
- cfg->pppbind = lp->pppbind;
- cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
- cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave) {
- if (strlen(lp->slave->name) >= 10)
- strcpy(cfg->slave, "too-long");
- else
- strcpy(cfg->slave, lp->slave->name);
- } else
- cfg->slave[0] = '\0';
- if (lp->master) {
- if (strlen(lp->master->name) >= 10)
- strcpy(cfg->master, "too-long");
- else
- strcpy(cfg->master, lp->master->name);
- } else
- cfg->master[0] = '\0';
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Add a phone-number to an interface.
- */
-int
-isdn_net_addphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- isdn_net_phone *n;
-
- if (p) {
- if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
- return -ENOMEM;
- strlcpy(n->num, phone->phone, sizeof(n->num));
- n->next = p->local->phone[phone->outgoing & 1];
- p->local->phone[phone->outgoing & 1] = n;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Copy a string of all phone-numbers of an interface to user space.
- * This might sleep and must be called with the isdn semaphore down.
- */
-int
-isdn_net_getphones(isdn_net_ioctl_phone *phone, char __user *phones)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- int more = 0;
- int count = 0;
- isdn_net_phone *n;
-
- if (!p)
- return -ENODEV;
- inout &= 1;
- for (n = p->local->phone[inout]; n; n = n->next) {
- if (more) {
- put_user(' ', phones++);
- count++;
- }
- if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
- return -EFAULT;
- }
- phones += strlen(n->num);
- count += strlen(n->num);
- more = 1;
- }
- put_user(0, phones);
- count++;
- return count;
-}
-
-/*
- * Copy a string containing the peer's phone number of a connected interface
- * to user space.
- */
-int
-isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int ch, dv, idx;
-
- if (!p)
- return -ENODEV;
- /*
- * Theoretical race: while this executes, the remote number might
- * become invalid (hang up) or change (new connection), resulting
- * in (partially) wrong number copied to user. This race
- * currently ignored.
- */
- ch = p->local->isdn_channel;
- dv = p->local->isdn_device;
- if (ch < 0 && dv < 0)
- return -ENOTCONN;
- idx = isdn_dc2minor(dv, ch);
- if (idx < 0)
- return -ENODEV;
- /* for pre-bound channels, we need this extra check */
- if (strncmp(dev->num[idx], "???", 3) == 0)
- return -ENOTCONN;
- strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN);
- phone->outgoing = USG_OUTGOING(dev->usage[idx]);
- if (copy_to_user(peer, phone, sizeof(*peer)))
- return -EFAULT;
- return 0;
-}
-/*
- * Delete a phone-number from an interface.
- */
-int
-isdn_net_delphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- isdn_net_phone *n;
- isdn_net_phone *m;
-
- if (p) {
- n = p->local->phone[inout];
- m = NULL;
- while (n) {
- if (!strcmp(n->num, phone->phone)) {
- if (p->local->dial == n)
- p->local->dial = n->next;
- if (m)
- m->next = n->next;
- else
- p->local->phone[inout] = n->next;
- kfree(n);
- return 0;
- }
- m = n;
- n = (isdn_net_phone *) n->next;
- }
- return -EINVAL;
- }
- return -ENODEV;
-}
-
-/*
- * Delete all phone-numbers of an interface.
- */
-static int
-isdn_net_rmallphone(isdn_net_dev *p)
-{
- isdn_net_phone *n;
- isdn_net_phone *m;
- int i;
-
- for (i = 0; i < 2; i++) {
- n = p->local->phone[i];
- while (n) {
- m = n->next;
- kfree(n);
- n = m;
- }
- p->local->phone[i] = NULL;
- }
- p->local->dial = NULL;
- return 0;
-}
-
-/*
- * Force a hangup of a network-interface.
- */
-int
-isdn_net_force_hangup(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
- struct net_device *q;
-
- if (p) {
- if (p->local->isdn_device < 0)
- return 1;
- q = p->local->slave;
- /* If this interface has slaves, do a hangup for them also. */
- while (q) {
- isdn_net_hangup(q);
- q = MASTER_TO_SLAVE(q);
- }
- isdn_net_hangup(p->dev);
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Helper-function for isdn_net_rm: Do the real work.
- */
-static int
-isdn_net_realrm(isdn_net_dev *p, isdn_net_dev *q)
-{
- u_long flags;
-
- if (isdn_net_device_started(p)) {
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (p->cprot && p->cprot->pops)
- p->cprot->pops->proto_del(p->cprot);
-#endif
- /* Free all phone-entries */
- isdn_net_rmallphone(p);
- /* If interface is bound exclusive, free channel-usage */
- if (p->local->exclusive != -1)
- isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
- if (p->local->master) {
- /* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave ==
- p->dev)
- ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave =
- p->local->slave;
- } else {
- /* Unregister only if it's a master-device */
- unregister_netdev(p->dev);
- }
- /* Unlink device from chain */
- spin_lock_irqsave(&dev->lock, flags);
- if (q)
- q->next = p->next;
- else
- dev->netdev = p->next;
- if (p->local->slave) {
- /* If this interface has a slave, remove it also */
- char *slavename = p->local->slave->name;
- isdn_net_dev *n = dev->netdev;
- q = NULL;
- while (n) {
- if (!strcmp(n->dev->name, slavename)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_realrm(n, q);
- spin_lock_irqsave(&dev->lock, flags);
- break;
- }
- q = n;
- n = (isdn_net_dev *)n->next;
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- free_netdev(p->dev);
- kfree(p);
-
- return 0;
-}
-
-/*
- * Remove a single network-interface.
- */
-int
-isdn_net_rm(char *name)
-{
- u_long flags;
- isdn_net_dev *p;
- isdn_net_dev *q;
-
- /* Search name in netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- p = dev->netdev;
- q = NULL;
- while (p) {
- if (!strcmp(p->dev->name, name)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return (isdn_net_realrm(p, q));
- }
- q = p;
- p = (isdn_net_dev *) p->next;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- return -ENODEV;
-}
-
-/*
- * Remove all network-interfaces
- */
-int
-isdn_net_rmall(void)
-{
- u_long flags;
- int ret;
-
- /* Walk through netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- while (dev->netdev) {
- if (!dev->netdev->local->master) {
- /* Remove master-devices only, slaves get removed with their master */
- spin_unlock_irqrestore(&dev->lock, flags);
- if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
- return ret;
- }
- spin_lock_irqsave(&dev->lock, flags);
- }
- }
- dev->netdev = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
-}
+++ /dev/null
-/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, network related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Definitions for hupflags: */
-#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
-#define ISDN_HAVECHARGE 2 /* We know a charge info */
-#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
-#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
-#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
-
-/*
- * Definitions for Cisco-HDLC header.
- */
-
-#define CISCO_ADDR_UNICAST 0x0f
-#define CISCO_ADDR_BROADCAST 0x8f
-#define CISCO_CTRL 0x00
-#define CISCO_TYPE_CDP 0x2000
-#define CISCO_TYPE_SLARP 0x8035
-#define CISCO_SLARP_REQUEST 0
-#define CISCO_SLARP_REPLY 1
-#define CISCO_SLARP_KEEPALIVE 2
-
-extern char *isdn_net_new(char *, struct net_device *);
-extern char *isdn_net_newslave(char *);
-extern int isdn_net_rm(char *);
-extern int isdn_net_rmall(void);
-extern int isdn_net_stat_callback(int, isdn_ctrl *);
-extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_addphone(isdn_net_ioctl_phone *);
-extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
-extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
-extern int isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int isdn_net_find_icall(int, int, int, setup_parm *);
-extern void isdn_net_hangup(struct net_device *);
-extern void isdn_net_dial(void);
-extern void isdn_net_autohup(void);
-extern int isdn_net_force_hangup(char *);
-extern int isdn_net_force_dial(char *);
-extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_rcv_skb(int, struct sk_buff *);
-extern int isdn_net_dial_req(isdn_net_local *);
-extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
-extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
-
-#define ISDN_NET_MAX_QUEUE_LENGTH 2
-
-#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master))
-#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave))
-#define MASTER_TO_SLAVE(master) \
- (((isdn_net_local *) netdev_priv(master))->slave)
-
-/*
- * is this particular channel busy?
- */
-static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
-{
- if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
- return 0;
- else
- return 1;
-}
-
-/*
- * For the given net device, this will get a non-busy channel out of the
- * corresponding bundle. The returned channel is locked.
- */
-static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd)
-{
- unsigned long flags;
- isdn_net_local *lp;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- lp = nd->queue; /* get lp on top of queue */
- while (isdn_net_lp_busy(nd->queue)) {
- nd->queue = nd->queue->next;
- if (nd->queue == lp) { /* not found -- should never happen */
- lp = NULL;
- goto errout;
- }
- }
- lp = nd->queue;
- nd->queue = nd->queue->next;
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- spin_lock(&lp->xmit_lock);
- local_bh_disable();
- return lp;
-errout:
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return lp;
-}
-
-/*
- * add a channel to a bundle
- */
-static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
-{
- isdn_net_local *lp;
- unsigned long flags;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
-
- lp = nd->queue;
-// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
-// __func__, lp->name, lp, nlp->name, nlp, lp->last);
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- nd->queue = nlp;
-
- spin_unlock_irqrestore(&nd->queue_lock, flags);
-}
-/*
- * remove a channel from the bundle it belongs to
- */
-static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
-{
- isdn_net_local *master_lp = lp;
- unsigned long flags;
-
- if (lp->master)
- master_lp = ISDN_MASTER_PRIV(lp);
-
-// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
-// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
- spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
- lp->last->next = lp->next;
- lp->next->last = lp->last;
- if (master_lp->netdev->queue == lp) {
- master_lp->netdev->queue = lp->next;
- if (lp->next == lp) { /* last in queue */
- master_lp->netdev->queue = master_lp->netdev->local;
- }
- }
- lp->next = lp->last = lp; /* (re)set own pointers */
-// printk(KERN_DEBUG "%s: mndq(%p)\n",
-// __func__, master_lp->netdev->queue);
- spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
-}
+++ /dev/null
-/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/poll.h>
-#include <linux/ppp-comp.h>
-#include <linux/slab.h>
-#ifdef CONFIG_IPPP_FILTER
-#include <linux/filter.h>
-#endif
-
-#include "isdn_common.h"
-#include "isdn_ppp.h"
-#include "isdn_net.h"
-
-#ifndef PPP_IPX
-#define PPP_IPX 0x002b
-#endif
-
-/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
-static int isdn_ppp_closewait(int slot);
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static int isdn_ppp_if_get_unit(char *namebuf);
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *);
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
- struct ippp_struct *, struct ippp_struct *, int *proto);
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type);
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-
-/* New CCP stuff */
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len);
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t);
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp);
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id);
-
-
-
-#ifdef CONFIG_ISDN_MPP
-static ippp_bundle *isdn_ppp_bundle_arr = NULL;
-
-static int isdn_ppp_mp_bundle_array_init(void);
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp);
-
-static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-#endif /* CONFIG_ISDN_MPP */
-
-char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
-
-static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
-
-static struct isdn_ppp_compressor *ipc_head = NULL;
-
-/*
- * frame log (debug)
- */
-static void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot)
-{
- int cnt,
- j,
- i;
- char buf[80];
-
- if (len < maxlen)
- maxlen = len;
-
- for (i = 0, cnt = 0; cnt < maxlen; i++) {
- for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
- sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]);
- printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf);
- }
-}
-
-/*
- * unbind isdn_net_local <=> ippp-device
- * note: it can happen, that we hangup/free the master before the slaves
- * in this case we bind another lp to the master device
- */
-int
-isdn_ppp_free(isdn_net_local *lp)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return 0;
- }
-
-#ifdef CONFIG_ISDN_MPP
- spin_lock(&lp->netdev->pb->lock);
-#endif
- isdn_net_rm_from_bundle(lp);
-#ifdef CONFIG_ISDN_MPP
- if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
- isdn_ppp_mp_cleanup(lp);
-
- lp->netdev->pb->ref_ct--;
- spin_unlock(&lp->netdev->pb->lock);
-#endif /* CONFIG_ISDN_MPP */
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
- __func__, lp->ppp_slot);
- return 0;
- }
- is = ippp_table[lp->ppp_slot];
- if ((is->state & IPPP_CONNECT))
- isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
- else if (is->state & IPPP_ASSIGNED)
- is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
-
- is->lp = NULL; /* link is down .. set lp to NULL */
- lp->ppp_slot = -1; /* is this OK ?? */
-
- return 0;
-}
-
-/*
- * bind isdn_net_local <=> ippp-device
- *
- * This function is allways called with holding dev->lock so
- * no additional lock is needed
- */
-int
-isdn_ppp_bind(isdn_net_local *lp)
-{
- int i;
- int unit = 0;
- struct ippp_struct *is;
- int retval;
-
- if (lp->pppbind < 0) { /* device bounded to ippp device ? */
- isdn_net_dev *net_dev = dev->netdev;
- char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
- memset(exclusive, 0, ISDN_MAX_CHANNELS);
- while (net_dev) { /* step through net devices to find exclusive minors */
- isdn_net_local *lp = net_dev->local;
- if (lp->pppbind >= 0)
- exclusive[lp->pppbind] = 1;
- net_dev = net_dev->next;
- }
- /*
- * search a free device / slot
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
- break;
- }
- }
- } else {
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->minor == lp->pppbind &&
- (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
- break;
- }
- }
-
- if (i >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
- retval = -1;
- goto out;
- }
- /* get unit number from interface name .. ugly! */
- unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
- if (unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
- lp->netdev->dev->name);
- retval = -1;
- goto out;
- }
-
- lp->ppp_slot = i;
- is = ippp_table[i];
- is->lp = lp;
- is->unit = unit;
- is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
-#ifdef CONFIG_ISDN_MPP
- retval = isdn_ppp_mp_init(lp, NULL);
- if (retval < 0)
- goto out;
-#endif /* CONFIG_ISDN_MPP */
-
- retval = lp->ppp_slot;
-
-out:
- return retval;
-}
-
-/*
- * kick the ipppd on the device
- * (wakes up daemon after B-channel connect)
- */
-
-void
-isdn_ppp_wakeup_daemon(isdn_net_local *lp)
-{
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
- wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
-}
-
-/*
- * there was a hangup on the netdevice
- * force wakeup of the ippp device
- * go into 'device waits for release' state
- */
-static int
-isdn_ppp_closewait(int slot)
-{
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return 0;
- }
- is = ippp_table[slot];
- if (is->state)
- wake_up_interruptible(&is->wq);
- is->state = IPPP_CLOSEWAIT;
- return 1;
-}
-
-/*
- * isdn_ppp_find_slot / isdn_ppp_free_slot
- */
-
-static int
-isdn_ppp_get_slot(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!ippp_table[i]->state)
- return i;
- }
- return -1;
-}
-
-/*
- * isdn_ppp_open
- */
-
-int
-isdn_ppp_open(int min, struct file *file)
-{
- int slot;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return -ENODEV;
-
- slot = isdn_ppp_get_slot();
- if (slot < 0) {
- return -EBUSY;
- }
- is = file->private_data = ippp_table[slot];
-
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
- slot, min, is->state);
-
- /* compression stuff */
- is->link_compressor = is->compressor = NULL;
- is->link_decompressor = is->decompressor = NULL;
- is->link_comp_stat = is->comp_stat = NULL;
- is->link_decomp_stat = is->decomp_stat = NULL;
- is->compflags = 0;
-
- is->reset = isdn_ppp_ccp_reset_alloc(is);
- if (!is->reset)
- return -ENOMEM;
-
- is->lp = NULL;
- is->mp_seqno = 0; /* MP sequence number */
- is->pppcfg = 0; /* ppp configuration */
- is->mpppcfg = 0; /* mppp configuration */
- is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
- is->unit = -1; /* set, when we have our interface */
- is->mru = 1524; /* MRU, default 1524 */
- is->maxcid = 16; /* VJ: maxcid */
- is->tk = current;
- init_waitqueue_head(&is->wq);
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
- is->minor = min;
-#ifdef CONFIG_ISDN_PPP_VJ
- /*
- * VJ header compression init
- */
- is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
- if (IS_ERR(is->slcomp)) {
- isdn_ppp_ccp_reset_free(is);
- return PTR_ERR(is->slcomp);
- }
-#endif
-#ifdef CONFIG_IPPP_FILTER
- is->pass_filter = NULL;
- is->active_filter = NULL;
-#endif
- is->state = IPPP_OPEN;
-
- return 0;
-}
-
-/*
- * release ippp device
- */
-void
-isdn_ppp_release(int min, struct file *file)
-{
- int i;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return;
- is = file->private_data;
-
- if (!is) {
- printk(KERN_ERR "%s: no file->private_data\n", __func__);
- return;
- }
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
-
- if (is->lp) { /* a lp address says: this link is still up */
- isdn_net_dev *p = is->lp->netdev;
-
- if (!p) {
- printk(KERN_ERR "%s: no lp->netdev\n", __func__);
- return;
- }
- is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
- /*
- * isdn_net_hangup() calls isdn_ppp_free()
- * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
- * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
- */
- isdn_net_hangup(p->dev);
- }
- for (i = 0; i < NUM_RCV_BUFFS; i++) {
- kfree(is->rq[i].buf);
- is->rq[i].buf = NULL;
- }
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
-
-#ifdef CONFIG_ISDN_PPP_VJ
-/* TODO: if this was the previous master: link the slcomp to the new master */
- slhc_free(is->slcomp);
- is->slcomp = NULL;
-#endif
-#ifdef CONFIG_IPPP_FILTER
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
-#endif
-
-/* TODO: if this was the previous master: link the stuff to the new master */
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->compressor = is->link_compressor = NULL;
- is->decompressor = is->link_decompressor = NULL;
- is->comp_stat = is->link_comp_stat = NULL;
- is->decomp_stat = is->link_decomp_stat = NULL;
-
- /* Clean up if necessary */
- if (is->reset)
- isdn_ppp_ccp_reset_free(is);
-
- /* this slot is ready for new connections */
- is->state = 0;
-}
-
-/*
- * get_arg .. ioctl helper
- */
-static int
-get_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_from_user(val, b, len))
- return -EFAULT;
- return 0;
-}
-
-/*
- * set arg .. ioctl helper
- */
-static int
-set_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_to_user(b, val, len))
- return -EFAULT;
- return 0;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
-{
- struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;
-
- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
-
- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
-
- /* uprog.len is unsigned short, so no overflow here */
- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
-
- *p = code;
- return uprog.len;
-}
-#endif /* CONFIG_IPPP_FILTER */
-
-/*
- * ippp device ioctl
- */
-int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
-{
- unsigned long val;
- int r, i, j;
- struct ippp_struct *is;
- isdn_net_local *lp;
- struct isdn_ppp_comp_data data;
- void __user *argp = (void __user *)arg;
-
- is = file->private_data;
- lp = is->lp;
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
-
- if (!(is->state & IPPP_OPEN))
- return -EINVAL;
-
- switch (cmd) {
- case PPPIOCBUNDLE:
-#ifdef CONFIG_ISDN_MPP
- if (!(is->state & IPPP_CONNECT))
- return -EINVAL;
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
- return isdn_ppp_bundle(is, val);
-#else
- return -1;
-#endif
- break;
- case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
- return r;
- break;
- case PPPIOCGIFNAME:
- if (!lp)
- return -EINVAL;
- if ((r = set_arg(argp, lp->netdev->dev->name,
- strlen(lp->netdev->dev->name))))
- return r;
- break;
- case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
- return r;
- break;
- case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mpppcfg = val;
- break;
- case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
- return r;
- break;
- case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val)))) {
- return r;
- }
- if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
- if (lp) {
- /* OK .. we are ready to send buffers */
- is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
- netif_wake_queue(lp->netdev->dev);
- break;
- }
- }
- is->pppcfg = val;
- break;
- case PPPIOCGIDLE: /* get idle time information */
- if (lp) {
- struct ppp_idle pidle;
- pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
- if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
- return r;
- }
- break;
- case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mru = val;
- break;
- case PPPIOCSMPMRU:
- break;
- case PPPIOCSMPMTU:
- break;
- case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- val++;
- if (is->maxcid != val) {
-#ifdef CONFIG_ISDN_PPP_VJ
- struct slcompress *sltmp;
-#endif
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
- is->maxcid = val;
-#ifdef CONFIG_ISDN_PPP_VJ
- sltmp = slhc_init(16, val);
- if (IS_ERR(sltmp))
- return PTR_ERR(sltmp);
- if (is->slcomp)
- slhc_free(is->slcomp);
- is->slcomp = sltmp;
-#endif
- }
- break;
- case PPPIOCGDEBUG:
- if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
- return r;
- break;
- case PPPIOCSDEBUG:
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->debug = val;
- break;
- case PPPIOCGCOMPRESSORS:
- {
- unsigned long protos[8] = {0,};
- struct isdn_ppp_compressor *ipc = ipc_head;
- while (ipc) {
- j = ipc->num / (sizeof(long) * 8);
- i = ipc->num % (sizeof(long) * 8);
- if (j < 8)
- protos[j] |= (1UL << i);
- ipc = ipc->next;
- }
- if ((r = set_arg(argp, protos, 8 * sizeof(long))))
- return r;
- }
- break;
- case PPPIOCSCOMPRESSOR:
- if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
- return r;
- return isdn_ppp_set_compressor(is, &data);
- case PPPIOCGCALLINFO:
- {
- struct pppcallinfo pci;
- memset((char *)&pci, 0, sizeof(struct pppcallinfo));
- if (lp)
- {
- strncpy(pci.local_num, lp->msn, 63);
- if (lp->dial) {
- strncpy(pci.remote_num, lp->dial->num, 63);
- }
- pci.charge_units = lp->charge;
- if (lp->outgoing)
- pci.calltype = CALLTYPE_OUTGOING;
- else
- pci.calltype = CALLTYPE_INCOMING;
- if (lp->flags & ISDN_NET_CALLBACK)
- pci.calltype |= CALLTYPE_CALLBACK;
- }
- return set_arg(argp, &pci, sizeof(struct pppcallinfo));
- }
-#ifdef CONFIG_IPPP_FILTER
- case PPPIOCSPASS:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->pass_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
- case PPPIOCSACTIVE:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->active_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
-#endif /* CONFIG_IPPP_FILTER */
- default:
- break;
- }
- return 0;
-}
-
-__poll_t
-isdn_ppp_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask;
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- struct ippp_struct *is;
-
- is = file->private_data;
-
- if (is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- iminor(file_inode(file)));
-
- /* just registers wait_queue hook. This doesn't really wait. */
- poll_wait(file, &is->wq, wait);
-
- if (!(is->state & IPPP_OPEN)) {
- if (is->state == IPPP_CLOSEWAIT)
- return EPOLLHUP;
- printk(KERN_DEBUG "isdn_ppp: device not open\n");
- return EPOLLERR;
- }
- /* we're always ready to send .. */
- mask = EPOLLOUT | EPOLLWRNORM;
-
- spin_lock_irqsave(&is->buflock, flags);
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
- is->state &= ~IPPP_NOBLOCK;
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- spin_unlock_irqrestore(&is->buflock, flags);
- return mask;
-}
-
-/*
- * fill up isdn_ppp_read() queue ..
- */
-
-static int
-isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
-{
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- u_char *nbuf;
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
- return 0;
- }
- is = ippp_table[slot];
-
- if (!(is->state & IPPP_CONNECT)) {
- printk(KERN_DEBUG "ippp: device not activated.\n");
- return 0;
- }
- nbuf = kmalloc(len + 4, GFP_ATOMIC);
- if (!nbuf) {
- printk(KERN_WARNING "ippp: Can't alloc buf\n");
- return 0;
- }
- nbuf[0] = PPP_ALLSTATIONS;
- nbuf[1] = PPP_UI;
- nbuf[2] = proto >> 8;
- nbuf[3] = proto & 0xff;
- memcpy(nbuf + 4, buf, len);
-
- spin_lock_irqsave(&is->buflock, flags);
- bf = is->first;
- bl = is->last;
-
- if (bf == bl) {
- printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
- bf = bf->next;
- kfree(bf->buf);
- is->first = bf;
- }
- bl->buf = (char *) nbuf;
- bl->len = len + 4;
-
- is->last = bl->next;
- spin_unlock_irqrestore(&is->buflock, flags);
- wake_up_interruptible(&is->wq);
- return len;
-}
-
-/*
- * read() .. non-blocking: ipppd calls it only after select()
- * reports, that there is data
- */
-
-int
-isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
-{
- struct ippp_struct *is;
- struct ippp_buf_queue *b;
- u_long flags;
- u_char *save_buf;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_OPEN))
- return 0;
-
- spin_lock_irqsave(&is->buflock, flags);
- b = is->first->next;
- save_buf = b->buf;
- if (!save_buf) {
- spin_unlock_irqrestore(&is->buflock, flags);
- return -EAGAIN;
- }
- if (b->len < count)
- count = b->len;
- b->buf = NULL;
- is->first = b;
-
- spin_unlock_irqrestore(&is->buflock, flags);
- if (copy_to_user(buf, save_buf, count))
- count = -EFAULT;
- kfree(save_buf);
-
- return count;
-}
-
-/*
- * ipppd wanna write a packet to the card .. non-blocking
- */
-
-int
-isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
-{
- isdn_net_local *lp;
- struct ippp_struct *is;
- int proto;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_CONNECT))
- return 0;
-
- lp = is->lp;
-
- /* -> push it directly to the lowlevel interface */
-
- if (!lp)
- printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
- else {
- if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
- unsigned char protobuf[4];
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- if (copy_from_user(protobuf, buf, 4))
- return -EFAULT;
-
- proto = PPP_PROTOCOL(protobuf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- return 0;
- }
-
- if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
- lp->dialstate == 0 &&
- (lp->flags & ISDN_NET_CONNECTED)) {
- unsigned short hl;
- struct sk_buff *skb;
- unsigned char *cpy_buf;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(hl + count, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
- return count;
- }
- skb_reserve(skb, hl);
- cpy_buf = skb_put(skb, count);
- if (copy_from_user(cpy_buf, buf, count))
- {
- kfree_skb(skb);
- return -EFAULT;
- }
-
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- proto = PPP_PROTOCOL(cpy_buf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- if (is->debug & 0x40) {
- printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
-
- isdn_net_write_super(lp, skb);
- }
- }
- return count;
-}
-
-/*
- * init memory, structures etc.
- */
-
-int
-isdn_ppp_init(void)
-{
- int i,
- j;
-
-#ifdef CONFIG_ISDN_MPP
- if (isdn_ppp_mp_bundle_array_init() < 0)
- return -ENOMEM;
-#endif /* CONFIG_ISDN_MPP */
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
- for (j = 0; j < i; j++)
- kfree(ippp_table[j]);
- return -1;
- }
- spin_lock_init(&ippp_table[i]->buflock);
- ippp_table[i]->state = 0;
- ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
- ippp_table[i]->last = ippp_table[i]->rq;
-
- for (j = 0; j < NUM_RCV_BUFFS; j++) {
- ippp_table[i]->rq[j].buf = NULL;
- ippp_table[i]->rq[j].last = ippp_table[i]->rq +
- (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
- ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
- }
- }
- return 0;
-}
-
-void
-isdn_ppp_cleanup(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(ippp_table[i]);
-
-#ifdef CONFIG_ISDN_MPP
- kfree(isdn_ppp_bundle_arr);
-#endif /* CONFIG_ISDN_MPP */
-
-}
-
-/*
- * check for address/control field and skip if allowed
- * retval != 0 -> discard packet silently
- */
-static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
-{
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] == 0xff) {
- if (skb->len < 2)
- return -1;
-
- if (skb->data[1] != 0x03)
- return -1;
-
- // skip address/control (AC) field
- skb_pull(skb, 2);
- } else {
- if (is->pppcfg & SC_REJ_COMP_AC)
- // if AC compression was not negotiated, but used, discard packet
- return -1;
- }
- return 0;
-}
-
-/*
- * get the PPP protocol header and pull skb
- * retval < 0 -> discard packet silently
- */
-static int isdn_ppp_strip_proto(struct sk_buff *skb)
-{
- int proto;
-
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] & 0x1) {
- // protocol field is compressed
- proto = skb->data[0];
- skb_pull(skb, 1);
- } else {
- if (skb->len < 2)
- return -1;
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb, 2);
- }
- return proto;
-}
-
-
-/*
- * handler for incoming packets on a syncPPP interface
- */
-void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *is;
- int slot;
- int proto;
-
- BUG_ON(net_dev->local->master); // we're called with the master device always
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- return;
- }
- is = ippp_table[slot];
-
- if (is->debug & 0x4) {
- printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
- (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
- isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- if (isdn_ppp_skip_ac(is, skb) < 0) {
- kfree_skb(skb);
- return;
- }
- proto = isdn_ppp_strip_proto(skb);
- if (proto < 0) {
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_ISDN_MPP
- if (is->compflags & SC_LINK_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, NULL, &proto);
- if (!skb) // decompression error
- return;
- }
-
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
- return;
- }
- }
-#endif
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-/*
- * we receive a reassembled frame, MPPP has been taken care of before.
- * address/control and protocol have been stripped from the skb
- * note: net_dev has to be master net_dev
- */
-static void
-isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto)
-{
- struct net_device *dev = net_dev->dev;
- struct ippp_struct *is, *mis;
- isdn_net_local *mlp = NULL;
- int slot;
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- is = ippp_table[slot];
-
- if (lp->master) { // FIXME?
- mlp = ISDN_MASTER_PRIV(lp);
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- }
- mis = ippp_table[slot];
-
- if (is->debug & 0x10) {
- printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
- if (mis->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, mis, &proto);
- if (!skb) // decompression error
- return;
- }
- switch (proto) {
- case PPP_IPX: /* untested */
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->protocol = htons(ETH_P_IPX);
- break;
- case PPP_IP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_COMP:
- case PPP_COMPFRAG:
- printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
- goto drop_packet;
-#ifdef CONFIG_ISDN_PPP_VJ
- case PPP_VJC_UNCOMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- goto drop_packet;
- }
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_VJC_COMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 128);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- skb = skb_old;
- goto drop_packet;
- }
- skb_put(skb, skb_old->len + 128);
- skb_copy_from_linear_data(skb_old, skb->data,
- skb_old->len);
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
- skb->data, skb_old->len);
- kfree_skb(skb_old);
- if (pkt_len < 0)
- goto drop_packet;
-
- skb_trim(skb, pkt_len);
- skb->protocol = htons(ETH_P_IP);
- }
- break;
-#endif
- case PPP_CCP:
- case PPP_CCPFRAG:
- isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
- /* Dont pop up ResetReq/Ack stuff to the daemon any
- longer - the job is done already */
- if (skb->data[0] == CCP_RESETREQ ||
- skb->data[0] == CCP_RESETACK)
- break;
- /* fall through */
- default:
- isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if the packet passes the pass and active filters
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet (which is still present) */
- skb_push(skb, 4);
-
- {
- u_int16_t *p = (u_int16_t *) skb->data;
-
- *p = 0; /* indicate inbound */
- }
-
- if (is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
- kfree_skb(skb);
- return;
- }
- if (!(is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
- skb->dev = dev;
- skb_reset_mac_header(skb);
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
- return;
-
-drop_packet:
- net_dev->local->stats.rx_dropped++;
- kfree_skb(skb);
-}
-
-/*
- * isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the skb
- * and allocs a new SKB if necessary
- */
-static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
-{
- struct sk_buff *skb = *skb_p;
-
- if (skb_headroom(skb) < len) {
- struct sk_buff *nskb = skb_realloc_headroom(skb, len);
-
- if (!nskb) {
- printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
- dev_kfree_skb(skb);
- *skb_p = nskb;
- return skb_push(nskb, len);
- }
- return skb_push(skb, len);
-}
-
-/*
- * send ppp frame .. we expect a PIDCOMPressable proto --
- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!!
- */
-
-int
-isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
- isdn_net_local *lp, *mlp;
- isdn_net_dev *nd;
- unsigned int proto = PPP_IP; /* 0x21 */
- struct ippp_struct *ipt, *ipts;
- int slot, retval = NETDEV_TX_OK;
-
- mlp = netdev_priv(netdev);
- nd = mlp->netdev; /* get master lp */
-
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- mlp->ppp_slot);
- kfree_skb(skb);
- goto out;
- }
- ipts = ippp_table[slot];
-
- if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
- if (ipts->debug & 0x1)
- printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX; /* untested */
- break;
- default:
- printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
- skb->protocol);
- dev_kfree_skb(skb);
- goto out;
- }
-
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
- /* we have our lp locked from now on */
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- goto unlock;
- }
- ipt = ippp_table[slot];
-
- /*
- * after this line .. requeueing in the device queue is no longer allowed!!!
- */
-
- /* Pull off the fake header we stuck on earlier to keep
- * the fragmentation code happy.
- */
- skb_pull(skb, IPPP_MAX_HEADER);
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if we should pass this packet
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet */
- *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- if (ipt->pass_filter
- && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
- kfree_skb(skb);
- goto unlock;
- }
- if (!(ipt->active_filter
- && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
-
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
- if (ipts->debug & 0x40)
- isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
-
-#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
- struct sk_buff *new_skb;
- unsigned short hl;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want.
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
- /*
- * Note: hl might still be insufficient because the method
- * above does not account for a possibible MPPP slave channel
- * which had larger HL header space requirements than the
- * master.
- */
- new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
- if (new_skb) {
- u_char *buf;
- int pktlen;
-
- skb_reserve(new_skb, hl);
- new_skb->dev = skb->dev;
- skb_put(new_skb, skb->len);
- buf = skb->data;
-
- pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
-
- if (buf != skb->data) {
- if (new_skb->data != buf)
- printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb);
- skb = new_skb;
- } else {
- dev_kfree_skb(new_skb);
- }
-
- skb_trim(skb, pktlen);
- if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
- proto = PPP_VJC_COMP;
- skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
- } else {
- if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
- proto = PPP_VJC_UNCOMP;
- skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
- }
- }
- }
-#endif
-
- /*
- * normal (single link) or bundle compression
- */
- if (ipts->compflags & SC_COMP_ON) {
- /* We send compressed only if both down- und upstream
- compression is negotiated, that means, CCP is up */
- if (ipts->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
- } else {
- printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
- }
- }
-
- if (ipt->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
-
-#ifdef CONFIG_ISDN_MPP
- if (ipt->mpppcfg & SC_MP_PROT) {
- /* we get mp_seqno from static isdn_net_local */
- long mp_seqno = ipts->mp_seqno;
- ipts->mp_seqno++;
- if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 3);
- if (!data)
- goto unlock;
- mp_seqno &= 0xfff;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
- data[1] = mp_seqno & 0xff;
- data[2] = proto; /* PID compression */
- } else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 5);
- if (!data)
- goto unlock;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- data[2] = (mp_seqno >> 8) & 0xff;
- data[3] = (mp_seqno >> 0) & 0xff;
- data[4] = proto; /* PID compression */
- }
- proto = PPP_MP; /* MP Protocol, 0x003d */
- }
-#endif
-
- /*
- * 'link in bundle' compression ...
- */
- if (ipt->compflags & SC_LINK_COMP_ON)
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
-
- if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 1);
- if (!data)
- goto unlock;
- data[0] = proto & 0xff;
- }
- else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = (proto >> 8) & 0xff;
- data[1] = proto & 0xff;
- }
- if (!(ipt->pppcfg & SC_COMP_AC)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = 0xff; /* All Stations */
- data[1] = 0x03; /* Unnumbered information */
- }
-
- /* tx-stats are now updated via BSENT-callback */
-
- if (ipts->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
- }
-
- isdn_net_writebuf_skb(lp, skb);
-
-unlock:
- spin_unlock_bh(&lp->xmit_lock);
-out:
- return retval;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-/*
- * check if this packet may trigger auto-dial.
- */
-
-int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
-{
- struct ippp_struct *is = ippp_table[lp->ppp_slot];
- u_int16_t proto;
- int drop = 0;
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX;
- break;
- default:
- printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
- skb->protocol);
- return 1;
- }
-
- /* the filter instructions are constructed assuming
- * a four-byte PPP header on each packet. we have to
- * temporarily remove part of the fake header stuck on
- * earlier.
- */
- *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- drop |= is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0;
- drop |= is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0;
-
- skb_push(skb, IPPP_MAX_HEADER - 4);
- return drop;
-}
-#endif
-#ifdef CONFIG_ISDN_MPP
-
-/* this is _not_ rfc1990 header, but something we convert both short and long
- * headers to for convinience's sake:
- * byte 0 is flags as in rfc1990
- * bytes 1...4 is 24-bit seqence number converted to host byte order
- */
-#define MP_HEADER_LEN 5
-
-#define MP_LONGSEQ_MASK 0x00ffffff
-#define MP_SHORTSEQ_MASK 0x00000fff
-#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
-#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
-#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
-#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
-
-/* sequence-wrap safe comparisons (for long sequence)*/
-#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
-#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
-
-#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
-#define MP_FLAGS(f) (f->data[0])
-
-static int isdn_ppp_mp_bundle_array_init(void)
-{
- int i;
- int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
- if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
- return 0;
-}
-
-static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
- return (isdn_ppp_bundle_arr + i);
- return NULL;
-}
-
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return (-EINVAL);
- }
-
- is = ippp_table[lp->ppp_slot];
- if (add_to) {
- if (lp->netdev->pb)
- lp->netdev->pb->ref_ct--;
- lp->netdev->pb = add_to;
- } else { /* first link in a bundle */
- is->mp_seqno = 0;
- if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
- return -ENOMEM;
- lp->next = lp->last = lp; /* nobody else in a queue */
- lp->netdev->pb->frags = NULL;
- lp->netdev->pb->frames = 0;
- lp->netdev->pb->seq = UINT_MAX;
- }
- lp->netdev->pb->ref_ct++;
-
- is->last_link_seqno = 0;
- return 0;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq);
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
-
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb)
-{
- struct ippp_struct *is;
- isdn_net_local *lpq;
- ippp_bundle *mp;
- isdn_mppp_stats *stats;
- struct sk_buff *newfrag, *frag, *start, *nextf;
- u32 newseq, minseq, thisseq;
- unsigned long flags;
- int slot;
-
- spin_lock_irqsave(&net_dev->pb->lock, flags);
- mp = net_dev->pb;
- stats = &mp->stats;
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
- __func__, lp->ppp_slot);
- stats->frame_drops++;
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
- is = ippp_table[slot];
- if (++mp->frames > stats->max_queue_len)
- stats->max_queue_len = mp->frames;
-
- if (is->debug & 0x8)
- isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
-
- newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
- skb, is->last_link_seqno);
-
-
- /* if this packet seq # is less than last already processed one,
- * toss it right away, but check for sequence start case first
- */
- if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
- mp->seq = newseq; /* the first packet: required for
- * rfc1990 non-compliant clients --
- * prevents constant packet toss */
- } else if (MP_LT(newseq, mp->seq)) {
- stats->frame_drops++;
- isdn_ppp_mp_free_skb(mp, skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
-
- /* find the minimum received sequence number over all links */
- is->last_link_seqno = minseq = newseq;
- for (lpq = net_dev->queue;;) {
- slot = lpq->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
- __func__, lpq->ppp_slot);
- } else {
- u32 lls = ippp_table[slot]->last_link_seqno;
- if (MP_LT(lls, minseq))
- minseq = lls;
- }
- if ((lpq = lpq->next) == net_dev->queue)
- break;
- }
- if (MP_LT(minseq, mp->seq))
- minseq = mp->seq; /* can't go beyond already processed
- * packets */
- newfrag = skb;
-
- /* if this new fragment is before the first one, then enqueue it now. */
- if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
- newfrag->next = frag;
- mp->frags = frag = newfrag;
- newfrag = NULL;
- }
-
- start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
- MP_SEQ(frag) == mp->seq ? frag : NULL;
-
- /*
- * main fragment traversing loop
- *
- * try to accomplish several tasks:
- * - insert new fragment into the proper sequence slot (once that's done
- * newfrag will be set to NULL)
- * - reassemble any complete fragment sequence (non-null 'start'
- * indicates there is a contiguous sequence present)
- * - discard any incomplete sequences that are below minseq -- due
- * to the fact that sender always increment sequence number, if there
- * is an incomplete sequence below minseq, no new fragments would
- * come to complete such sequence and it should be discarded
- *
- * loop completes when we accomplished the following tasks:
- * - new fragment is inserted in the proper sequence ('newfrag' is
- * set to NULL)
- * - we hit a gap in the sequence, so no reassembly/processing is
- * possible ('start' would be set to NULL)
- *
- * algorithm for this code is derived from code in the book
- * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
- */
- while (start != NULL || newfrag != NULL) {
-
- thisseq = MP_SEQ(frag);
- nextf = frag->next;
-
- /* drop any duplicate fragments */
- if (newfrag != NULL && thisseq == newseq) {
- isdn_ppp_mp_free_skb(mp, newfrag);
- newfrag = NULL;
- }
-
- /* insert new fragment before next element if possible. */
- if (newfrag != NULL && (nextf == NULL ||
- MP_LT(newseq, MP_SEQ(nextf)))) {
- newfrag->next = nextf;
- frag->next = nextf = newfrag;
- newfrag = NULL;
- }
-
- if (start != NULL) {
- /* check for misplaced start */
- if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
- printk(KERN_WARNING"isdn_mppp(seq %d): new "
- "BEGIN flag with no prior END", thisseq);
- stats->seqerrs++;
- stats->frame_drops++;
- start = isdn_ppp_mp_discard(mp, start, frag);
- nextf = frag->next;
- }
- } else if (MP_LE(thisseq, minseq)) {
- if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
- start = frag;
- else {
- if (MP_FLAGS(frag) & MP_END_FRAG)
- stats->frame_drops++;
- if (mp->frags == frag)
- mp->frags = nextf;
- isdn_ppp_mp_free_skb(mp, frag);
- frag = nextf;
- continue;
- }
- }
-
- /* if start is non-null and we have end fragment, then
- * we have full reassembly sequence -- reassemble
- * and process packet now
- */
- if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
- minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
- /* Reassemble the packet then dispatch it */
- isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
-
- start = NULL;
- frag = NULL;
-
- mp->frags = nextf;
- }
-
- /* check if need to update start pointer: if we just
- * reassembled the packet and sequence is contiguous
- * then next fragment should be the start of new reassembly
- * if sequence is contiguous, but we haven't reassembled yet,
- * keep going.
- * if sequence is not contiguous, either clear everything
- * below low watermark and set start to the next frag or
- * clear start ptr.
- */
- if (nextf != NULL &&
- ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
- /* if we just reassembled and the next one is here,
- * then start another reassembly. */
-
- if (frag == NULL) {
- if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
- start = nextf;
- else
- {
- printk(KERN_WARNING"isdn_mppp(seq %d):"
- " END flag with no following "
- "BEGIN", thisseq);
- stats->seqerrs++;
- }
- }
-
- } else {
- if (nextf != NULL && frag != NULL &&
- MP_LT(thisseq, minseq)) {
- /* we've got a break in the sequence
- * and we not at the end yet
- * and we did not just reassembled
- *(if we did, there wouldn't be anything before)
- * and we below the low watermark
- * discard all the frames below low watermark
- * and start over */
- stats->frame_drops++;
- mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
- }
- /* break in the sequence, no reassembly */
- start = NULL;
- }
-
- frag = nextf;
- } /* while -- main loop */
-
- if (mp->frags == NULL)
- mp->frags = frag;
-
- /* rather straighforward way to deal with (not very) possible
- * queue overflow */
- if (mp->frames > MP_MAX_QUEUE_LEN) {
- stats->overflows++;
- while (mp->frames > MP_MAX_QUEUE_LEN) {
- frag = mp->frags->next;
- isdn_ppp_mp_free_skb(mp, mp->frags);
- mp->frags = frag;
- }
- }
- spin_unlock_irqrestore(&mp->lock, flags);
-}
-
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
-{
- struct sk_buff *frag = lp->netdev->pb->frags;
- struct sk_buff *nextfrag;
- while (frag) {
- nextfrag = frag->next;
- isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
- frag = nextfrag;
- }
- lp->netdev->pb->frags = NULL;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq)
-{
- u32 seq;
- int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
-
- if (!short_seq)
- {
- seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
- skb_push(skb, 1);
- }
- else
- {
- /* convert 12-bit short seq number to 24-bit long one
- */
- seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
-
- /* check for seqence wrap */
- if (!(seq & MP_SHORTSEQ_MAXBIT) &&
- (last_seq & MP_SHORTSEQ_MAXBIT) &&
- (unsigned long)last_seq <= MP_LONGSEQ_MAX)
- seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
- (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
- else
- seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
-
- skb_push(skb, 3); /* put converted seqence back in skb */
- }
- *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
- * order */
- skb->data[0] = flags; /* restore flags */
- return seq;
-}
-
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from,
- struct sk_buff *to)
-{
- if (from)
- while (from != to) {
- struct sk_buff *next = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = next;
- }
- return from;
-}
-
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to)
-{
- ippp_bundle *mp = net_dev->pb;
- int proto;
- struct sk_buff *skb;
- unsigned int tot_len;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
- "len %d\n", MP_SEQ(from), from->len);
- skb = from;
- skb_pull(skb, MP_HEADER_LEN);
- mp->frames--;
- } else {
- struct sk_buff *frag;
- int n;
-
- for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
- tot_len += frag->len - MP_HEADER_LEN;
-
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
- "to %d, len %d\n", MP_SEQ(from),
- (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
- if ((skb = dev_alloc_skb(tot_len)) == NULL) {
- printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
- "of size %d\n", tot_len);
- isdn_ppp_mp_discard(mp, from, to);
- return;
- }
-
- while (from != to) {
- unsigned int len = from->len - MP_HEADER_LEN;
-
- skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
- skb_put(skb, len),
- len);
- frag = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = frag;
- }
- }
- proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
-{
- dev_kfree_skb(skb);
- mp->frames--;
-}
-
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
-{
- printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
- slot, (int) skb->len,
- (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
-}
-
-static int
-isdn_ppp_bundle(struct ippp_struct *is, int unit)
-{
- char ifn[IFNAMSIZ + 1];
- isdn_net_dev *p;
- isdn_net_local *lp, *nlp;
- int rc;
- unsigned long flags;
-
- sprintf(ifn, "ippp%d", unit);
- p = isdn_net_findif(ifn);
- if (!p) {
- printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&p->pb->lock, flags);
-
- nlp = is->lp;
- lp = p->queue;
- if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
- lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
- nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
- nlp->ppp_slot : lp->ppp_slot);
- rc = -EINVAL;
- goto out;
- }
-
- isdn_net_add_to_bundle(p, nlp);
-
- ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-
- /* maybe also SC_CCP stuff */
- ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
- ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- rc = isdn_ppp_mp_init(nlp, p->pb);
-out:
- spin_unlock_irqrestore(&p->pb->lock, flags);
- return rc;
-}
-
-#endif /* CONFIG_ISDN_MPP */
-
-/*
- * network device ioctl handlers
- */
-
-static int
-isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
-{
- struct ppp_stats __user *res = ifr->ifr_data;
- struct ppp_stats t;
- isdn_net_local *lp = netdev_priv(dev);
-
- /* build a temporary stat struct and copy it to user space */
-
- memset(&t, 0, sizeof(struct ppp_stats));
- if (dev->flags & IFF_UP) {
- t.p.ppp_ipackets = lp->stats.rx_packets;
- t.p.ppp_ibytes = lp->stats.rx_bytes;
- t.p.ppp_ierrors = lp->stats.rx_errors;
- t.p.ppp_opackets = lp->stats.tx_packets;
- t.p.ppp_obytes = lp->stats.tx_bytes;
- t.p.ppp_oerrors = lp->stats.tx_errors;
-#ifdef CONFIG_ISDN_PPP_VJ
- if (slot >= 0 && ippp_table[slot]->slcomp) {
- struct slcompress *slcomp = ippp_table[slot]->slcomp;
- t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
- t.vj.vjs_compressed = slcomp->sls_o_compressed;
- t.vj.vjs_searches = slcomp->sls_o_searches;
- t.vj.vjs_misses = slcomp->sls_o_misses;
- t.vj.vjs_errorin = slcomp->sls_i_error;
- t.vj.vjs_tossed = slcomp->sls_i_tossed;
- t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
- t.vj.vjs_compressedin = slcomp->sls_i_compressed;
- }
-#endif
- }
- if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
- return -EFAULT;
- return 0;
-}
-
-int
-isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int error = 0;
- int len;
- isdn_net_local *lp = netdev_priv(dev);
-
-
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -EINVAL;
-
- switch (cmd) {
-#define PPP_VERSION "2.3.7"
- case SIOCGPPPVER:
- len = strlen(PPP_VERSION) + 1;
- if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
- error = -EFAULT;
- break;
-
- case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
- break;
- default:
- error = -EINVAL;
- break;
- }
- return error;
-}
-
-static int
-isdn_ppp_if_get_unit(char *name)
-{
- int len,
- i,
- unit = 0,
- deci;
-
- len = strlen(name);
-
- if (strncmp("ippp", name, 4) || len > 8)
- return -1;
-
- for (i = 0, deci = 1; i < len; i++, deci *= 10) {
- char a = name[len - i - 1];
- if (a >= '0' && a <= '9')
- unit += (a - '0') * deci;
- else
- break;
- }
- if (!i || len - i != 4)
- unit = -1;
-
- return unit;
-}
-
-
-int
-isdn_ppp_dial_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
- if (!(mlp->flags & ISDN_NET_CONNECTED))
- break;
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_dial_req(netdev_priv(sdev));
- return 0;
-#else
- return -1;
-#endif
-}
-
-int
-isdn_ppp_hangup_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
-
- if (mlp->slave) { /* find last connected link in chain */
- isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
-
- if (!(nlp->flags & ISDN_NET_CONNECTED))
- break;
- } else if (mlp->flags & ISDN_NET_CONNECTED)
- break;
-
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_hangup(sdev);
- return 0;
-#else
- return -1;
-#endif
-}
-
-/*
- * PPP compression stuff
- */
-
-
-/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
- generate a CCP Reset-Request or tear down CCP altogether */
-
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
-{
- isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
-}
-
-/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
- but absolutely nontrivial. The most abstruse problem we are facing is
- that the generation, reception and all the handling of timeouts and
- resends including proper request id management should be entirely left
- to the (de)compressor, but indeed is not covered by the current API to
- the (de)compressor. The API is a prototype version from PPP where only
- some (de)compressors have yet been implemented and all of them are
- rather simple in their reset handling. Especially, their is only one
- outstanding ResetAck at a time with all of them and ResetReq/-Acks do
- not have parameters. For this very special case it was sufficient to
- just return an error code from the decompressor and have a single
- reset() entry to communicate all the necessary information between
- the framework and the (de)compressor. Bad enough, LZS is different
- (and any other compressor may be different, too). It has multiple
- histories (eventually) and needs to Reset each of them independently
- and thus uses multiple outstanding Acks and history numbers as an
- additional parameter to Reqs/Acks.
- All that makes it harder to port the reset state engine into the
- kernel because it is not just the same simple one as in (i)pppd but
- it must be able to pass additional parameters and have multiple out-
- standing Acks. We are trying to achieve the impossible by handling
- reset transactions independent by their id. The id MUST change when
- the data portion changes, thus any (de)compressor who uses more than
- one resettable state must provide and recognize individual ids for
- each individual reset transaction. The framework itself does _only_
- differentiate them by id, because it has no other semantics like the
- (de)compressor might.
- This looks like a major redesign of the interface would be nice,
- but I don't have an idea how to do it better. */
-
-/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
- getting that lengthy because there is no simple "send-this-frame-out"
- function above but every wrapper does a bit different. Hope I guess
- correct in this hack... */
-
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len)
-{
- struct sk_buff *skb;
- unsigned char *p;
- int hl;
- int cnt = 0;
- isdn_net_local *lp = is->lp;
-
- /* Alloc large enough skb */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING
- "ippp: CCP cannot send reset - out of memory\n");
- return;
- }
- skb_reserve(skb, hl);
-
- /* We may need to stuff an address and control field first */
- if (!(is->pppcfg & SC_COMP_AC)) {
- p = skb_put(skb, 2);
- *p++ = 0xff;
- *p++ = 0x03;
- }
-
- /* Stuff proto, code, id and length */
- p = skb_put(skb, 6);
- *p++ = (proto >> 8);
- *p++ = (proto & 0xff);
- *p++ = code;
- *p++ = id;
- cnt = 4 + len;
- *p++ = (cnt >> 8);
- *p++ = (cnt & 0xff);
-
- /* Now stuff remaining bytes */
- if (len) {
- skb_put_data(skb, data, len);
- }
-
- /* skb is now ready for xmit */
- printk(KERN_DEBUG "Sending CCP Frame:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- isdn_net_write_super(lp, skb);
-}
-
-/* Allocate the reset state vector */
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
-{
- struct ippp_ccp_reset *r;
- r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
- if (!r) {
- printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
- " structure - no mem\n");
- return NULL;
- }
- printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
- is->reset = r;
- return r;
-}
-
-/* Destroy the reset state vector. Kill all pending timers first. */
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
-{
- unsigned int id;
-
- printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
- is->reset);
- for (id = 0; id < 256; id++) {
- if (is->reset->rs[id]) {
- isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
- }
- }
- kfree(is->reset);
- is->reset = NULL;
-}
-
-/* Free a given state and clear everything up for later reallocation */
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (is->reset->rs[id]) {
- printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
- rs = is->reset->rs[id];
- /* Make sure the kernel will not call back later */
- if (rs->ta)
- del_timer(&rs->timer);
- is->reset->rs[id] = NULL;
- kfree(rs);
- } else {
- printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
- }
-}
-
-/* The timer callback function which is called when a ResetReq has timed out,
- aka has never been answered by a ResetAck */
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t)
-{
- struct ippp_ccp_reset_state *rs =
- from_timer(rs, t, timer);
-
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
- return;
- }
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* We are correct here */
- if (!rs->expra) {
- /* Hmm, there is no Ack really expected. We can clean
- up the state now, it will be reallocated if the
- decompressor insists on another reset */
- rs->ta = 0;
- isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
- return;
- }
- printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
- rs->id);
- /* Push it again */
- isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Restart timer */
- rs->timer.expires = jiffies + HZ * 5;
- add_timer(&rs->timer);
- } else {
- printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
- rs->state);
- }
-}
-
-/* Allocate a new reset transaction state */
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
- if (is->reset->rs[id]) {
- printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
- id);
- return NULL;
- } else {
- rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
- if (!rs)
- return NULL;
- rs->state = CCPResetIdle;
- rs->is = is;
- rs->id = id;
- timer_setup(&rs->timer, isdn_ppp_ccp_timer_callback, 0);
- is->reset->rs[id] = rs;
- }
- return rs;
-}
-
-
-/* A decompressor wants a reset with a set of parameters - do what is
- necessary to fulfill it */
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (rp->valid) {
- /* The decompressor defines parameters by itself */
- if (rp->rsend) {
- /* And he wants us to send a request */
- if (!(rp->idval)) {
- printk(KERN_ERR "ippp_ccp: decompressor must"
- " specify reset id\n");
- return;
- }
- if (is->reset->rs[rp->id]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[rp->id];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- /* Ok, this is a new transaction */
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", rp->id);
- rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- rs->expra = rp->expra;
- if (rp->dtval) {
- rs->dlen = rp->dlen;
- memcpy(rs->data, rp->data, rp->dlen);
- }
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
- CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
- }
- } else {
- /* The reset params are invalid. The decompressor does not
- care about them, so we just send the minimal requests
- and increase ids only when an Ack is received for a
- given id */
- if (is->reset->rs[is->reset->lastid]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[is->reset->lastid];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", is->reset->lastid);
- rs = isdn_ppp_ccp_reset_alloc_state(is,
- is->reset->lastid);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- /* We always expect an Ack if the decompressor doesn't
- know better */
- rs->expra = 1;
- rs->dlen = 0;
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
- rs->id, NULL, 0);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- }
-}
-
-/* An Ack was received for this id. This means we stop the timer and clean
- up the state prior to calling the decompressors reset routine. */
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs = is->reset->rs[id];
-
- if (rs) {
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* Great, we are correct */
- if (!rs->expra)
- printk(KERN_DEBUG "ippp_ccp: ResetAck received"
- " for id %d but not expected\n", id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received out of"
- "sync for id %d\n", id);
- }
- if (rs->ta) {
- rs->ta = 0;
- del_timer(&rs->timer);
- }
- isdn_ppp_ccp_reset_free_state(is, id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
- " %d\n", id);
- }
- /* Make sure the simple reset stuff uses a new id next time */
- is->reset->lastid++;
-}
-
-/*
- * decompress packet
- *
- * if master = 0, we're trying to uncompress an per-link compressed packet,
- * as opposed to an compressed reconstructed-from-MPPP packet.
- * proto is updated to protocol field of uncompressed packet.
- *
- * retval: decompressed packet,
- * same packet if uncompressed,
- * NULL if decompression error
- */
-
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
- int *proto)
-{
- void *stat = NULL;
- struct isdn_ppp_compressor *ipc = NULL;
- struct sk_buff *skb_out;
- int len;
- struct ippp_struct *ri;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- if (!master) {
- // per-link decompression
- stat = is->link_decomp_stat;
- ipc = is->link_decompressor;
- ri = is;
- } else {
- stat = master->decomp_stat;
- ipc = master->decompressor;
- ri = master;
- }
-
- if (!ipc) {
- // no decompressor -> we can't decompress.
- printk(KERN_DEBUG "ippp: no decompressor defined!\n");
- return skb;
- }
- BUG_ON(!stat); // if we have a compressor, stat has been set as well
-
- if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
- // compressed packets are compressed by their protocol type
-
- // Set up reset params for the decompressor
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
-
- skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
- if (!skb_out) {
- kfree_skb(skb);
- printk(KERN_ERR "ippp: decomp memory allocation failure\n");
- return NULL;
- }
- len = ipc->decompress(stat, skb, skb_out, &rsparm);
- kfree_skb(skb);
- if (len <= 0) {
- switch (len) {
- case DECOMP_ERROR:
- printk(KERN_INFO "ippp: decomp wants reset %s params\n",
- rsparm.valid ? "with" : "without");
-
- isdn_ppp_ccp_reset_trans(ri, &rsparm);
- break;
- case DECOMP_FATALERROR:
- ri->pppcfg |= SC_DC_FERROR;
- /* Kick ipppd to recognize the error */
- isdn_ppp_ccp_kickup(ri);
- break;
- }
- kfree_skb(skb_out);
- return NULL;
- }
- *proto = isdn_ppp_strip_proto(skb_out);
- if (*proto < 0) {
- kfree_skb(skb_out);
- return NULL;
- }
- return skb_out;
- } else {
- // uncompressed packets are fed through the decompressor to
- // update the decompressor state
- ipc->incomp(stat, skb, *proto);
- return skb;
- }
-}
-
-/*
- * compress a frame
- * type=0: normal/bundle compression
- * =1: link compression
- * returns original skb if we haven't compressed the frame
- * and a new skb pointer if we've done it
- */
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type)
-{
- int ret;
- int new_proto;
- struct isdn_ppp_compressor *compressor;
- void *stat;
- struct sk_buff *skb_out;
-
- /* we do not compress control protocols */
- if (*proto < 0 || *proto > 0x3fff) {
- return skb_in;
- }
-
- if (type) { /* type=1 => Link compression */
- return skb_in;
- }
- else {
- if (!master) {
- compressor = is->compressor;
- stat = is->comp_stat;
- }
- else {
- compressor = master->compressor;
- stat = master->comp_stat;
- }
- new_proto = PPP_COMP;
- }
-
- if (!compressor) {
- printk(KERN_ERR "isdn_ppp: No compressor set!\n");
- return skb_in;
- }
- if (!stat) {
- printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
- return skb_in;
- }
-
- /* Allow for at least 150 % expansion (for now) */
- skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
- skb_headroom(skb_in), GFP_ATOMIC);
- if (!skb_out)
- return skb_in;
- skb_reserve(skb_out, skb_headroom(skb_in));
-
- ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
- if (!ret) {
- dev_kfree_skb(skb_out);
- return skb_in;
- }
-
- dev_kfree_skb(skb_in);
- *proto = new_proto;
- return skb_out;
-}
-
-/*
- * we received a CCP frame ..
- * not a clean solution, but we MUST handle a few cases in the kernel
- */
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto)
-{
- struct ippp_struct *is;
- struct ippp_struct *mis;
- int len;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
- lp->ppp_slot);
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- is = ippp_table[lp->ppp_slot];
- isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
-
- switch (skb->data[0]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~SC_COMP_ON;
- else
- is->compflags &= ~SC_LINK_COMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we RECEIVE an ackowledge we enable the decompressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable decompression here!\n");
- if (proto == PPP_CCP) {
- if (!mis->decompressor)
- break;
- mis->compflags |= SC_DECOMP_ON;
- } else {
- if (!is->decompressor)
- break;
- is->compflags |= SC_LINK_DECOMP_ON;
- }
- break;
-
- case CCP_RESETACK:
- printk(KERN_DEBUG "Received ResetAck from peer\n");
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
-
- if (proto == PPP_CCP) {
- /* If a reset Ack was outstanding for this id, then
- clean up the state engine */
- isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
- if (mis->decompressor && mis->decomp_stat)
- mis->decompressor->
- reset(mis->decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: This is not easy to decide here */
- mis->compflags &= ~SC_DECOMP_DISCARD;
- }
- else {
- isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
- if (is->link_decompressor && is->link_decomp_stat)
- is->link_decompressor->
- reset(is->link_decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: neither here */
- is->compflags &= ~SC_LINK_DECOMP_DISCARD;
- }
- break;
-
- case CCP_RESETREQ:
- printk(KERN_DEBUG "Received ResetReq from peer\n");
- /* Receiving a ResetReq means we must reset our compressor */
- /* Set up reset params for the reset entry */
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
- /* Isolate data length */
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
- if (proto == PPP_CCP) {
- if (mis->compressor && mis->comp_stat)
- mis->compressor->
- reset(mis->comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->
- reset(is->link_comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- /* Ack the Req as specified by rsparm */
- if (rsparm.valid) {
- /* Compressor reset handler decided how to answer */
- if (rsparm.rsend) {
- /* We should send a Frame */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- rsparm.idval ? rsparm.id
- : skb->data[1],
- rsparm.dtval ?
- rsparm.data : NULL,
- rsparm.dtval ?
- rsparm.dlen : 0);
- } else {
- printk(KERN_DEBUG "ResetAck suppressed\n");
- }
- } else {
- /* We answer with a straight reflected Ack */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len);
- }
- break;
- }
-}
-
-
-/*
- * Daemon sends a CCP frame ...
- */
-
-/* TODO: Clean this up with new Reset semantics */
-
-/* I believe the CCP handling as-is is done wrong. Compressed frames
- * should only be sent/received after CCP reaches UP state, which means
- * both sides have sent CONF_ACK. Currently, we handle both directions
- * independently, which means we may accept compressed frames too early
- * (supposedly not a problem), but may also mean we send compressed frames
- * too early, which may turn out to be a problem.
- * This part of state machine should actually be handled by (i)pppd, but
- * that's too big of a change now. --kai
- */
-
-/* Actually, we might turn this into an advantage: deal with the RFC in
- * the old tradition of beeing generous on what we accept, but beeing
- * strict on what we send. Thus we should just
- * - accept compressed frames as soon as decompression is negotiated
- * - send compressed frames only when decomp *and* comp are negotiated
- * - drop rx compressed frames if we cannot decomp (instead of pushing them
- * up to ipppd)
- * and I tried to modify this file according to that. --abp
- */
-
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *mis, *is;
- int proto, slot = lp->ppp_slot;
- unsigned char *data;
-
- if (!skb || skb->len < 3)
- return;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- is = ippp_table[slot];
- /* Daemon may send with or without address and control field comp */
- data = skb->data;
- if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
- data += 2;
- if (skb->len < 5)
- return;
- }
-
- proto = ((int)data[0]<<8) + data[1];
- if (proto != PPP_CCP && proto != PPP_CCPFRAG)
- return;
-
- printk(KERN_DEBUG "Received CCP frame from daemon:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
- if (mis != is)
- printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
-
- switch (data[2]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable decompression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~SC_DECOMP_ON;
- else
- is->compflags &= ~SC_LINK_DECOMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we SEND an ackowledge we can/must enable the compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable compression here!\n");
- if (proto == PPP_CCP) {
- if (!is->compressor)
- break;
- is->compflags |= SC_COMP_ON;
- } else {
- if (!is->compressor)
- break;
- is->compflags |= SC_LINK_COMP_ON;
- }
- break;
- case CCP_RESETACK:
- /* If we send a ACK we should reset our compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Reset decompression state here!\n");
- printk(KERN_DEBUG "ResetAck from daemon passed by\n");
- if (proto == PPP_CCP) {
- /* link to master? */
- if (is->compressor && is->comp_stat)
- is->compressor->reset(is->comp_stat, 0, 0,
- NULL, 0, NULL);
- is->compflags &= ~SC_COMP_DISCARD;
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->reset(is->link_comp_stat,
- 0, 0, NULL, 0, NULL);
- is->compflags &= ~SC_LINK_COMP_DISCARD;
- }
- break;
- case CCP_RESETREQ:
- /* Just let it pass by */
- printk(KERN_DEBUG "ResetReq from daemon passed by\n");
- break;
- }
-}
-
-int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
-{
- ipc->next = ipc_head;
- ipc->prev = NULL;
- if (ipc_head) {
- ipc_head->prev = ipc;
- }
- ipc_head = ipc;
- return 0;
-}
-
-int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
-{
- if (ipc->prev)
- ipc->prev->next = ipc->next;
- else
- ipc_head = ipc->next;
- if (ipc->next)
- ipc->next->prev = ipc->prev;
- ipc->prev = ipc->next = NULL;
- return 0;
-}
-
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
-{
- struct isdn_ppp_compressor *ipc = ipc_head;
- int ret;
- void *stat;
- int num = data->num;
-
- if (is->debug & 0x10)
- printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
- (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
-
- /* If is has no valid reset state vector, we cannot allocate a
- decompressor. The decompressor would cause reset transactions
- sooner or later, and they need that vector. */
-
- if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
- printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
- " allow decompression.\n");
- return -ENOMEM;
- }
-
- while (ipc) {
- if (ipc->num == num) {
- stat = ipc->alloc(data);
- if (stat) {
- ret = ipc->init(stat, data, is->unit, 0);
- if (!ret) {
- printk(KERN_ERR "Can't init (de)compression!\n");
- ipc->free(stat);
- stat = NULL;
- break;
- }
- }
- else {
- printk(KERN_ERR "Can't alloc (de)compression!\n");
- break;
- }
-
- if (data->flags & IPPP_COMP_FLAG_XMIT) {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- is->link_comp_stat = stat;
- is->link_compressor = ipc;
- }
- else {
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- is->comp_stat = stat;
- is->compressor = ipc;
- }
- }
- else {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- is->link_decomp_stat = stat;
- is->link_decompressor = ipc;
- }
- else {
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->decomp_stat = stat;
- is->decompressor = ipc;
- }
- }
- return 0;
- }
- ipc = ipc->next;
- }
- return -EINVAL;
-}
+++ /dev/null
-/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
-#include <linux/isdn_ppp.h> /* for isdn_ppp info */
-
-extern int isdn_ppp_read(int, struct file *, char __user *, int);
-extern int isdn_ppp_write(int, struct file *, const char __user *, int);
-extern int isdn_ppp_open(int, struct file *);
-extern int isdn_ppp_init(void);
-extern void isdn_ppp_cleanup(void);
-extern int isdn_ppp_free(isdn_net_local *);
-extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
-extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
-extern int isdn_ppp_dial_slave(char *);
-extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
-
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
-
-#define IPPP_OPEN 0x01
-#define IPPP_CONNECT 0x02
-#define IPPP_CLOSEWAIT 0x04
-#define IPPP_NOBLOCK 0x08
-#define IPPP_ASSIGNED 0x10
-
-#define IPPP_MAX_HEADER 10
+++ /dev/null
-/*
- * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#undef ISDN_TTY_STAT_DEBUG
-
-#include <linux/isdn.h>
-#include <linux/serial.h> /* ASYNC_* flags */
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/sched/signal.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#define VBUF 0x3e0
-#define VBUFX (VBUF/16)
-#endif
-
-#define FIX_FILE_TRANSFER
-#define DUMMY_HAYES_AT
-
-/* Prototypes */
-
-static DEFINE_MUTEX(modem_info_mutex);
-static int isdn_tty_edit_at(const char *, int, modem_info *);
-static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
-static void isdn_tty_modem_reset_regs(modem_info *, int);
-static void isdn_tty_cmd_ATA(modem_info *);
-static void isdn_tty_flush_buffer(struct tty_struct *);
-static void isdn_tty_modem_result(int, modem_info *);
-#ifdef CONFIG_ISDN_AUDIO
-static int isdn_tty_countDLE(unsigned char *, int);
-#endif
-
-/* Leave this unchanged unless you know what you do! */
-#define MODEM_PARANOIA_CHECK
-#define MODEM_DO_RESTART
-
-static int bit2si[8] =
-{1, 5, 7, 7, 7, 7, 7, 7};
-static int si2bit[8] =
-{4, 1, 4, 4, 4, 4, 4, 4};
-
-/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
- * to stuff incoming data directly into a tty's flip-buffer. This
- * is done to speed up tty-receiving if the receive-queue is empty.
- * This routine MUST be called with interrupts off.
- * Return:
- * 1 = Success
- * 0 = Failure, data has to be buffered and later processed by
- * isdn_tty_readmodem().
- */
-static int
-isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
-{
- struct tty_port *port = &info->port;
- int c;
- int len;
- char last;
-
- if (!info->online)
- return 0;
-
- if (!(info->mcr & UART_MCR_RTS))
- return 0;
-
- len = skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- ;
-
- c = tty_buffer_request_room(port, len);
- if (c < len)
- return 0;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
- int l = skb->len;
- unsigned char *dp = skb->data;
- while (--l) {
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- tty_insert_flip_char(port, *dp++, 0);
- }
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- last = *dp;
- } else {
-#endif
- if (len > 1)
- tty_insert_flip_string(port, skb->data, len - 1);
- last = skb->data[len - 1];
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
- tty_flip_buffer_push(port);
- kfree_skb(skb);
-
- return 1;
-}
-
-/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
- * It tries getting received data from the receive queue an stuff it into
- * the tty's flip-buffer.
- */
-void
-isdn_tty_readmodem(void)
-{
- int resched = 0;
- int midx;
- int i;
- int r;
- modem_info *info;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- midx = dev->m_idx[i];
- if (midx < 0)
- continue;
-
- info = &dev->mdm.info[midx];
- if (!info->online)
- continue;
-
- r = 0;
-#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 1);
- if (r)
- tty_flip_buffer_push(&info->port);
- } else
- r = 1;
-
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
- }
- if (!resched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
-}
-
-int
-isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
-{
- ulong flags;
- int midx;
-#ifdef CONFIG_ISDN_AUDIO
- int ifmt;
-#endif
- modem_info *info;
-
- if ((midx = dev->m_idx[i]) < 0) {
- /* if midx is invalid, packet is not for tty */
- return 0;
- }
- info = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
- ifmt = 1;
-
- if ((info->vonline) && (!info->emu.vpar[4]))
- isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
-#endif
- if ((info->online < 2)
-#ifdef CONFIG_ISDN_AUDIO
- && (!(info->vonline & 1))
-#endif
- ) {
- /* If Modem not listening, drop data */
- kfree_skb(skb);
- return 1;
- }
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
- /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
- if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
- skb_pull(skb, 4);
- else
- if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
- skb_pull(skb, 2);
- } else
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb, 4);
- }
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- if (info->vonline & 1) {
- /* voice conversion/compression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm
- * Since compressed data takes less
- * space, we can overwrite the buffer.
- */
- skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
- ifmt,
- skb->data,
- skb->data,
- skb->len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_ulaw2alaw(skb->data, skb->len);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_alaw2ulaw(skb->data, skb->len);
- break;
- }
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- else {
- if (info->faxonline & 2) {
- isdn_tty_fax_bitorder(info, skb);
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
- }
-#endif
-#endif
- /* Try to deliver directly via tty-buf if queue is empty */
- spin_lock_irqsave(&info->readlock, flags);
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- if (isdn_tty_try_read(info, skb)) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return 1;
- }
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] +=
- (skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- );
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- return 1;
-}
-
-static void
-isdn_tty_cleanup_xmit(modem_info *info)
-{
- skb_queue_purge(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_purge(&info->dtmf_queue);
-#endif
-}
-
-static void
-isdn_tty_tint(modem_info *info)
-{
- struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
- int len, slen;
-
- if (!skb)
- return;
- len = skb->len;
- if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, 1, skb)) == len) {
- struct tty_struct *tty = info->port.tty;
- info->send_outstanding++;
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- tty_wakeup(tty);
- return;
- }
- if (slen < 0) {
- /* Error: no channel, already shutdown, or wrong parameter */
- dev_kfree_skb(skb);
- return;
- }
- skb_queue_head(&info->xmit_queue, skb);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static int
-isdn_tty_countDLE(unsigned char *buf, int len)
-{
- int count = 0;
-
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() to perform
- * DLE-decoding when sending audio-data.
- */
-static int
-isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
-{
- unsigned char *p = &info->port.xmit_buf[info->xmit_count];
- int count = 0;
-
- while (len > 0) {
- if (m->lastDLE) {
- m->lastDLE = 0;
- switch (*p) {
- case DLE:
- /* Escape code */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- count++;
- break;
- case ETX:
- /* End of data */
- info->vonline |= 4;
- return count;
- case DC4:
- /* Abort RX */
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003", info);
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- /* Fall through */
- case 'q':
- case 's':
- /* Silence */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- break;
- }
- } else {
- if (*p == DLE)
- m->lastDLE = 1;
- else
- count++;
- }
- p++;
- len--;
- }
- if (len < 0) {
- printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
- return 0;
- }
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() when receiving
- * audio-data. It interrupts receiving, if an character other than
- * ^S or ^Q is sent.
- */
-static int
-isdn_tty_end_vrx(const char *buf, int c)
-{
- char ch;
-
- while (c--) {
- ch = *buf;
- if ((ch != 0x11) && (ch != 0x13))
- return 1;
- buf++;
- }
- return 0;
-}
-
-static int voice_cf[7] =
-{0, 0, 4, 3, 2, 0, 0};
-
-#endif /* CONFIG_ISDN_AUDIO */
-
-/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
- * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
- * outgoing data from the tty's xmit-buffer, handles voice-decompression or
- * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
- */
-static void
-isdn_tty_senddown(modem_info *info)
-{
- int buflen;
- int skb_res;
-#ifdef CONFIG_ISDN_AUDIO
- int audio_len;
-#endif
- struct sk_buff *skb;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 4) {
- info->vonline &= ~6;
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "senddown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- }
-#endif
- if (!(buflen = info->xmit_count))
- return;
- if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- /* info->xmit_count is modified here and in isdn_tty_write().
- * So we return here if isdn_tty_write() is in the
- * critical section.
- */
- atomic_inc(&info->xmit_lock);
- if (!(atomic_dec_and_test(&info->xmit_lock)))
- return;
- if (info->isdn_driver < 0) {
- info->xmit_count = 0;
- return;
- }
- skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2)
- audio_len = buflen * voice_cf[info->emu.vpar[3]];
- else
- audio_len = 0;
- skb = dev_alloc_skb(skb_res + buflen + audio_len);
-#else
- skb = dev_alloc_skb(skb_res + buflen);
-#endif
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n",
- info->line);
- return;
- }
- skb_reserve(skb, skb_res);
- skb_put_data(skb, info->port.xmit_buf, buflen);
- info->xmit_count = 0;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- /* For now, ifmt is fixed to 1 (alaw), since this
- * is used with ISDN everywhere in the world, except
- * US, Canada and Japan.
- * Later, when US-ISDN protocols are implemented,
- * this setting will depend on the D-channel protocol.
- */
- int ifmt = 1;
-
- /* voice conversion/decompression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm, compatible to ZyXel 1496 modem
- * with ROM revision 6.01
- */
- audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- skb->data,
- skb_put(skb, audio_len),
- buflen);
- skb_pull(skb, buflen);
- skb_trim(skb, audio_len);
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_alaw2ulaw(skb->data,
- buflen);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_ulaw2alaw(skb->data,
- buflen);
- break;
- }
- }
-#endif /* CONFIG_ISDN_AUDIO */
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- /* Add T.70 simplified header */
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
- memcpy(skb_push(skb, 2), "\1\0", 2);
- else
- memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
- }
- skb_queue_tail(&info->xmit_queue, skb);
-}
-
-/************************************************************
- *
- * Modem-functions
- *
- * mostly "stolen" from original Linux-serial.c and friends.
- *
- ************************************************************/
-
-/* The next routine is called once from within timer-interrupt
- * triggered within isdn_tty_modem_ncarrier(). It calls
- * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
- * into the tty's buffer.
- */
-static void
-isdn_tty_modem_do_ncarrier(struct timer_list *t)
-{
- modem_info *info = from_timer(info, t, nc_timer);
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-}
-
-/* Next routine is called, whenever the DTR-signal is raised.
- * It checks the ncarrier-flag, and triggers the above routine
- * when necessary. The ncarrier-flag is set, whenever DTR goes
- * low.
- */
-static void
-isdn_tty_modem_ncarrier(modem_info *info)
-{
- if (info->ncarrier) {
- info->nc_timer.expires = jiffies + HZ;
- add_timer(&info->nc_timer);
- }
-}
-
-/*
- * return the usage calculated by si and layer 2 protocol
- */
-static int
-isdn_calc_usage(int si, int l2)
-{
- int usg = ISDN_USAGE_MODEM;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (si == 1) {
- switch (l2) {
- case ISDN_PROTO_L2_MODEM:
- usg = ISDN_USAGE_MODEM;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_PROTO_L2_FAX:
- usg = ISDN_USAGE_FAX;
- break;
-#endif
- case ISDN_PROTO_L2_TRANS:
- default:
- usg = ISDN_USAGE_VOICE;
- break;
- }
- }
-#endif
- return (usg);
-}
-
-/* isdn_tty_dial() performs dialing of a tty an the necessary
- * setup of the lower levels before that.
- */
-static void
-isdn_tty_dial(char *n, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- u_long flags;
- isdn_ctrl cmd;
- int i;
- int j;
-
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- sprintf(cmd.parm.setup.phone, "%s", n);
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.parm.setup.si1 = si;
- cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
- cmd.command = ISDN_CMD_DIAL;
- info->dialing = 1;
- info->emu.carrierwait = 0;
- strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_hangup() disassociates a tty from the real
- * ISDN-line (hangup). The usage-status is cleared
- * and some cleanup is done also.
- */
-void
-isdn_tty_modem_hup(modem_info *info, int local)
-{
- isdn_ctrl cmd;
- int di, ch;
-
- if (!info)
- return;
-
- di = info->isdn_driver;
- ch = info->isdn_channel;
- if (di < 0 || ch < 0)
- return;
-
- info->isdn_driver = -1;
- info->isdn_channel = -1;
-
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
-#endif
- info->rcvsched = 0;
- isdn_tty_flush_buffer(info->port.tty);
- if (info->online) {
- info->last_lhup = local;
- info->online = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- }
-#ifdef CONFIG_ISDN_AUDIO
- info->vonline = 0;
-#ifdef CONFIG_ISDN_TTY_FAX
- info->faxonline = 0;
- info->fax->phase = ISDN_FAX_PHASE_IDLE;
-#endif
- info->emu.vpar[4] = 0;
- info->emu.vpar[5] = 8;
- kfree(info->dtmf_state);
- info->dtmf_state = NULL;
- kfree(info->silence_state);
- info->silence_state = NULL;
- kfree(info->adpcms);
- info->adpcms = NULL;
- kfree(info->adpcmr);
- info->adpcmr = NULL;
-#endif
- if ((info->msr & UART_MSR_RI) &&
- (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
- isdn_tty_modem_result(RESULT_RUNG, info);
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
- info->lsr |= UART_LSR_TEMT;
-
- if (local) {
- cmd.driver = di;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = ch;
- isdn_command(&cmd);
- }
-
- isdn_all_eaz(di, ch);
- info->emu.mdmreg[REG_RINGCNT] = 0;
- isdn_free_channel(di, ch, 0);
-
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
-}
-
-/*
- * Begin of a CAPI like interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-#include <linux/module.h>
-
-int
-isdn_tty_capi_facility(capi_msg *cm) {
- return (-1); /* dummy */
-}
-
-/* isdn_tty_suspend() tries to suspend the current tty connection
- */
-static void
-isdn_tty_suspend(char *id, modem_info *info, atemu *m)
-{
- isdn_ctrl cmd;
-
- int l;
-
- if (!info)
- return;
-
-#ifdef ISDN_DEBUG_MODEM_SERVICES
- printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
-#endif
- l = strlen(id);
- if ((info->isdn_driver >= 0)) {
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- isdn_command(&cmd);
- }
-}
-
-/* isdn_tty_resume() tries to resume a suspended call
- * setup of the lower levels before that. unfortunately here is no
- * checking for compatibility of used protocols implemented by Q931
- * It does the same things like isdn_tty_dial, the last command
- * is different, may be we can merge it.
- */
-
-static void
-isdn_tty_resume(char *id, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = strlen(id);
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
-// strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- info->dialing = 1;
-// strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_send_msg() sends a message to a HL driver
- * This is used for hybrid modem cards to send AT commands to it
- */
-
-static void
-isdn_tty_send_msg(modem_info *info, atemu *m, char *msg)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = min(strlen(msg), sizeof(cmd.parm) - sizeof(cmd.parm.cmsg)
- + sizeof(cmd.parm.cmsg.para) - 2);
-
- if (!l) {
- isdn_tty_modem_result(RESULT_ERROR, info);
- return;
- }
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 14;
- cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = l + 1;
- strncpy(&cmd.parm.cmsg.para[1], msg, l);
- cmd.parm.cmsg.para[l + 1] = 0xd;
- cmd.command = CAPI_PUT_MESSAGE;
-/* info->dialing = 1;
- strcpy(dev->num[i], n);
- isdn_info_update();
-*/
- isdn_command(&cmd);
- }
-}
-
-static inline int
-isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
-{
-#ifdef MODEM_PARANOIA_CHECK
- if (!info) {
- printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
- name, routine);
- return 1;
- }
- if (info->magic != ISDN_ASYNC_MAGIC) {
- printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n",
- name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void
-isdn_tty_change_speed(modem_info *info)
-{
- struct tty_port *port = &info->port;
- uint cflag,
- cval,
- quot;
- int i;
-
- if (!port->tty)
- return;
- cflag = port->tty->termios.c_cflag;
-
- quot = i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2)
- port->tty->termios.c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (quot) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- } else {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in changespeed\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_reset_regs(info, 0);
- isdn_tty_modem_hup(info, 1);
- }
- return;
- }
- /* byte size and parity */
- cval = cflag & (CSIZE | CSTOPB);
- cval >>= 4;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- tty_port_set_check_carrier(port, ~cflag & CLOCAL);
-}
-
-static int
-isdn_tty_startup(modem_info *info)
-{
- if (tty_port_initialized(&info->port))
- return 0;
- isdn_lock_drivers();
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
-#endif
- /*
- * Now, initialize the UART
- */
- info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- /*
- * and set the speed of the serial port
- */
- isdn_tty_change_speed(info);
-
- tty_port_set_initialized(&info->port, 1);
- info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
- info->send_outstanding = 0;
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-isdn_tty_shutdown(modem_info *info)
-{
- if (!tty_port_initialized(&info->port))
- return;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
-#endif
- isdn_unlock_drivers();
- info->msr &= ~UART_MSR_RI;
- if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
- info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
- }
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- tty_port_set_initialized(&info->port, 0);
-}
-
-/* isdn_tty_write() is the main send-routine. It is called from the upper
- * levels within the kernel to perform sending data. Depending on the
- * online-flag it either directs output to the at-command-interpreter or
- * to the lower level. Additional tasks done here:
- * - If online, check for escape-sequence (+++)
- * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
- * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
- * - If dialing, abort dial.
- */
-static int
-isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
-{
- int c;
- int total = 0;
- modem_info *info = (modem_info *) tty->driver_data;
- atemu *m = &info->emu;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
- return 0;
- /* See isdn_tty_senddown() */
- atomic_inc(&info->xmit_lock);
- while (1) {
- c = count;
- if (c > info->xmit_size - info->xmit_count)
- c = info->xmit_size - info->xmit_count;
- if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
- c = dev->drv[info->isdn_driver]->maxbufsize;
- if (c <= 0)
- break;
- if ((info->online > 1)
-#ifdef CONFIG_ISDN_AUDIO
- || (info->vonline & 3)
-#endif
- ) {
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
- &(m->pluscount),
- &(m->lastplus));
- memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
- if (info->vonline & 2) {
- if (!cc) {
- /* If DLE decoding results in zero-transmit, but
- * c originally was non-zero, do a wakeup.
- */
- tty_wakeup(tty);
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- }
- info->xmit_count += cc;
- }
- if ((info->vonline & 3) == 1) {
- /* Do NOT handle Ctrl-Q or Ctrl-S
- * when in full-duplex audio mode.
- */
- if (isdn_tty_end_vrx(buf, c)) {
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
- }
- }
- } else
- if (TTY_IS_FCLASS1(info)) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
-
- if (info->vonline & 4) { /* ETX seen */
- isdn_ctrl c;
-
- c.command = ISDN_CMD_FAXCMD;
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
- c.parm.aux.subcmd = ETX;
- isdn_command(&c);
- }
- info->vonline = 0;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
-#endif
- info->xmit_count += cc;
- } else
-#endif
- info->xmit_count += c;
- } else {
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- if (info->dialing) {
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
-#endif
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- c = isdn_tty_edit_at(buf, c, info);
- }
- buf += c;
- count -= c;
- total += c;
- }
- atomic_dec(&info->xmit_lock);
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
- if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- }
- return total;
-}
-
-static int
-isdn_tty_write_room(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- int ret;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room"))
- return 0;
- if (!info->online)
- return info->xmit_size;
- ret = info->xmit_size - info->xmit_count;
- return (ret < 0) ? 0 : ret;
-}
-
-static int
-isdn_tty_chars_in_buffer(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer"))
- return 0;
- if (!info->online)
- return 0;
- return (info->xmit_count);
-}
-
-static void
-isdn_tty_flush_buffer(struct tty_struct *tty)
-{
- modem_info *info;
-
- if (!tty) {
- return;
- }
- info = (modem_info *) tty->driver_data;
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
- return;
- }
- isdn_tty_cleanup_xmit(info);
- info->xmit_count = 0;
- tty_wakeup(tty);
-}
-
-static void
-isdn_tty_flush_chars(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
- return;
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-isdn_tty_throttle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle"))
- return;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
- info->mcr &= ~UART_MCR_RTS;
-}
-
-static void
-isdn_tty_unthrottle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle"))
- return;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
- info->mcr |= UART_MCR_RTS;
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*
- * isdn_tty_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows RS485 driver to be written in user space.
- */
-static int
-isdn_tty_get_lsr_info(modem_info *info, uint __user *value)
-{
- u_char status;
- uint result;
-
- status = info->lsr;
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, value);
-}
-
-
-static int
-isdn_tty_tiocmget(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- u_char control, status;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
- mutex_lock(&modem_info_mutex);
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
-#endif
-
- control = info->mcr;
- status = info->msr;
- mutex_unlock(&modem_info_mutex);
- return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
-
-static int
-isdn_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
-#endif
-
- mutex_lock(&modem_info_mutex);
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- }
-
- if (clear & TIOCM_RTS)
- info->mcr &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR) {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in TIOCMSET\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_hup(info, 1);
- }
- }
- mutex_unlock(&modem_info_mutex);
- return 0;
-}
-
-static int
-isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
-#endif
- return isdn_tty_get_lsr_info(info, (uint __user *) arg);
- default:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
-#endif
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void
-isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- mutex_lock(&modem_info_mutex);
- if (!old_termios)
- isdn_tty_change_speed(info);
- else {
- if (tty->termios.c_cflag == old_termios->c_cflag &&
- tty->termios.c_ispeed == old_termios->c_ispeed &&
- tty->termios.c_ospeed == old_termios->c_ospeed) {
- mutex_unlock(&modem_info_mutex);
- return;
- }
- isdn_tty_change_speed(info);
- }
- mutex_unlock(&modem_info_mutex);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_open() and friends
- * ------------------------------------------------------------
- */
-
-static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- modem_info *info = &dev->mdm.info[tty->index];
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- tty->driver_data = info;
-
- return tty_port_install(&info->port, driver, tty);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int
-isdn_tty_open(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = tty->driver_data;
- struct tty_port *port = &info->port;
- int retval;
-
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
- port->count);
-#endif
- port->count++;
- port->tty = tty;
- /*
- * Start up serial port
- */
- retval = isdn_tty_startup(info);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after startup\n");
-#endif
- return retval;
- }
- retval = tty_port_block_til_ready(port, tty, filp);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
-#endif
- return retval;
- }
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
-#endif
- dev->modempoll++;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open normal exit\n");
-#endif
- return 0;
-}
-
-static void
-isdn_tty_close(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
- ulong timeout;
-
- if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
- return;
- if (tty_hung_up_p(filp)) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
-#endif
- return;
- }
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
-#endif
- return;
- }
- info->closing = 1;
-
- tty->closing = 1;
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- if (tty_port_initialized(port)) {
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies + HZ;
- while (!(info->lsr & UART_LSR_TEMT)) {
- schedule_timeout_interruptible(20);
- if (time_after(jiffies, timeout))
- break;
- }
- }
- dev->modempoll--;
- isdn_tty_shutdown(info);
- isdn_tty_flush_buffer(tty);
- tty_ldisc_flush(tty);
- port->tty = NULL;
- info->ncarrier = 0;
-
- tty_port_close_end(port, tty);
- info->closing = 0;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close normal exit\n");
-#endif
-}
-
-/*
- * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void
-isdn_tty_hangup(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
- return;
- isdn_tty_shutdown(info);
- port->count = 0;
- tty_port_set_active(port, 0);
- port->tty = NULL;
- wake_up_interruptible(&port->open_wait);
-}
-
-/* This routine initializes all emulator-data.
- */
-static void
-isdn_tty_reset_profile(atemu *m)
-{
- m->profile[0] = 0;
- m->profile[1] = 0;
- m->profile[2] = 43;
- m->profile[3] = 13;
- m->profile[4] = 10;
- m->profile[5] = 8;
- m->profile[6] = 3;
- m->profile[7] = 60;
- m->profile[8] = 2;
- m->profile[9] = 6;
- m->profile[10] = 7;
- m->profile[11] = 70;
- m->profile[12] = 0x45;
- m->profile[13] = 4;
- m->profile[14] = ISDN_PROTO_L2_X75I;
- m->profile[15] = ISDN_PROTO_L3_TRANS;
- m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
- m->profile[17] = ISDN_MODEM_WINSIZE;
- m->profile[18] = 4;
- m->profile[19] = 0;
- m->profile[20] = 0;
- m->profile[23] = 0;
- m->pmsn[0] = '\0';
- m->plmsn[0] = '\0';
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static void
-isdn_tty_modem_reset_vpar(atemu *m)
-{
- m->vpar[0] = 2; /* Voice-device (2 = phone line) */
- m->vpar[1] = 0; /* Silence detection level (0 = none ) */
- m->vpar[2] = 70; /* Silence interval (7 sec. ) */
- m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
- m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */
- m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */
-}
-#endif
-
-#ifdef CONFIG_ISDN_TTY_FAX
-static void
-isdn_tty_modem_reset_faxpar(modem_info *info)
-{
- T30_s *f = info->fax;
-
- f->code = 0;
- f->phase = ISDN_FAX_PHASE_IDLE;
- f->direction = 0;
- f->resolution = 1; /* fine */
- f->rate = 5; /* 14400 bit/s */
- f->width = 0;
- f->length = 0;
- f->compression = 0;
- f->ecm = 0;
- f->binary = 0;
- f->scantime = 0;
- memset(&f->id[0], 32, FAXIDLEN - 1);
- f->id[FAXIDLEN - 1] = 0;
- f->badlin = 0;
- f->badmul = 0;
- f->bor = 0;
- f->nbc = 0;
- f->cq = 0;
- f->cr = 0;
- f->ctcrty = 0;
- f->minsp = 0;
- f->phcto = 30;
- f->rel = 0;
- memset(&f->pollid[0], 32, FAXIDLEN - 1);
- f->pollid[FAXIDLEN - 1] = 0;
-}
-#endif
-
-static void
-isdn_tty_modem_reset_regs(modem_info *info, int force)
-{
- atemu *m = &info->emu;
- if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
- memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
- memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
- memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- }
-#ifdef CONFIG_ISDN_AUDIO
- isdn_tty_modem_reset_vpar(m);
-#endif
-#ifdef CONFIG_ISDN_TTY_FAX
- isdn_tty_modem_reset_faxpar(info);
-#endif
- m->mdmcmdl = 0;
-}
-
-static void
-modem_write_profile(atemu *m)
-{
- memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
- memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
- memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
- if (dev->profd)
- send_sig(SIGIO, dev->profd, 1);
-}
-
-static const struct tty_operations modem_ops = {
- .install = isdn_tty_install,
- .open = isdn_tty_open,
- .close = isdn_tty_close,
- .write = isdn_tty_write,
- .flush_chars = isdn_tty_flush_chars,
- .write_room = isdn_tty_write_room,
- .chars_in_buffer = isdn_tty_chars_in_buffer,
- .flush_buffer = isdn_tty_flush_buffer,
- .ioctl = isdn_tty_ioctl,
- .throttle = isdn_tty_throttle,
- .unthrottle = isdn_tty_unthrottle,
- .set_termios = isdn_tty_set_termios,
- .hangup = isdn_tty_hangup,
- .tiocmget = isdn_tty_tiocmget,
- .tiocmset = isdn_tty_tiocmset,
-};
-
-static int isdn_tty_carrier_raised(struct tty_port *port)
-{
- modem_info *info = container_of(port, modem_info, port);
- return info->msr & UART_MSR_DCD;
-}
-
-static const struct tty_port_operations isdn_tty_port_ops = {
- .carrier_raised = isdn_tty_carrier_raised,
-};
-
-int
-isdn_tty_modem_init(void)
-{
- isdn_modem_t *m;
- int i, retval;
- modem_info *info;
-
- m = &dev->mdm;
- m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
- if (!m->tty_modem)
- return -ENOMEM;
- m->tty_modem->name = "ttyI";
- m->tty_modem->major = ISDN_TTY_MAJOR;
- m->tty_modem->minor_start = 0;
- m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
- m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
- m->tty_modem->init_termios = tty_std_termios;
- m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
- m->tty_modem->driver_name = "isdn_tty";
- tty_set_operations(m->tty_modem, &modem_ops);
- retval = tty_register_driver(m->tty_modem);
- if (retval) {
- printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
- goto err;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
- printk(KERN_ERR "Could not allocate fax t30-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
-#endif
- tty_port_init(&info->port);
- info->port.ops = &isdn_tty_port_ops;
- spin_lock_init(&info->readlock);
- sprintf(info->last_cause, "0000");
- sprintf(info->last_num, "none");
- info->last_dir = 0;
- info->last_lhup = 1;
- info->last_l2 = -1;
- info->last_si = 0;
- isdn_tty_reset_profile(&info->emu);
- isdn_tty_modem_reset_regs(info, 1);
- info->magic = ISDN_ASYNC_MAGIC;
- info->line = i;
- info->x_char = 0;
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- info->drv_index = -1;
- info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
- timer_setup(&info->nc_timer, isdn_tty_modem_do_ncarrier, 0);
- skb_queue_head_init(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_head_init(&info->dtmf_queue);
-#endif
- info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
- GFP_KERNEL);
- if (!info->port.xmit_buf) {
- printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
- /* Make room for T.70 header */
- info->port.xmit_buf += 4;
- }
- return 0;
-err_unregister:
- for (i--; i >= 0; i--) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(m->tty_modem);
-err:
- put_tty_driver(m->tty_modem);
- m->tty_modem = NULL;
- return retval;
-}
-
-void
-isdn_tty_exit(void)
-{
- modem_info *info;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- isdn_tty_cleanup_xmit(info);
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(dev->mdm.tty_modem);
- put_tty_driver(dev->mdm.tty_modem);
- dev->mdm.tty_modem = NULL;
-}
-
-
-/*
- * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
- * match the MSN against the MSNs (glob patterns) defined for tty_emulator,
- * and return 0 for match, 1 for no match, 2 if MSN could match if longer.
- */
-
-static int
-isdn_tty_match_icall(char *cid, atemu *emu, int di)
-{
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
- emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
- emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
-#endif
- if (strlen(emu->lmsn)) {
- char *p = emu->lmsn;
- char *q;
- int tmp;
- int ret = 0;
-
- while (1) {
- if ((q = strchr(p, ';')))
- *q = '\0';
- if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
- ret = tmp;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
- p, isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- if (q) {
- *q = ';';
- p = q;
- p++;
- }
- if (!tmp)
- return 0;
- if (!q)
- break;
- }
- return ret;
- } else {
- int tmp;
- tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
- isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- return tmp;
- }
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the tty-devices for an appropriate device and bind
- * it to the ISDN-Channel.
- * Return:
- *
- * 0 = No matching device found.
- * 1 = A matching device found.
- * 3 = No match found, but eventually would match, if
- * CID is longer.
- */
-int
-isdn_tty_find_icall(int di, int ch, setup_parm *setup)
-{
- char *eaz;
- int i;
- int wret;
- int idx;
- int si1;
- int si2;
- char *nr;
- ulong flags;
-
- if (!setup->phone[0]) {
- nr = "0";
- printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
- } else
- nr = setup->phone;
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
-#endif
- wret = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
-
- if (info->port.count == 0)
- continue;
- if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
- (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
- idx = isdn_dc2minor(di, ch);
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
- printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
- info->port.flags, info->isdn_driver,
- info->isdn_channel, dev->usage[idx]);
-#endif
- if (
-#ifndef FIX_FILE_TRANSFER
- tty_port_active(&info->port) &&
-#endif
- (info->isdn_driver == -1) &&
- (info->isdn_channel == -1) &&
- (USG_NONE(dev->usage[idx]))) {
- int matchret;
-
- if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
- wret = matchret;
- if (!matchret) { /* EAZ is matching */
- info->isdn_driver = di;
- info->isdn_channel = ch;
- info->drv_index = idx;
- dev->m_idx[idx] = info->line;
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
- strcpy(dev->num[idx], nr);
- strcpy(info->emu.cpn, eaz);
- info->emu.mdmreg[REG_SI1I] = si2bit[si1];
- info->emu.mdmreg[REG_PLAN] = setup->plan;
- info->emu.mdmreg[REG_SCREEN] = setup->screen;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
- info->line);
- info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(RESULT_RING, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
- return 1;
- }
- }
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
- ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored");
- return (wret == 2) ? 3 : 0;
-}
-
-int
-isdn_tty_stat_callback(int i, isdn_ctrl *c)
-{
- int mi;
- modem_info *info;
- char *e;
-
- if (i < 0)
- return 0;
- if ((mi = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[mi];
- switch (c->command) {
- case ISDN_STAT_CINF:
- printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
- info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
- if (e == (char *)c->parm.num)
- info->emu.charge = 0;
-
- break;
- case ISDN_STAT_BSENT:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
-#endif
- if ((info->isdn_driver == c->driver) &&
- (info->isdn_channel == c->arg)) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- return 1;
- }
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
-#endif
- /* Signal cause to tty-device */
- strncpy(info->last_cause, c->parm.num, 5);
- return 1;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
-#endif
- /* Signal display to tty-device */
- if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) &&
- !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("DISPLAY: ", info);
- isdn_tty_at_cout(c->parm.display, info);
- isdn_tty_at_cout("\r\n", info);
- }
- return 1;
- case ISDN_STAT_DCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1) {
- info->dialing = 2;
- return 1;
- }
- }
- break;
- case ISDN_STAT_DHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1)
- isdn_tty_modem_result(RESULT_BUSY, info);
- if (info->dialing > 1)
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_BCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
-#endif
- /* Wake up any processes waiting
- * for incoming call of this device when
- * DCD follow the state of incoming carrier
- */
- if (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
- wake_up_interruptible(&info->port.open_wait);
- }
-
- /* Schedule CONNECT-Message to any tty
- * waiting for it and
- * set DCD-bit of its modem-status.
- */
- if (tty_port_active(&info->port) ||
- (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
- info->msr |= UART_MSR_DCD;
- info->emu.charge = 0;
- if (info->dialing & 0xf)
- info->last_dir = 1;
- else
- info->last_dir = 0;
- info->dialing = 0;
- info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i])) {
- if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
- strcpy(info->emu.connmsg, c->parm.num);
- isdn_tty_modem_result(RESULT_CONNECT, info);
- } else
- isdn_tty_modem_result(RESULT_CONNECT64000, info);
- }
- if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(RESULT_VCON, info);
- return 1;
- }
- break;
- case ISDN_STAT_BHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing) {
- info->dialing = 0;
- info->last_l2 = -1;
- info->last_si = 0;
- sprintf(info->last_cause, "0000");
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- }
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_UNLOAD:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
-#endif
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- if (info->isdn_driver == c->driver) {
- if (info->online)
- isdn_tty_modem_hup(info, 1);
- }
- }
- return 1;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- if (tty_port_active(&info->port)) {
- isdn_tty_fax_command(info, c);
- }
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- if (tty_port_active(&info->port)) {
- switch (c->parm.num[0]) {
- case ISDN_AUDIO_DTMF:
- if (info->vonline) {
- isdn_audio_put_dle_code(info,
- c->parm.num[1]);
- }
- break;
- }
- }
- break;
-#endif
- }
- }
- return 0;
-}
-
-/*********************************************************************
- Modem-Emulator-Routines
-*********************************************************************/
-
-#define cmdchar(c) ((c >= ' ') && (c <= 0x7f))
-
-/*
- * Put a message from the AT-emulator into receive-buffer of tty,
- * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
- */
-void
-isdn_tty_at_cout(char *msg, modem_info *info)
-{
- struct tty_port *port = &info->port;
- atemu *m = &info->emu;
- char *p;
- char c;
- u_long flags;
- struct sk_buff *skb = NULL;
- char *sp = NULL;
- int l;
-
- if (!msg) {
- printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
- return;
- }
-
- l = strlen(msg);
-
- spin_lock_irqsave(&info->readlock, flags);
- if (info->closing) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
-
- /* use queue instead of direct, if online and */
- /* data is in queue or buffer is full */
- if (info->online && ((tty_buffer_request_room(port, l) < l) ||
- !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
- skb = alloc_skb(l, GFP_ATOMIC);
- if (!skb) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
- sp = skb_put(skb, l);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
-
- for (p = msg; *p; p++) {
- switch (*p) {
- case '\r':
- c = m->mdmreg[REG_CR];
- break;
- case '\n':
- c = m->mdmreg[REG_LF];
- break;
- case '\b':
- c = m->mdmreg[REG_BS];
- break;
- default:
- c = *p;
- }
- if (skb) {
- *sp++ = c;
- } else {
- if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
- break;
- }
- }
- if (skb) {
- __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
- dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if (dev->modempoll && info->rcvsched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-
- } else {
- spin_unlock_irqrestore(&info->readlock, flags);
- tty_flip_buffer_push(port);
- }
-}
-
-/*
- * Perform ATH Hangup
- */
-static void
-isdn_tty_on_hook(modem_info *info)
-{
- if (info->isdn_channel >= 0) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
-}
-
-static void
-isdn_tty_off_hook(void)
-{
- printk(KERN_DEBUG "isdn_tty_off_hook\n");
-}
-
-#define PLUSWAIT1 (HZ / 2) /* 0.5 sec. */
-#define PLUSWAIT2 (HZ * 3 / 2) /* 1.5 sec */
-
-/*
- * Check Buffer for Modem-escape-sequence, activate timer-callback to
- * isdn_tty_modem_escape() if sequence found.
- *
- * Parameters:
- * p pointer to databuffer
- * plus escape-character
- * count length of buffer
- * pluscount count of valid escape-characters so far
- * lastplus timestamp of last character
- */
-static void
-isdn_tty_check_esc(const u_char *p, u_char plus, int count, int *pluscount,
- u_long *lastplus)
-{
- if (plus > 127)
- return;
- if (count > 3) {
- p += count - 3;
- count = 3;
- *pluscount = 0;
- }
- while (count > 0) {
- if (*(p++) == plus) {
- if ((*pluscount)++) {
- /* Time since last '+' > 0.5 sec. ? */
- if (time_after(jiffies, *lastplus + PLUSWAIT1))
- *pluscount = 1;
- } else {
- /* Time since last non-'+' < 1.5 sec. ? */
- if (time_before(jiffies, *lastplus + PLUSWAIT2))
- *pluscount = 0;
- }
- if ((*pluscount == 3) && (count == 1))
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
- if (*pluscount > 3)
- *pluscount = 1;
- } else
- *pluscount = 0;
- *lastplus = jiffies;
- count--;
- }
-}
-
-/*
- * Return result of AT-emulator to tty-receive-buffer, depending on
- * modem-register 12, bit 0 and 1.
- * For CONNECT-messages also switch to online-mode.
- * For RING-message handle auto-ATA if register 0 != 0
- */
-
-static void
-isdn_tty_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- static char *msg[] =
- {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
- "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
- "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
- char s[ISDN_MSNLEN + 10];
-
- switch (code) {
- case RESULT_RING:
- m->mdmreg[REG_RINGCNT]++;
- if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
- /* Automatically accept incoming call */
- isdn_tty_cmd_ATA(info);
- break;
- case RESULT_NO_CARRIER:
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- info->closing, !info->port.tty);
-#endif
- m->mdmreg[REG_RINGCNT] = 0;
- del_timer(&info->nc_timer);
- info->ncarrier = 0;
- if (info->closing || !info->port.tty)
- return;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
- info->line);
-#endif
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
- }
-#endif
- break;
- case RESULT_CONNECT:
- case RESULT_CONNECT64000:
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 2;
- break;
- case RESULT_VCON:
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
- info->line);
-#endif
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 1;
- break;
- } /* switch (code) */
-
- if (m->mdmreg[REG_RESP] & BIT_RESP) {
- /* Show results */
- if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
- /* Show numeric results only */
- sprintf(s, "\r\n%d\r\n", code);
- isdn_tty_at_cout(s, info);
- } else {
- if (code == RESULT_RING) {
- /* return if "show RUNG" and ringcounter>1 */
- if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
- (m->mdmreg[REG_RINGCNT] > 1))
- return;
- /* print CID, _before_ _every_ ring */
- if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
- isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
- switch (code) {
- case RESULT_CONNECT:
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout(" ", info);
- isdn_tty_at_cout(m->connmsg, info);
- break;
- }
- break;
- case RESULT_RING:
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
- sprintf(s, "/%s", m->cpn);
- isdn_tty_at_cout(s, info);
- }
- /* Print CID only once, _after_ 1st RING */
- if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
- (m->mdmreg[REG_RINGCNT] == 1)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("CALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- break;
- case RESULT_NO_CARRIER:
- case RESULT_NO_DIALTONE:
- case RESULT_BUSY:
- case RESULT_NO_ANSWER:
- m->mdmreg[REG_RINGCNT] = 0;
- /* Append Cause-Message if enabled */
- if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
- sprintf(s, "/%s", info->last_cause);
- isdn_tty_at_cout(s, info);
- }
- break;
- case RESULT_CONNECT64000:
- /* Append Protocol to CONNECT message */
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("/X.75", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("/HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("/V110/9600", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("/V110/19200", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("/V110/38400", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- break;
- }
- isdn_tty_at_cout("\r\n", info);
- }
- }
- if (code == RESULT_NO_CARRIER) {
- if (info->closing || (!info->port.tty))
- return;
-
- if (tty_port_check_carrier(&info->port))
- tty_hangup(info->port.tty);
- }
-}
-
-
-/*
- * Display a modem-register-value.
- */
-static void
-isdn_tty_show_profile(int ridx, modem_info *info)
-{
- char v[6];
-
- sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
- isdn_tty_at_cout(v, info);
-}
-
-/*
- * Get MSN-string from char-pointer, set pointer to end of number
- */
-static void
-isdn_tty_get_msnstr(char *n, char **p)
-{
- int limit = ISDN_MSNLEN - 1;
-
- while (((*p[0] >= '0' && *p[0] <= '9') ||
- /* Why a comma ??? */
- (*p[0] == ',') || (*p[0] == ':')) &&
- (limit--))
- *n++ = *p[0]++;
- *n = '\0';
-}
-
-/*
- * Get phone-number from modem-commandbuffer
- */
-static void
-isdn_tty_getdial(char *p, char *q, int cnt)
-{
- int first = 1;
- int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid
- buffer overflow */
-
- while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt > 0) {
- if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
- ((*p == 'R') && first) ||
- (*p == '*') || (*p == '#')) {
- *q++ = *p;
- limit--;
- }
- if (!limit)
- break;
- p++;
- first = 0;
- }
- *q = 0;
-}
-
-#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
-#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
-
-static void
-isdn_tty_report(modem_info *info)
-{
- atemu *m = &info->emu;
- char s[80];
-
- isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
- sprintf(s, " Remote Number: %s\r\n", info->last_num);
- isdn_tty_at_cout(s, info);
- sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
- isdn_tty_at_cout(s, info);
- isdn_tty_at_cout(" Layer-2 Protocol: ", info);
- switch (info->last_l2) {
- case ISDN_PROTO_L2_X75I:
- isdn_tty_at_cout("X.75i", info);
- break;
- case ISDN_PROTO_L2_X75UI:
- isdn_tty_at_cout("X.75ui", info);
- break;
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("X.75bui", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("V.110 9600 Baud", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("V.110 19200 Baud", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("V.110 38400 Baud", info);
- break;
- case ISDN_PROTO_L2_TRANS:
- isdn_tty_at_cout("transparent", info);
- break;
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout("modem", info);
- break;
- case ISDN_PROTO_L2_FAX:
- isdn_tty_at_cout("fax", info);
- break;
- default:
- isdn_tty_at_cout("unknown", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(" Service: ", info);
- switch (info->last_si) {
- case 1:
- isdn_tty_at_cout("audio\r\n", info);
- break;
- case 5:
- isdn_tty_at_cout("btx\r\n", info);
- break;
- case 7:
- isdn_tty_at_cout("data\r\n", info);
- break;
- default:
- sprintf(s, "%d\r\n", info->last_si);
- isdn_tty_at_cout(s, info);
- break;
- }
- sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
- isdn_tty_at_cout(s, info);
- sprintf(s, " Last cause: %s\r\n", info->last_cause);
- isdn_tty_at_cout(s, info);
-}
-
-/*
- * Parse AT&.. commands.
- */
-static int
-isdn_tty_cmd_ATand(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int i;
- char rb[100];
-
-#define MAXRB (sizeof(rb) - 1)
-
- switch (*p[0]) {
- case 'B':
- /* &B - Set Buffersize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
- PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
- PARSE_ERROR1;
-#endif
- m->mdmreg[REG_PSIZE] = i / 16;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case 'C':
- /* &C - DCD Status */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DCD] &= ~BIT_DCD;
- break;
- case 1:
- m->mdmreg[REG_DCD] |= BIT_DCD;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'D':
- /* &D - Set DTR-Low-behavior */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 2:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 3:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] |= BIT_DTRR;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'E':
- /* &E -Set EAZ/MSN */
- p[0]++;
- isdn_tty_get_msnstr(m->msn, p);
- break;
- case 'F':
- /* &F -Set Factory-Defaults */
- p[0]++;
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR1;
- isdn_tty_reset_profile(m);
- isdn_tty_modem_reset_regs(info, 1);
- break;
-#ifdef DUMMY_HAYES_AT
- case 'K':
- /* only for be compilant with common scripts */
- /* &K Flowcontrol - no function */
- p[0]++;
- isdn_getnum(p);
- break;
-#endif
- case 'L':
- /* &L -Set Numbers to listen on */
- p[0]++;
- i = 0;
- while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN - 1))
- m->lmsn[i++] = *p[0]++;
- m->lmsn[i] = '\0';
- break;
- case 'R':
- /* &R - Set V.110 bitrate adaption */
- p[0]++;
- i = isdn_getnum(p);
- switch (i) {
- case 0:
- /* Switch off V.110, back to X.75 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_SI2] = 0;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 9600:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
- m->mdmreg[REG_SI2] = 197;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 19200:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
- m->mdmreg[REG_SI2] = 199;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 38400:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
- m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- default:
- PARSE_ERROR1;
- }
- /* Switch off T.70 */
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- /* Set Service 7 */
- m->mdmreg[REG_SI1] |= 4;
- break;
- case 'S':
- /* &S - Set Windowsize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i > 0) && (i < 9))
- m->mdmreg[REG_WSIZE] = i;
- else
- PARSE_ERROR1;
- break;
- case 'V':
- /* &V - Show registers */
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
- sprintf(rb, "S%02d=%03d%s", i,
- m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
- isdn_tty_at_cout(rb, info);
- }
- sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
- strlen(m->msn) ? m->msn : "None");
- isdn_tty_at_cout(rb, info);
- if (strlen(m->lmsn)) {
- isdn_tty_at_cout("\r\nListen: ", info);
- isdn_tty_at_cout(m->lmsn, info);
- isdn_tty_at_cout("\r\n", info);
- }
- break;
- case 'W':
- /* &W - Write Profile */
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- modem_write_profile(m);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 'X':
- /* &X - Switch to BTX-Mode and T.70 */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 1:
- m->mdmreg[REG_T70] |= BIT_T70;
- m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- case 2:
- m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-
-static int
-isdn_tty_check_ats(int mreg, int mval, modem_info *info, atemu *m)
-{
- /* Some plausibility checks */
- switch (mreg) {
- case REG_L2PROT:
- if (mval > ISDN_PROTO_L2_MAX)
- return 1;
- break;
- case REG_PSIZE:
- if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
- return 1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
- return 1;
-#endif
- info->xmit_size = mval * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case REG_SI1I:
- case REG_PLAN:
- case REG_SCREEN:
- /* readonly registers */
- return 1;
- }
- return 0;
-}
-
-/*
- * Perform ATS command
- */
-static int
-isdn_tty_cmd_ATS(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int bitpos;
- int mreg;
- int mval;
- int bval;
-
- mreg = isdn_getnum(p);
- if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- mval = isdn_getnum(p);
- if (mval < 0 || mval > 255)
- PARSE_ERROR1;
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '.':
- /* Set/Clear a single bit */
- p[0]++;
- bitpos = isdn_getnum(p);
- if ((bitpos < 0) || (bitpos > 7))
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- bval = isdn_getnum(p);
- if (bval < 0 || bval > 1)
- PARSE_ERROR1;
- if (bval)
- mval = m->mdmreg[mreg] | (1 << bitpos);
- else
- mval = m->mdmreg[mreg] & ~(1 << bitpos);
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case '?':
- p[0]++;
- isdn_tty_show_profile(mreg, info);
- break;
- default:
- PARSE_ERROR1;
- break;
- }
- return 0;
-}
-
-/*
- * Perform ATA command
- */
-static void
-isdn_tty_cmd_ATA(modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- int l2;
-
- if (info->msr & UART_MSR_RI) {
- /* Accept incoming call */
- info->last_dir = 0;
- strcpy(info->last_num, dev->num[info->drv_index]);
- m->mdmreg[REG_RINGCNT] = 0;
- info->msr &= ~UART_MSR_RI;
- l2 = m->mdmreg[REG_L2PROT];
-#ifdef CONFIG_ISDN_AUDIO
- /* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
- if (m->mdmreg[REG_SI1I] == 1) {
- if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
- l2 = ISDN_PROTO_L2_TRANS;
- } else
- l2 = ISDN_PROTO_L2_X75I;
- }
-#endif
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- info->last_l2 = l2;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_IN;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTD;
- info->dialing = 16;
- info->emu.carrierwait = 0;
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- } else
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-/*
- * Parse AT+F.. commands
- */
-static int
-isdn_tty_cmd_PLUSF(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- char rs[20];
-
- if (!strncmp(p[0], "CLASS", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d",
- (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (TTY_IS_FCLASS2(info))
- sprintf(rs, "\r\n2");
- else if (TTY_IS_FCLASS1(info))
- sprintf(rs, "\r\n1");
-#endif
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 4;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case '1':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS1))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
- case '2':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS2))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#endif
- case '8':
- p[0]++;
- /* L2 will change on dialout with si=1 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 5;
- info->xmit_size = VBUF;
- break;
- case '?':
- p[0]++;
- strcpy(rs, "\r\n0,");
-#ifdef CONFIG_ISDN_TTY_FAX
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS1)
- strcat(rs, "1,");
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS2)
- strcat(rs, "2,");
-#endif
- strcat(rs, "8");
- isdn_tty_at_cout(rs, info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- return (isdn_tty_cmd_PLUSF_FAX(p, info));
-#else
- PARSE_ERROR1;
-#endif
-}
-
-/*
- * Parse AT+V.. commands
- */
-static int
-isdn_tty_cmd_PLUSV(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- static char *vcmd[] =
- {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
- int i;
- int par1;
- int par2;
- char rs[20];
-
- i = 0;
- while (vcmd[i]) {
- if (!strncmp(vcmd[i], p[0], 2)) {
- p[0] += 2;
- break;
- }
- i++;
- }
- switch (i) {
- case 0:
- /* AT+VNH - Auto hangup feature */
- switch (*p[0]) {
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '1':
- p[0]++;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 1:
- /* AT+VIP - Reset all voice parameters */
- isdn_tty_modem_reset_vpar(m);
- break;
- case 2:
- /* AT+VLS - Select device, accept incoming call */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", m->vpar[0]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->vpar[0] = 0;
- break;
- case '2':
- p[0]++;
- m->vpar[0] = 2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n0,2", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 3:
- /* AT+VRX - Start recording */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- info->silence_state = isdn_audio_silence_init(info->silence_state);
- if (!info->silence_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
- if (!info->adpcmr) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VRX\n");
-#endif
- info->vonline |= 1;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 4:
- /* AT+VSD - Silence detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[1],
- m->vpar[2]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 31))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[1] = par1;
- m->vpar[2] = par2;
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-31>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 5:
- /* AT+VSM - Select compression */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d><8000>",
- m->vpar[3],
- m->vpar[1]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- par1 = isdn_getnum(p);
- if ((par1 < 2) || (par1 > 6))
- PARSE_ERROR1;
- m->vpar[3] = par1;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 6:
- /* AT+VTX - Start sending */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
- if (!info->adpcms) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VTX\n");
-#endif
- m->lastDLE = 0;
- info->vonline |= 2;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 7:
- /* AT+VDD - DTMF detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[4],
- m->vpar[5]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- if (info->online != 1)
- PARSE_ERROR1;
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 15))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[4] = par1;
- m->vpar[5] = par2;
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_AUDIO;
- cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
- cmd.parm.num[0] = par1;
- cmd.parm.num[1] = par2;
- isdn_command(&cmd);
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-15>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-#endif /* CONFIG_ISDN_AUDIO */
-
-/*
- * Parse and perform an AT-command-line.
- */
-static void
-isdn_tty_parse_at(modem_info *info)
-{
- atemu *m = &info->emu;
- char *p;
- char ds[ISDN_MSNLEN];
-
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
-#endif
- for (p = &m->mdmcmd[2]; *p;) {
- switch (*p) {
- case ' ':
- p++;
- break;
- case 'A':
- /* A - Accept incoming call */
- p++;
- isdn_tty_cmd_ATA(info);
- return;
- case 'D':
- /* D - Dial */
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR;
- if (info->msr & UART_MSR_RI) {
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- }
- isdn_tty_getdial(++p, ds, sizeof ds);
- p += strlen(p);
- if (!strlen(m->msn))
- isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
- else if (strlen(ds))
- isdn_tty_dial(ds, info, m);
- else
- PARSE_ERROR;
- return;
- case 'E':
- /* E - Turn Echo on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
- break;
- case 1:
- m->mdmreg[REG_ECHO] |= BIT_ECHO;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'H':
- /* H - On/Off-hook */
- p++;
- switch (*p) {
- case '0':
- p++;
- isdn_tty_on_hook(info);
- break;
- case '1':
- p++;
- isdn_tty_off_hook();
- break;
- default:
- isdn_tty_on_hook(info);
- break;
- }
- break;
- case 'I':
- /* I - Information */
- p++;
- isdn_tty_at_cout("\r\nLinux ISDN", info);
- switch (*p) {
- case '0':
- case '1':
- p++;
- break;
- case '2':
- p++;
- isdn_tty_report(info);
- break;
- case '3':
- p++;
- snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge);
- isdn_tty_at_cout(ds, info);
- break;
- default:;
- }
- break;
-#ifdef DUMMY_HAYES_AT
- case 'L':
- case 'M':
- /* only for be compilant with common scripts */
- /* no function */
- p++;
- isdn_getnum(&p);
- break;
-#endif
- case 'O':
- /* O - Go online */
- p++;
- if (info->msr & UART_MSR_DCD)
- /* if B-Channel is up */
- isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT : RESULT_CONNECT64000, info);
- else
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- case 'Q':
- /* Q - Turn Emulator messages on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESP;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESP;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'S':
- /* S - Set/Get Register */
- p++;
- if (isdn_tty_cmd_ATS(&p, info))
- return;
- break;
- case 'V':
- /* V - Numeric or ASCII Emulator-messages */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESPNUM;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'Z':
- /* Z - Load Registers from Profile */
- p++;
- if (info->msr & UART_MSR_DCD) {
- info->online = 0;
- isdn_tty_on_hook(info);
- }
- isdn_tty_modem_reset_regs(info, 1);
- break;
- case '+':
- p++;
- switch (*p) {
-#ifdef CONFIG_ISDN_AUDIO
- case 'F':
- p++;
- if (isdn_tty_cmd_PLUSF(&p, info))
- return;
- break;
- case 'V':
- if ((!(m->mdmreg[REG_SI1] & 1)) ||
- (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
- PARSE_ERROR;
- p++;
- if (isdn_tty_cmd_PLUSV(&p, info))
- return;
- break;
-#endif /* CONFIG_ISDN_AUDIO */
- case 'S': /* SUSPEND */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_suspend(ds, info, m);
- break;
- case 'R': /* RESUME */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_resume(ds, info, m);
- break;
- case 'M': /* MESSAGE */
- p++;
- isdn_tty_send_msg(info, m, p);
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case '&':
- p++;
- if (isdn_tty_cmd_ATand(&p, info))
- return;
- break;
- default:
- PARSE_ERROR;
- }
- }
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_modem_result(RESULT_OK, info);
-}
-
-/* Need own toupper() because standard-toupper is not available
- * within modules.
- */
-#define my_toupper(c) (((c >= 'a') && (c <= 'z')) ? (c & 0xdf) : c)
-
-/*
- * Perform line-editing of AT-commands
- *
- * Parameters:
- * p inputbuffer
- * count length of buffer
- * channel index to line (minor-device)
- */
-static int
-isdn_tty_edit_at(const char *p, int count, modem_info *info)
-{
- atemu *m = &info->emu;
- int total = 0;
- u_char c;
- char eb[2];
- int cnt;
-
- for (cnt = count; cnt > 0; p++, cnt--) {
- c = *p;
- total++;
- if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
- /* Separator (CR or LF) */
- m->mdmcmd[m->mdmcmdl] = 0;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
- isdn_tty_parse_at(info);
- m->mdmcmdl = 0;
- continue;
- }
- if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
- /* Backspace-Function */
- if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
- if (m->mdmcmdl)
- m->mdmcmdl--;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO)
- isdn_tty_at_cout("\b", info);
- }
- continue;
- }
- if (cmdchar(c)) {
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if (m->mdmcmdl < 255) {
- c = my_toupper(c);
- switch (m->mdmcmdl) {
- case 1:
- if (c == 'T') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- break;
- } else
- m->mdmcmdl = 0;
- /* Fall through - check for 'A' */
- case 0:
- if (c == 'A') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- break;
- default:
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- }
- }
- }
- return total;
-}
-
-/*
- * Switch all modem-channels who are online and got a valid
- * escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_escape(void)
-{
- int ton = 0;
- int i;
- int midx;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies,
- info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
-}
-
-/*
- * Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_ring(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(RESULT_RING, info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
-}
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-void
-isdn_tty_modem_xmit(void)
-{
- int ton = 1;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->online) {
- ton = 1;
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
-}
-
-/*
- * Check all channels if we have a 'no carrier' timeout.
- * Timeout value is set by Register S7.
- */
-void
-isdn_tty_carrier_timeout(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (!info->dialing)
- continue;
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- ton = 1;
- }
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
-}
+++ /dev/null
-/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define DLE 0x10
-#define ETX 0x03
-#define DC4 0x14
-
-
-/*
- * Definition of some special Registers of AT-Emulator
- */
-#define REG_RINGATA 0
-#define REG_RINGCNT 1 /* ring counter register */
-#define REG_ESC 2
-#define REG_CR 3
-#define REG_LF 4
-#define REG_BS 5
-
-#define REG_WAITC 7
-
-#define REG_RESP 12 /* show response messages register */
-#define BIT_RESP 1 /* show response messages bit */
-#define REG_RESPNUM 12 /* show numeric responses register */
-#define BIT_RESPNUM 2 /* show numeric responses bit */
-#define REG_ECHO 12
-#define BIT_ECHO 4
-#define REG_DCD 12
-#define BIT_DCD 8
-#define REG_CTS 12
-#define BIT_CTS 16
-#define REG_DTRR 12
-#define BIT_DTRR 32
-#define REG_DSR 12
-#define BIT_DSR 64
-#define REG_CPPP 12
-#define BIT_CPPP 128
-
-#define REG_DXMT 13
-#define BIT_DXMT 1
-#define REG_T70 13
-#define BIT_T70 2
-#define BIT_T70_EXT 32
-#define REG_DTRHUP 13
-#define BIT_DTRHUP 4
-#define REG_RESPXT 13
-#define BIT_RESPXT 8
-#define REG_CIDONCE 13
-#define BIT_CIDONCE 16
-#define REG_RUNG 13 /* show RUNG message register */
-#define BIT_RUNG 64 /* show RUNG message bit */
-#define REG_DISPLAY 13
-#define BIT_DISPLAY 128
-
-#define REG_L2PROT 14
-#define REG_L3PROT 15
-#define REG_PSIZE 16
-#define REG_WSIZE 17
-#define REG_SI1 18
-#define REG_SI2 19
-#define REG_SI1I 20
-#define REG_PLAN 21
-#define REG_SCREEN 22
-
-#define REG_CPN 23
-#define BIT_CPN 1
-#define REG_CPNFCON 23
-#define BIT_CPNFCON 2
-#define REG_CDN 23
-#define BIT_CDN 4
-
-/* defines for result codes */
-#define RESULT_OK 0
-#define RESULT_CONNECT 1
-#define RESULT_RING 2
-#define RESULT_NO_CARRIER 3
-#define RESULT_ERROR 4
-#define RESULT_CONNECT64000 5
-#define RESULT_NO_DIALTONE 6
-#define RESULT_BUSY 7
-#define RESULT_NO_ANSWER 8
-#define RESULT_RINGING 9
-#define RESULT_NO_MSN_EAZ 10
-#define RESULT_VCON 11
-#define RESULT_RUNG 12
-
-#define TTY_IS_FCLASS1(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
-#define TTY_IS_FCLASS2(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
-
-extern void isdn_tty_modem_escape(void);
-extern void isdn_tty_modem_ring(void);
-extern void isdn_tty_carrier_timeout(void);
-extern void isdn_tty_modem_xmit(void);
-extern int isdn_tty_modem_init(void);
-extern void isdn_tty_exit(void);
-extern void isdn_tty_readmodem(void);
-extern int isdn_tty_find_icall(int, int, setup_parm *);
-extern int isdn_tty_stat_callback(int, isdn_ctrl *);
-extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
-extern int isdn_tty_capi_facility(capi_msg *cm);
-extern void isdn_tty_at_cout(char *, modem_info *);
-extern void isdn_tty_modem_hup(modem_info *, int);
-#ifdef CONFIG_ISDN_TTY_FAX
-extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
-extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
-#endif
+++ /dev/null
-/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_TTY_FAX_STAT_DEBUG
-#undef ISDN_TTY_FAX_CMD_DEBUG
-
-#include <linux/isdn.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_ttyfax.h"
-
-
-static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
-
-#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Fax Class 2 Modem results
- *
- */
-
-static void
-isdn_tty_fax_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- char rs[50];
- char rss[50];
- char *rp;
- int i;
- static char *msg[] =
- {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
- "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
- "+FCFR", "+FPTS:", "+FET:"};
-
-
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
- msg[code], info->line);
-#endif
- switch (code) {
- case 0: /* OK */
- break;
- case 1: /* ERROR */
- break;
- case 2: /* +FCON */
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
- (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
- sprintf(rs, "/%s", m->cpn);
- isdn_tty_at_cout(rs, info);
- }
- info->online = 1;
- f->fet = 0;
- if (f->phase == ISDN_FAX_PHASE_A)
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 3: /* +FCSI */
- case 8: /* +FTSI */
- sprintf(rs, "\"%s\"", f->r_id);
- isdn_tty_at_cout(rs, info);
- break;
- case 4: /* +FDIS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 5: /* +FHNG */
- sprintf(rs, "%d", f->code);
- isdn_tty_at_cout(rs, info);
- info->faxonline = 0;
- break;
- case 6: /* +FDCS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 7: /* CONNECT */
- info->faxonline |= 2;
- break;
- case 9: /* FCFR */
- break;
- case 10: /* FPTS */
- isdn_tty_at_cout("1", info);
- break;
- case 11: /* FET */
- sprintf(rs, "%d", f->fet);
- isdn_tty_at_cout(rs, info);
- break;
- }
-
- isdn_tty_at_cout("\r\n", info);
-
- switch (code) {
- case 7: /* CONNECT */
- info->online = 2;
- if (info->faxonline & 1) {
- sprintf(rs, "%c", XON);
- isdn_tty_at_cout(rs, info);
- }
- break;
- }
-}
-
-static int
-isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c)
-{
- static char *msg[] =
- {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
-#endif
- if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
- if (info->online)
- info->online = 1;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
- isdn_tty_at_cout("\r\n", info);
- }
- switch (c->parm.aux.cmd) {
- case ISDN_FAX_CLASS1_CONNECT:
- info->online = 2;
- break;
- case ISDN_FAX_CLASS1_OK:
- case ISDN_FAX_CLASS1_FCERROR:
- case ISDN_FAX_CLASS1_ERROR:
- case ISDN_FAX_CLASS1_NOCARR:
- break;
- case ISDN_FAX_CLASS1_QUERY:
- isdn_tty_at_cout("\r\n", info);
- if (!c->parm.aux.para[0]) {
- isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
- isdn_tty_at_cout("\r\n", info);
- } else {
- isdn_tty_at_cout(c->parm.aux.para, info);
- isdn_tty_at_cout("\r\nOK\r\n", info);
- }
- break;
- }
- return (0);
-}
-
-int
-isdn_tty_fax_command(modem_info *info, isdn_ctrl *c)
-{
- T30_s *f = info->fax;
- char rs[10];
-
- if (TTY_IS_FCLASS1(info))
- return (isdn_tty_fax_command1(info, c));
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
- f->r_code, info->line);
-#endif
- switch (f->r_code) {
- case ISDN_TTY_FAX_FCON:
- info->faxonline = 1;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_FCON_I:
- info->faxonline = 16;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_RID:
- if (info->faxonline & 1)
- isdn_tty_fax_modem_result(3, info); /* +FCSI */
- if (info->faxonline & 16)
- isdn_tty_fax_modem_result(8, info); /* +FTSI */
- return (0);
- case ISDN_TTY_FAX_DIS:
- isdn_tty_fax_modem_result(4, info); /* +FDIS */
- return (0);
- case ISDN_TTY_FAX_HNG:
- if (f->phase == ISDN_FAX_PHASE_C) {
- if (f->direction == ISDN_TTY_FAX_CONN_IN) {
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- } else {
- sprintf(rs, "%c", 0x18);
- isdn_tty_at_cout(rs, info);
- }
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- }
- f->phase = ISDN_FAX_PHASE_E;
- isdn_tty_fax_modem_result(5, info); /* +FHNG */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_DCS:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- f->phase = ISDN_FAX_PHASE_C;
- return (0);
- case ISDN_TTY_FAX_TRAIN_OK:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_SENT:
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_CFR:
- isdn_tty_fax_modem_result(9, info); /* +FCFR */
- return (0);
- case ISDN_TTY_FAX_ET:
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- isdn_tty_fax_modem_result(11, info); /* +FET */
- isdn_tty_fax_modem_result(0, info); /* OK */
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
- case ISDN_TTY_FAX_PTS:
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
- if (f->fet == 1)
- f->phase = ISDN_FAX_PHASE_B;
- if (f->fet == 0)
- isdn_tty_fax_modem_result(0, info); /* OK */
- }
- return (0);
- case ISDN_TTY_FAX_EOP:
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
-
- }
- return (-1);
-}
-
-
-void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
-{
- __u8 LeftMask;
- __u8 RightMask;
- __u8 fBit;
- __u8 Data;
- int i;
-
- if (!info->fax->bor) {
- for (i = 0; i < skb->len; i++) {
- Data = skb->data[i];
- for (
- LeftMask = 0x80, RightMask = 0x01;
- LeftMask > RightMask;
- LeftMask >>= 1, RightMask <<= 1
- ) {
- fBit = (Data & LeftMask);
- if (Data & RightMask)
- Data |= LeftMask;
- else
- Data &= ~LeftMask;
- if (fBit)
- Data |= RightMask;
- else
- Data &= ~RightMask;
-
- }
- skb->data[i] = Data;
- }
- }
-}
-
-/*
- * Parse AT+F.. FAX class 1 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS1(char **p, modem_info *info)
-{
- static char *cmd[] =
- {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
- isdn_ctrl c;
- int par, i;
- u_long flags;
-
- for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
- if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
- break;
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
-#endif
- if (c.parm.aux.cmd == 7)
- PARSE_ERROR1;
-
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- c.parm.aux.subcmd = AT_QUERY;
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- c.parm.aux.subcmd = AT_EQ_QUERY;
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- c.parm.aux.subcmd = AT_EQ_VALUE;
- c.parm.aux.para[0] = par;
- }
- break;
- case 0:
- c.parm.aux.subcmd = AT_COMMAND;
- break;
- default:
- PARSE_ERROR1;
- }
- c.command = ISDN_CMD_FAXCMD;
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
- c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
-#endif
- if (info->isdn_driver < 0) {
- if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
- (c.parm.aux.subcmd == AT_COMMAND)) {
- PARSE_ERROR1;
- }
- spin_lock_irqsave(&dev->lock, flags);
- /* get a temporary connection to the first free fax driver */
- i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
- ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- PARSE_ERROR1;
- }
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- spin_unlock_irqrestore(&dev->lock, flags);
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- spin_lock_irqsave(&dev->lock, flags);
- isdn_free_channel(info->isdn_driver, info->isdn_channel,
- ISDN_USAGE_FAX);
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- }
- return 1;
-}
-
-/*
- * Parse AT+F.. FAX class 2 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS2(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- isdn_ctrl cmd;
- int par;
- char rs[50];
- char rss[50];
- int maxdccval[] =
- {1, 5, 2, 2, 3, 2, 0, 7};
-
- /* FAA still unchanged */
- if (!strncmp(p[0], "AA", 2)) { /* TODO */
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", 0);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
- if (!strncmp(p[0], "BADLIN", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badlin);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badlin = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */
- if (!strncmp(p[0], "BADMUL", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badmul);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badmul = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BOR=n - Phase C bit order, 0=direct, 1=reverse */
- if (!strncmp(p[0], "BOR", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->bor);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->bor = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* NBC=n - No Best Capabilities */
- if (!strncmp(p[0], "NBC", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->nbc);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->nbc = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BUF? - Readonly buffersize readout */
- if (!strncmp(p[0], "BUF?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
-#endif
- p[0]++;
- sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
- /* CIG=string - local fax station id string for polling rx */
- if (!strncmp(p[0], "CIG", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->pollid);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->pollid[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->pollid[r] = 32;
- }
- f->pollid[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
- if (!strncmp(p[0], "CQ", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cq);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->cq = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
- if (!strncmp(p[0], "CR", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1"); /* display online help */
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->cr = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CTCRTY=value - ECM retry count */
- if (!strncmp(p[0], "CTCRTY", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ctcrty);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->ctcrty = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
- if (!strncmp(p[0], "DCC", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
- if (!strncmp(p[0], "DIS", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DR - Receive Phase C data command, initiates document reception */
- if (!strncmp(p[0], "DR", 2)) {
- p[0] += 2;
- if ((info->faxonline & 16) && /* incoming connection */
- ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
-#endif
- f->code = ISDN_TTY_FAX_DR;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_B) {
- f->phase = ISDN_FAX_PHASE_C;
- } else if (f->phase == ISDN_FAX_PHASE_D) {
- switch (f->fet) {
- case 0: /* next page will be received */
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- break;
- case 1: /* next doc will be received */
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 2: /* fax session is terminating */
- f->phase = ISDN_FAX_PHASE_E;
- break;
- default:
- PARSE_ERROR1;
- }
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
- if (!strncmp(p[0], "DT", 2)) {
- int i, val[] =
- {4, 0, 2, 3};
- char *rp = &f->resolution;
-
- p[0] += 2;
- if (!(info->faxonline & 1)) /* not outgoing connection */
- PARSE_ERROR1;
-
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[val[i]]) {
- PARSE_ERROR1;
- }
- rp[val[i]] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
- rp[4], rp[0], rp[2], rp[3]);
-#endif
- if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
- f->code = ISDN_TTY_FAX_DT;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_D) {
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
- if (!strncmp(p[0], "ECM", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ecm);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par != 0) && (par != 2))
- PARSE_ERROR1;
- f->ecm = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* ET=n - End of page or document */
- if (!strncmp(p[0], "ET=", 3)) {
- p[0] += 3;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-2");
- isdn_tty_at_cout(rs, info);
- } else {
- if ((f->phase != ISDN_FAX_PHASE_D) ||
- (!(info->faxonline & 1)))
- PARSE_ERROR1;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->fet = par;
- f->code = ISDN_TTY_FAX_ET;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
-#endif
- return 1;
- }
- return 0;
- }
- /* K - terminate */
- if (!strncmp(p[0], "K", 1)) {
- p[0] += 1;
- if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
- PARSE_ERROR1;
- isdn_tty_modem_hup(info, 1);
- return 1;
- }
- /* LID=string - local fax ID */
- if (!strncmp(p[0], "LID", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->id);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->id[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->id[r] = 32;
- }
- f->id[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* MDL? - DCE Model */
- if (!strncmp(p[0], "MDL?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMDL?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MFR? - DCE Manufacturer */
- if (!strncmp(p[0], "MFR?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMFR?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MINSP=n - Minimum Speed for Phase C */
- if (!strncmp(p[0], "MINSP", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->minsp);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-5");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 5))
- PARSE_ERROR1;
- f->minsp = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* PHCTO=value - DTE phase C timeout */
- if (!strncmp(p[0], "PHCTO", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->phcto);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->phcto = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* REL=n - Phase C received EOL alignment */
- if (!strncmp(p[0], "REL", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->rel);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->rel = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* REV? - DCE Revision */
- if (!strncmp(p[0], "REV?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FREV?\n");
-#endif
- strcpy(rss, isdn_tty_fax_revision);
- sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
-
- /* Phase C Transmit Data Block Size */
- if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
-#endif
- switch (*p[0]) {
- case '0':
- p[0]++;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
- PARSE_ERROR1;
-}
-
-int
-isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info)
-{
- if (TTY_IS_FCLASS2(info))
- return (isdn_tty_cmd_FCLASS2(p, info));
- else if (TTY_IS_FCLASS1(info))
- return (isdn_tty_cmd_FCLASS1(p, info));
- PARSE_ERROR1;
-}
+++ /dev/null
-/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define XON 0x11
-#define XOFF 0x13
-#define DC2 0x12
+++ /dev/null
-/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <linux/isdn.h>
-#include "isdn_v110.h"
-
-#undef ISDN_V110_DEBUG
-
-char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
-
-#define V110_38400 255
-#define V110_19200 15
-#define V110_9600 3
-
-/*
- * The following data are precoded matrices, online and offline matrix
- * for 9600, 19200 und 38400, respectively
- */
-static unsigned char V110_OnMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
-
-static unsigned char V110_OffMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
- 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
-
-static unsigned char V110_OffMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_38400[] =
-{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
-
-static unsigned char V110_OffMatrix_38400[] =
-{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
-
-/*
- * FlipBits reorders sequences of keylen bits in one byte.
- * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
- * and to 67452301 when keylen = 2. This is necessary because ordering on
- * the isdn line is the other way.
- */
-static inline unsigned char
-FlipBits(unsigned char c, int keylen)
-{
- unsigned char b = c;
- unsigned char bit = 128;
- int i;
- int j;
- int hunks = (8 / keylen);
-
- c = 0;
- for (i = 0; i < hunks; i++) {
- for (j = 0; j < keylen; j++) {
- if (b & (bit >> j))
- c |= bit >> (keylen - j - 1);
- }
- bit >>= keylen;
- }
- return c;
-}
-
-
-/* isdn_v110_open allocates and initializes private V.110 data
- * structures and returns a pointer to these.
- */
-static isdn_v110_stream *
-isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
-{
- int i;
- isdn_v110_stream *v;
-
- if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
- return NULL;
- v->key = key;
- v->nbits = 0;
- for (i = 0; key & (1 << i); i++)
- v->nbits++;
-
- v->nbytes = 8 / v->nbits;
- v->decodelen = 0;
-
- switch (key) {
- case V110_38400:
- v->OnlineFrame = V110_OnMatrix_38400;
- v->OfflineFrame = V110_OffMatrix_38400;
- break;
- case V110_19200:
- v->OnlineFrame = V110_OnMatrix_19200;
- v->OfflineFrame = V110_OffMatrix_19200;
- break;
- default:
- v->OnlineFrame = V110_OnMatrix_9600;
- v->OfflineFrame = V110_OffMatrix_9600;
- break;
- }
- v->framelen = v->nbytes * 10;
- v->SyncInit = 5;
- v->introducer = 0;
- v->dbit = 1;
- v->b = 0;
- v->skbres = hdrlen;
- v->maxsize = maxsize - hdrlen;
- if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
- kfree(v);
- return NULL;
- }
- return v;
-}
-
-/* isdn_v110_close frees private V.110 data structures */
-void
-isdn_v110_close(isdn_v110_stream *v)
-{
- if (v == NULL)
- return;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "v110 close\n");
-#endif
- kfree(v->encodebuf);
- kfree(v);
-}
-
-
-/*
- * ValidHeaderBytes return the number of valid bytes in v->decodebuf
- */
-static int
-ValidHeaderBytes(isdn_v110_stream *v)
-{
- int i;
- for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
- if ((v->decodebuf[i] & v->key) != 0)
- break;
- return i;
-}
-
-/*
- * SyncHeader moves the decodebuf ptr to the next valid header
- */
-static void
-SyncHeader(isdn_v110_stream *v)
-{
- unsigned char *rbuf = v->decodebuf;
- int len = v->decodelen;
-
- if (len == 0)
- return;
- for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
- if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
- break; /* jupp! */
- if (len)
- memcpy(v->decodebuf, rbuf, len);
-
- v->decodelen = len;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: Header resync\n");
-#endif
-}
-
-/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
- len is the number of matrix-lines. len must be a multiple of 10, i.e.
- only complete matices must be given.
- From these, netto data is extracted and returned in buf. The return-value
- is the bytecount of the decoded data.
-*/
-static int
-DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf)
-{
- int line = 0;
- int buflen = 0;
- int mbit = 64;
- int introducer = v->introducer;
- int dbit = v->dbit;
- unsigned char b = v->b;
-
- while (line < len) { /* Are we done with all lines of the matrix? */
- if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
- if (m[line] != 0x00) { /* not 0 ? -> error! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line of matrix */
- continue;
- } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
- if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line */
- continue;
- } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
- introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
- next_byte:
- if (mbit > 2) { /* was it the last bit in this line ? */
- mbit >>= 1; /* no -> take next */
- continue;
- } /* otherwise start with leftmost bit in the next line */
- mbit = 64;
- line++;
- continue;
- } else { /* otherwise we need to set a data bit */
- if (m[line] & mbit) /* was that bit set in the matrix ? */
- b |= dbit; /* yes -> set it in the data byte */
- else
- b &= dbit - 1; /* no -> clear it in the data byte */
- if (dbit < 128) /* is that data byte done ? */
- dbit <<= 1; /* no, got the next bit */
- else { /* data byte is done */
- buf[buflen++] = b; /* copy byte into the output buffer */
- introducer = b = 0; /* init of the intro sequence and of the data byte */
- dbit = 1; /* next we look for the 0th bit */
- }
- goto next_byte; /* look for next bit in the matrix */
- }
- }
- v->introducer = introducer;
- v->dbit = dbit;
- v->b = b;
- return buflen; /* return number of bytes in the output buffer */
-}
-
-/*
- * DecodeStream receives V.110 coded data from the input stream. It recovers the
- * original frames.
- * The input stream doesn't need to be framed
- */
-struct sk_buff *
-isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int len;
- unsigned char *v110_buf;
- unsigned char *rbuf;
-
- if (!skb) {
- printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
- return NULL;
- }
- rbuf = skb->data;
- len = skb->len;
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- if (v->decodelen == 0) /* cache empty? */
- for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
- if ((*rbuf & v->key) == 0)
- break; /* found first byte */
- if (len == 0) {
- dev_kfree_skb(skb);
- return NULL;
- }
- /* copy new data to decode-buffer */
- memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
- v->decodelen += len;
-ReSync:
- if (v->decodelen < v->nbytes) { /* got a new header ? */
- dev_kfree_skb(skb);
- return NULL; /* no, try later */
- }
- if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
- SyncHeader(v); /* no -> look for header */
- goto ReSync;
- }
- len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
- if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
- printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- for (i = 0; i < len; i++) {
- v110_buf[i] = 0;
- for (j = 0; j < v->nbytes; j++)
- v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
- v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
- }
- v->decodelen = (v->decodelen % (10 * v->nbytes));
- memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
-
- skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
- kfree(v110_buf);
- if (skb->len)
- return skb;
- else {
- kfree_skb(skb);
- return NULL;
- }
-}
-
-/* EncodeMatrix takes input data in buf, len is the bytecount.
- Data is encoded into v110 frames in m. Return value is the number of
- matrix-lines generated.
-*/
-static int
-EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
-{
- int line = 0;
- int i = 0;
- int mbit = 128;
- int dbit = 1;
- int introducer = 3;
- int ibit[] = {0, 1, 1};
-
- while ((i < len) && (line < mlen)) { /* while we still have input data */
- switch (line % 10) { /* in which line of the matrix are we? */
- case 0:
- m[line++] = 0x00; /* line 0 is always 0 */
- mbit = 128; /* go on with the 7th bit */
- break;
- case 5:
- m[line++] = 0xbf; /* line 5 is always 10111111 */
- mbit = 128; /* go on with the 7th bit */
- break;
- }
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- next_bit:
- switch (mbit) { /* leftmost or rightmost bit ? */
- case 1:
- line++; /* rightmost -> go to next line */
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- /* fall through */
- case 128:
- m[line] = 128; /* leftmost -> set byte to 1000000 */
- mbit = 64; /* current bit in the matrix line */
- continue;
- }
- if (introducer) { /* set 110 sequence ? */
- introducer--; /* set on digit less */
- m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
- mbit >>= 1; /* bit of matrix line >> 1 */
- goto next_bit; /* and go on there */
- } /* else push data bits into the matrix! */
- m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
- if (dbit == 128) { /* was it the last one? */
- dbit = 1; /* then go on with first bit of */
- i++; /* next byte in input buffer */
- if (i < len) /* input buffer done ? */
- introducer = 3; /* no, write introducer 110 */
- else { /* input buffer done ! */
- m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
- break;
- }
- } else /* not the last data bit */
- dbit <<= 1; /* then go to next data bit */
- mbit >>= 1; /* go to next bit of matrix */
- goto next_bit;
-
- }
- /* if necessary, generate remaining lines of the matrix... */
- if ((line) && ((line + 10) < mlen))
- switch (++line % 10) {
- case 1:
- m[line++] = 0xfe;
- /* fall through */
- case 2:
- m[line++] = 0xfe;
- /* fall through */
- case 3:
- m[line++] = 0xfe;
- /* fall through */
- case 4:
- m[line++] = 0xfe;
- /* fall through */
- case 5:
- m[line++] = 0xbf;
- /* fall through */
- case 6:
- m[line++] = 0xfe;
- /* fall through */
- case 7:
- m[line++] = 0xfe;
- /* fall through */
- case 8:
- m[line++] = 0xfe;
- /* fall through */
- case 9:
- m[line++] = 0xfe;
- }
- return line; /* that's how many lines we have */
-}
-
-/*
- * Build a sync frame.
- */
-static struct sk_buff *
-isdn_v110_sync(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OfflineFrame, v->framelen);
- }
- return skb;
-}
-
-/*
- * Build an idle frame.
- */
-static struct sk_buff *
-isdn_v110_idle(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OnlineFrame, v->framelen);
- }
- return skb;
-}
-
-struct sk_buff *
-isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int rlen;
- int mlen;
- int olen;
- int size;
- int sval1;
- int sval2;
- int nframes;
- unsigned char *v110buf;
- unsigned char *rbuf;
- struct sk_buff *nskb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
- return NULL;
- }
- if (!skb) {
- /* invalid skb, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
- return NULL;
- }
- rlen = skb->len;
- nframes = (rlen + 3) / 4;
- v110buf = v->encodebuf;
- if ((nframes * 40) > v->maxsize) {
- size = v->maxsize;
- rlen = v->maxsize / 40;
- } else
- size = nframes * 40;
- if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
- printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
- return NULL;
- }
- skb_reserve(nskb, v->skbres + sizeof(int));
- if (skb->len == 0) {
- skb_put_data(nskb, v->OnlineFrame, v->framelen);
- *((int *)skb_push(nskb, sizeof(int))) = 0;
- return nskb;
- }
- mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
- /* now distribute 2 or 4 bits each to the output stream! */
- rbuf = skb_put(nskb, size);
- olen = 0;
- sval1 = 8 - v->nbits;
- sval2 = v->key << sval1;
- for (i = 0; i < mlen; i++) {
- v110buf[i] = FlipBits(v110buf[i], v->nbits);
- for (j = 0; j < v->nbytes; j++) {
- if (size--)
- *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
- else {
- printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
- goto buffer_full;
- }
- olen++;
- }
- }
-buffer_full:
- skb_trim(nskb, olen);
- *((int *)skb_push(nskb, sizeof(int))) = rlen;
- return nskb;
-}
-
-int
-isdn_v110_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_v110_stream *v = NULL;
- int i;
- int ret = 0;
-
- if (idx < 0)
- return 0;
- switch (c->command) {
- case ISDN_STAT_BSENT:
- /* Keep the send-queue of the driver filled
- * with frames:
- * If number of outstanding frames < 3,
- * send down an Idle-Frame (or an Sync-Frame, if
- * v->SyncInit != 0).
- */
- if (!(v = dev->v110[idx]))
- return 0;
- atomic_inc(&dev->v110use[idx]);
- for (i = 0; i * v->framelen < c->parm.length; i++) {
- if (v->skbidle > 0) {
- v->skbidle--;
- ret = 1;
- } else {
- if (v->skbuser > 0)
- v->skbuser--;
- ret = 0;
- }
- }
- for (i = v->skbuser + v->skbidle; i < 2; i++) {
- struct sk_buff *skb;
- if (v->SyncInit > 0)
- skb = isdn_v110_sync(v);
- else
- skb = isdn_v110_idle(v);
- if (skb) {
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- break;
- } else {
- if (v->SyncInit)
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- break;
- }
- atomic_dec(&dev->v110use[idx]);
- return ret;
- case ISDN_STAT_DHUP:
- case ISDN_STAT_BHUP:
- while (1) {
- atomic_inc(&dev->v110use[idx]);
- if (atomic_dec_and_test(&dev->v110use[idx])) {
- isdn_v110_close(dev->v110[idx]);
- dev->v110[idx] = NULL;
- break;
- }
- mdelay(1);
- }
- break;
- case ISDN_STAT_BCONN:
- if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
- int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
- int maxsize = dev->drv[c->driver]->interface->maxbufsize;
- atomic_inc(&dev->v110use[idx]);
- switch (dev->v110emu[idx]) {
- case ISDN_PROTO_L2_V11096:
- dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11019:
- dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11038:
- dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
- break;
- default:;
- }
- if ((v = dev->v110[idx])) {
- while (v->SyncInit) {
- struct sk_buff *skb = isdn_v110_sync(v);
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- /* Unable to send, try later */
- break;
- }
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
- atomic_dec(&dev->v110use[idx]);
- }
- break;
- default:
- return 0;
- }
- return 0;
-}
+++ /dev/null
-/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _isdn_v110_h_
-#define _isdn_v110_h_
-
-/*
- * isdn_v110_encode will take raw data and encode it using V.110
- */
-extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
-
-/*
- * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
- * frames from them. The source stream doesn't need to be framed.
- */
-extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
-
-extern int isdn_v110_stat_callback(int, isdn_ctrl *);
-extern void isdn_v110_close(isdn_v110_stream *v);
-
-#endif
+++ /dev/null
-/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, X.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * stuff needed to support the Linux X.25 PLP code on top of devices that
- * can provide a lab_b service using the concap_proto mechanism.
- * This module supports a network interface which provides lapb_sematics
- * -- as defined in Documentation/networking/x25-iface.txt -- to
- * the upper layer and assumes that the lower layer provides a reliable
- * data link service by means of the concap_device_ops callbacks.
- *
- * Only protocol specific stuff goes here. Device specific stuff
- * goes to another -- device related -- concap_proto support source file.
- *
- */
-
-/* #include <linux/isdn.h> */
-#include <linux/netdevice.h>
-#include <linux/concap.h>
-#include <linux/slab.h>
-#include <linux/wanrouter.h>
-#include <net/x25device.h>
-#include "isdn_x25iface.h"
-
-/* for debugging messages not to cause an oops when device pointer is NULL*/
-#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
-
-
-typedef struct isdn_x25iface_proto_data {
- int magic;
- enum wan_states state;
- /* Private stuff, not to be accessed via proto_data. We provide the
- other storage for the concap_proto instance here as well,
- enabling us to allocate both with just one kmalloc(): */
- struct concap_proto priv;
-} ix25_pdata_t;
-
-
-
-/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
-static void isdn_x25iface_proto_del(struct concap_proto *);
-static int isdn_x25iface_proto_close(struct concap_proto *);
-static int isdn_x25iface_proto_restart(struct concap_proto *,
- struct net_device *,
- struct concap_device_ops *);
-static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_connect_ind(struct concap_proto *);
-static int isdn_x25iface_disconn_ind(struct concap_proto *);
-
-
-static struct concap_proto_ops ix25_pops = {
- .proto_new = &isdn_x25iface_proto_new,
- .proto_del = &isdn_x25iface_proto_del,
- .restart = &isdn_x25iface_proto_restart,
- .close = &isdn_x25iface_proto_close,
- .encap_and_xmit = &isdn_x25iface_xmit,
- .data_ind = &isdn_x25iface_receive,
- .connect_ind = &isdn_x25iface_connect_ind,
- .disconn_ind = &isdn_x25iface_disconn_ind
-};
-
-/* error message helper function */
-static void illegal_state_warn(unsigned state, unsigned char firstbyte)
-{
- printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
- "current state %d\n", firstbyte, state);
-}
-
-/* check protocol data field for consistency */
-static int pdata_is_bad(ix25_pdata_t *pda) {
-
- if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0;
- printk(KERN_WARNING
- "isdn_x25iface_xxx: illegal pointer to proto data\n");
- return 1;
-}
-
-/* create a new x25 interface protocol instance
- */
-struct concap_proto *isdn_x25iface_proto_new(void)
-{
- ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL);
- IX25DEBUG("isdn_x25iface_proto_new\n");
- if (tmp) {
- tmp->magic = ISDN_X25IFACE_MAGIC;
- tmp->state = WAN_UNCONFIGURED;
- /* private data space used to hold the concap_proto data.
- Only to be accessed via the returned pointer */
- spin_lock_init(&tmp->priv.lock);
- tmp->priv.dops = NULL;
- tmp->priv.net_dev = NULL;
- tmp->priv.pops = &ix25_pops;
- tmp->priv.flags = 0;
- tmp->priv.proto_data = tmp;
- return (&(tmp->priv));
- }
- return NULL;
-};
-
-/* close the x25iface encapsulation protocol
- */
-static int isdn_x25iface_proto_close(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
- int ret = 0;
- ulong flags;
-
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_close: "
- "invalid concap_proto pointer\n");
- return -1;
- }
- IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->dops = NULL;
- cprot->net_dev = NULL;
- tmp = cprot->proto_data;
- if (pdata_is_bad(tmp)) {
- ret = -1;
- } else {
- tmp->state = WAN_UNCONFIGURED;
- }
- spin_unlock_irqrestore(&cprot->lock, flags);
- return ret;
-}
-
-/* Delete the x25iface encapsulation protocol instance
- */
-static void isdn_x25iface_proto_del(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
-
- IX25DEBUG("isdn_x25iface_proto_del \n");
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_del: "
- "concap_proto pointer is NULL\n");
- return;
- }
- tmp = cprot->proto_data;
- if (tmp == NULL) {
- printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
- "proto_data pointer (maybe already deleted?)\n");
- return;
- }
- /* close if the protocol is still open */
- if (cprot->dops) isdn_x25iface_proto_close(cprot);
- /* freeing the storage should be sufficient now. But some additional
- settings might help to catch wild pointer bugs */
- tmp->magic = 0;
- cprot->proto_data = NULL;
-
- kfree(tmp);
- return;
-}
-
-/* (re-)initialize the data structures for x25iface encapsulation
- */
-static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops)
-{
- ix25_pdata_t *pda = cprot->proto_data;
- ulong flags;
-
- IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
-
- if (pdata_is_bad(pda)) return -1;
-
- if (!(dops && dops->data_req && dops->connect_req
- && dops->disconn_req)) {
- printk(KERN_WARNING "isdn_x25iface_restart: required dops"
- " missing\n");
- isdn_x25iface_proto_close(cprot);
- return -1;
- }
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->net_dev = ndev;
- cprot->pops = &ix25_pops;
- cprot->dops = dops;
- pda->state = WAN_DISCONNECTED;
- spin_unlock_irqrestore(&cprot->lock, flags);
- return 0;
-}
-
-/* deliver a dl_data frame received from i4l HL driver to the network layer
- */
-static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
-{
- IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
- if (((ix25_pdata_t *)(cprot->proto_data))
- ->state == WAN_CONNECTED) {
- if (skb_push(skb, 1)) {
- skb->data[0] = X25_IFACE_DATA;
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- }
- }
- printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
- dev_kfree_skb(skb);
- return -1;
-}
-
-/* a connection set up is indicated by lower layer
- */
-static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_connect_ind %s \n"
- , MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_connect_ind while unconfigured %s\n"
- , MY_DEVNAME(cprot->net_dev));
- return -1;
- }
- *state_p = WAN_CONNECTED;
-
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_CONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_connect_ind: "
- " out of memory -- disconnecting\n");
- cprot->dops->disconn_req(cprot);
- return -1;
- }
-}
-
-/* a disconnect is indicated by lower layer
- */
-static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_disconn_ind while unconfigured\n");
- return -1;
- }
- if (!cprot->net_dev) return -1;
- *state_p = WAN_DISCONNECTED;
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_DISCONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
- " out of memory\n");
- return -1;
- }
-}
-
-/* process a frame handed over to us from linux network layer. First byte
- semantics as defined in Documentation/networking/x25-iface.txt
-*/
-static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
-{
- unsigned char firstbyte = skb->data[0];
- enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
- int ret = 0;
- IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
- MY_DEVNAME(cprot->net_dev), firstbyte, *state);
- switch (firstbyte) {
- case X25_IFACE_DATA:
- if (*state == WAN_CONNECTED) {
- skb_pull(skb, 1);
- netif_trans_update(cprot->net_dev);
- ret = (cprot->dops->data_req(cprot, skb));
- /* prepare for future retransmissions */
- if (ret) skb_push(skb, 1);
- return ret;
- }
- illegal_state_warn(*state, firstbyte);
- break;
- case X25_IFACE_CONNECT:
- if (*state == WAN_DISCONNECTED) {
- *state = WAN_CONNECTING;
- ret = cprot->dops->connect_req(cprot);
- if (ret) {
- /* reset state and notify upper layer about
- * immidiatly failed attempts */
- isdn_x25iface_disconn_ind(cprot);
- }
- } else {
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_DISCONNECT:
- switch (*state) {
- case WAN_DISCONNECTED:
- /* Should not happen. However, give upper layer a
- chance to recover from inconstistency but don't
- trust the lower layer sending the disconn_confirm
- when already disconnected */
- printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
- " requested while disconnected\n");
- isdn_x25iface_disconn_ind(cprot);
- break; /* prevent infinite loops */
- case WAN_CONNECTING:
- case WAN_CONNECTED:
- *state = WAN_DISCONNECTED;
- cprot->dops->disconn_req(cprot);
- break;
- default:
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_PARAMS:
- printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
- " options not yet supported\n");
- break;
- default:
- printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
- " first byte %x ignored:\n", firstbyte);
- }
- dev_kfree_skb(skb);
- return 0;
-}
+++ /dev/null
-/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, x.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _LINUX_ISDN_X25IFACE_H
-#define _LINUX_ISDN_X25IFACE_H
-
-#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
-/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
-#ifdef DEBUG_ISDN_X25
-# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
-#else
-# define IX25DEBUG(fmt, args...)
-#endif
-
-#include <linux/skbuff.h>
-#include <linux/isdn.h>
-#include <linux/concap.h>
-
-extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt;
-extern struct concap_proto *isdn_x25iface_proto_new(void);
-
-
-
-#endif
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the isdnloop ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o
+++ /dev/null
-/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $
- *
- * ISDN low-level module implementing a dummy loop driver.
- *
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include "isdnloop.h"
-
-static char *isdnloop_id = "loop0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-module_param(isdnloop_id, charp, 0);
-MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
-
-static int isdnloop_addcard(char *);
-
-/*
- * Free queue completely.
- *
- * Parameter:
- * card = pointer to card struct
- * channel = channel number
- */
-static void
-isdnloop_free_queue(isdnloop_card *card, int channel)
-{
- struct sk_buff_head *queue = &card->bqueue[channel];
-
- skb_queue_purge(queue);
- card->sndcount[channel] = 0;
-}
-
-/*
- * Send B-Channel data to another virtual card.
- * This routine is called via timer-callback from isdnloop_pollbchan().
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel number (0-based)
- */
-static void
-isdnloop_bchan_send(isdnloop_card *card, int ch)
-{
- isdnloop_card *rcard = card->rcard[ch];
- int rch = card->rch[ch], len, ack;
- struct sk_buff *skb;
- isdn_ctrl cmd;
-
- while (card->sndcount[ch]) {
- skb = skb_dequeue(&card->bqueue[ch]);
- if (skb) {
- len = skb->len;
- card->sndcount[ch] -= len;
- ack = *(skb->head); /* used as scratch area */
- cmd.driver = card->myid;
- cmd.arg = ch;
- if (rcard) {
- rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
- } else {
- printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
- dev_kfree_skb(skb);
-
- }
- cmd.command = ISDN_STAT_BSENT;
- cmd.parm.length = len;
- card->interface.statcallb(&cmd);
- } else
- card->sndcount[ch] = 0;
- }
-}
-
-/*
- * Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- *
- * Parameter:
- * data = pointer to card struct, set by kernel timer.data
- */
-static void
-isdnloop_pollbchan(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, rb_timer);
- unsigned long flags;
-
- if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
- isdnloop_bchan_send(card, 0);
- if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
- isdnloop_bchan_send(card, 1);
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- } else
- card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
-}
-
-/*
- * Parse ICN-type setup string and fill fields of setup-struct
- * with parsed data.
- *
- * Parameter:
- * setup = setup string, format: [caller-id],si1,si2,[called-id]
- * cmd = pointer to struct to be filled.
- */
-static void
-isdnloop_parse_setup(char *setup, isdn_ctrl *cmd)
-{
- char *t = setup;
- char *s = strchr(t, ',');
-
- *s++ = '\0';
- strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone));
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd->parm.setup.si1 = 0;
- else
- cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10);
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd->parm.setup.si2 = 0;
- else
- cmd->parm.setup.si2 =
- simple_strtoul(t, NULL, 10);
- strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn));
- cmd->parm.setup.plan = 0;
- cmd->parm.setup.screen = 0;
-}
-
-typedef struct isdnloop_stat {
- char *statstr;
- int command;
- int action;
-} isdnloop_stat;
-/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_stat_table[] = {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
- {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
- {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
- {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
- {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
- {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
- {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
- {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
- {"E_L1: ACTIVATION FAILED",
- ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Parse Status message-strings from virtual card.
- * Depending on status, call statcallb for sending messages to upper
- * levels. Also set/reset B-Channel active-flags.
- *
- * Parameter:
- * status = status string to parse.
- * channel = channel where message comes from.
- * card = card where message comes from.
- */
-static void
-isdnloop_parse_status(u_char *status, int channel, isdnloop_card *card)
-{
- isdnloop_stat *s = isdnloop_stat_table;
- int action = -1;
- isdn_ctrl cmd;
-
- while (s->statstr) {
- if (!strncmp(status, s->statstr, strlen(s->statstr))) {
- cmd.command = s->command;
- action = s->action;
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 1:
- /* BCON_x */
- card->flags |= (channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
- break;
- case 2:
- /* BDIS_x */
- card->flags &= ~((channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
- isdnloop_free_queue(card, channel);
- break;
- case 3:
- /* DCAL_I and DSCA_I */
- isdnloop_parse_setup(status + 6, &cmd);
- break;
- case 4:
- /* FCALL */
- sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
- sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
- cmd.parm.setup.si1 = 7;
- cmd.parm.setup.si2 = 0;
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 5:
- /* CIF */
- strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
- break;
- case 6:
- /* AOC */
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
- (int) simple_strtoul(status + 7, NULL, 16));
- break;
- case 7:
- /* CAU */
- status += 3;
- if (strlen(status) == 4)
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
- status + 2, *status, *(status + 1));
- else
- strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
- break;
- case 8:
- /* Misc Errors on L1 and L2 */
- card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
- isdnloop_free_queue(card, 0);
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_BHUP;
- card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE;
- isdnloop_free_queue(card, 1);
- cmd.arg = 1;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- break;
- }
- card->interface.statcallb(&cmd);
-}
-
-/*
- * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
- *
- * Parameter:
- * card = pointer to card struct.
- * c = char to store.
- */
-static void
-isdnloop_putmsg(isdnloop_card *card, unsigned char c)
-{
- ulong flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Poll a virtual cards message queue.
- * If there are new status-replies from the card, copy them to
- * ringbuffer for reading on /dev/isdnctrl and call
- * isdnloop_parse_status() for processing them. Watch for special
- * Firmware bootmessage and parse it, to get the D-Channel protocol.
- * If there are B-Channels open, initiate a timer-callback to
- * isdnloop_pollbchan().
- * This routine is called periodically via timer interrupt.
- *
- * Parameter:
- * data = pointer to card struct
- */
-static void
-isdnloop_polldchan(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, st_timer);
- struct sk_buff *skb;
- int avail;
- int left;
- u_char c;
- int ch;
- unsigned long flags;
- u_char *p;
- isdn_ctrl cmd;
-
- skb = skb_dequeue(&card->dqueue);
- if (skb)
- avail = skb->len;
- else
- avail = 0;
- for (left = avail; left > 0; left--) {
- c = *skb->data;
- skb_pull(skb, 1);
- isdnloop_putmsg(card, c);
- card->imsg[card->iptr] = c;
- if (card->iptr < 59)
- card->iptr++;
- if (!skb->len) {
- avail++;
- isdnloop_putmsg(card, '\n');
- card->imsg[card->iptr] = 0;
- card->iptr = 0;
- if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
- card->imsg[1] <= '2' && card->imsg[2] == ';') {
- ch = (card->imsg[1] - '0') - 1;
- p = &card->imsg[3];
- isdnloop_parse_status(p, ch, card);
- } else {
- p = card->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p);
- if (!strncmp(p + 7, "TC", 2)) {
- card->ptype = ISDN_PTYPE_1TR6;
- card->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO
- "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID);
- }
- if (!strncmp(p + 7, "EC", 2)) {
- card->ptype = ISDN_PTYPE_EURO;
- card->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO
- "isdnloop: (%s) Euro-Protocol loaded and running\n", CID);
- }
- continue;
-
- }
- }
- }
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
- if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- del_timer(&card->rb_timer);
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- }
- /* schedule again */
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
- add_timer(&card->st_timer);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Append a packet to the transmit buffer-queue.
- *
- * Parameter:
- * channel = Number of B-channel
- * skb = packet to send.
- * card = pointer to card-struct
- * Return:
- * Number of bytes transferred, -E??? on error
- */
-static int
-isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card)
-{
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
-
- if (len > 4000) {
- printk(KERN_WARNING
- "isdnloop: Send packet too large\n");
- return -EINVAL;
- }
- if (len) {
- if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE)))
- return 0;
- if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
- return 0;
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- nskb = dev_alloc_skb(skb->len);
- if (nskb) {
- skb_copy_from_linear_data(skb,
- skb_put(nskb, len), len);
- skb_queue_tail(&card->bqueue[channel], nskb);
- dev_kfree_skb(skb);
- } else
- len = 0;
- card->sndcount[channel] += len;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- }
- return len;
-}
-
-/*
- * Read the messages from the card's ringbuffer
- *
- * Parameter:
- * buf = pointer to buffer.
- * len = number of bytes to read.
- * user = flag, 1: called from userlevel 0: called from kernel.
- * card = pointer to card struct.
- * Return:
- * number of bytes actually transferred.
- */
-static int
-isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card *card)
-{
- int count;
- u_char __user *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (put_user(*card->msg_buf_read++, p))
- return -EFAULT;
- if (card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- return count;
-}
-
-/*
- * Simulate a card's response by appending it to the cards
- * message queue.
- *
- * Parameter:
- * card = pointer to card struct.
- * s = pointer to message-string.
- * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages.
- * Return:
- * 0 on success, 1 on memory squeeze.
- */
-static int
-isdnloop_fake(isdnloop_card *card, char *s, int ch)
-{
- struct sk_buff *skb;
- int len = strlen(s) + ((ch >= 0) ? 3 : 0);
- skb = dev_alloc_skb(len);
- if (!skb) {
- printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
- return 1;
- }
- if (ch >= 0)
- sprintf(skb_put(skb, 3), "%02d;", ch);
- skb_put_data(skb, s, strlen(s));
- skb_queue_tail(&card->dqueue, skb);
- return 0;
-}
-/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_cmd_table[] = {
- {"BCON_R", 0, 1}, /* B-Channel connect */
- {"BCON_I", 0, 17}, /* B-Channel connect ind */
- {"BDIS_R", 0, 2}, /* B-Channel disconnect */
- {"DDIS_R", 0, 3}, /* D-Channel disconnect */
- {"DCON_R", 0, 16}, /* D-Channel connect */
- {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */
- {"DCAL_R", 0, 5}, /* Dial */
- {"EAZC", 0, 6}, /* Clear EAZ listener */
- {"EAZ", 0, 7}, /* Set EAZ listener */
- {"SEEAZ", 0, 8}, /* Get EAZ listener */
- {"MSN", 0, 9}, /* Set/Clear MSN listener */
- {"MSALL", 0, 10}, /* Set multi MSN listeners */
- {"SETSIL", 0, 11}, /* Set SI list */
- {"SEESIL", 0, 12}, /* Get SI list */
- {"SILC", 0, 13}, /* Clear SI list */
- {"LOCK", 0, -1}, /* LOCK channel */
- {"UNLOCK", 0, -1}, /* UNLOCK channel */
- {"FV2ON", 1, 14}, /* Leased mode on */
- {"FV2OFF", 1, 15}, /* Leased mode off */
- {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Simulate an error-response from a card.
- *
- * Parameter:
- * card = pointer to card struct.
- */
-static void
-isdnloop_fake_err(isdnloop_card *card)
-{
- char buf[64];
-
- snprintf(buf, sizeof(buf), "E%s", card->omsg);
- isdnloop_fake(card, buf, -1);
- isdnloop_fake(card, "NAK", -1);
-}
-
-static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12};
-static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a};
-
-/*
- * Assemble a simplified cause message depending on the
- * D-channel protocol used.
- *
- * Parameter:
- * card = pointer to card struct.
- * loc = location: 0 = local, 1 = remote.
- * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
- * Return:
- * Pointer to buffer containing the assembled message.
- */
-static char *
-isdnloop_unicause(isdnloop_card *card, int loc, int cau)
-{
- static char buf[6];
-
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
- break;
- case ISDN_PTYPE_1TR6:
- sprintf(buf, "%02X44", ctable_1t[cau]);
- break;
- default:
- return "0000";
- }
- return buf;
-}
-
-/*
- * Release a virtual connection. Called from timer interrupt, when
- * called party did not respond.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based)
- */
-static void
-isdnloop_atimeout(isdnloop_card *card, int ch)
-{
- unsigned long flags;
- char buf[60];
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- if (card->rcard[ch]) {
- isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
- card->rcard[ch]->rcard[card->rch[ch]] = NULL;
- card->rcard[ch] = NULL;
- }
- isdnloop_fake(card, "DDIS_I", ch + 1);
- /* No user responding */
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
- isdnloop_fake(card, buf, ch + 1);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Wrapper for isdnloop_atimeout().
- */
-static void
-isdnloop_atimeout0(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, c_timer[0]);
-
- isdnloop_atimeout(card, 0);
-}
-
-/*
- * Wrapper for isdnloop_atimeout().
- */
-static void
-isdnloop_atimeout1(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, c_timer[1]);
-
- isdnloop_atimeout(card, 1);
-}
-
-/*
- * Install a watchdog for a user, not responding.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel to watch for.
- */
-static void
-isdnloop_start_ctimer(isdnloop_card *card, int ch)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- timer_setup(&card->c_timer[ch], ch ? isdnloop_atimeout1
- : isdnloop_atimeout0, 0);
- card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
- add_timer(&card->c_timer[ch]);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Kill a pending channel watchdog.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based).
- */
-static void
-isdnloop_kill_ctimer(isdnloop_card *card, int ch)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- del_timer(&card->c_timer[ch]);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
-static u_char bit2si[] = {1, 5, 7};
-
-/*
- * Try finding a listener for an outgoing call.
- *
- * Parameter:
- * card = pointer to calling card.
- * p = pointer to ICN-type setup-string.
- * lch = channel of calling card.
- * cmd = pointer to struct to be filled when parsing setup.
- * Return:
- * 0 = found match, alerting should happen.
- * 1 = found matching number but it is busy.
- * 2 = no matching listener.
- * 3 = found matching number but SI does not match.
- */
-static int
-isdnloop_try_call(isdnloop_card *card, char *p, int lch, isdn_ctrl *cmd)
-{
- isdnloop_card *cc = cards;
- unsigned long flags;
- int ch;
- int num_match;
- int i;
- char *e;
- char nbuf[32];
-
- isdnloop_parse_setup(p, cmd);
- while (cc) {
- for (ch = 0; ch < 2; ch++) {
- /* Exclude ourself */
- if ((cc == card) && (ch == lch))
- continue;
- num_match = 0;
- switch (cc->ptype) {
- case ISDN_PTYPE_EURO:
- for (i = 0; i < 3; i++)
- if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
- num_match = 1;
- break;
- case ISDN_PTYPE_1TR6:
- e = cc->eazlist[ch];
- while (*e) {
- sprintf(nbuf, "%s%c", cc->s0num[0], *e);
- if (!(strcmp(nbuf, cmd->parm.setup.phone)))
- num_match = 1;
- e++;
- }
- }
- if (num_match) {
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- /* channel idle? */
- if (!(cc->rcard[ch])) {
- /* Check SI */
- if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 3;
- }
- /* ch is idle, si and number matches */
- cc->rcard[ch] = card;
- cc->rch[ch] = lch;
- card->rcard[lch] = cc;
- card->rch[lch] = ch;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 0;
- } else {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- /* num matches, but busy */
- if (ch == 1)
- return 1;
- }
- }
- }
- cc = cc->next;
- }
- return 2;
-}
-
-/*
- * Depending on D-channel protocol and caller/called, modify
- * phone number.
- *
- * Parameter:
- * card = pointer to card struct.
- * phone = pointer phone number.
- * caller = flag: 1 = caller, 0 = called.
- * Return:
- * pointer to new phone number.
- */
-static char *
-isdnloop_vstphone(isdnloop_card *card, char *phone, int caller)
-{
- int i;
- static char nphone[30];
-
- if (!card) {
- printk("BUG!!!\n");
- return "";
- }
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- if (caller) {
- for (i = 0; i < 2; i++)
- if (!(strcmp(card->s0num[i], phone)))
- return phone;
- return card->s0num[0];
- }
- return phone;
- break;
- case ISDN_PTYPE_1TR6:
- if (caller) {
- sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
- return nphone;
- } else
- return &phone[strlen(phone) - 1];
- break;
- }
- return "";
-}
-
-/*
- * Parse an ICN-type command string sent to the 'card'.
- * Perform misc. actions depending on the command.
- *
- * Parameter:
- * card = pointer to card struct.
- */
-static void
-isdnloop_parse_cmd(isdnloop_card *card)
-{
- char *p = card->omsg;
- isdn_ctrl cmd;
- char buf[60];
- isdnloop_stat *s = isdnloop_cmd_table;
- int action = -1;
- int i;
- int ch;
-
- if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
- isdnloop_fake_err(card);
- return;
- }
- ch = card->omsg[1] - '0';
- if ((ch < 0) || (ch > 2)) {
- isdnloop_fake_err(card);
- return;
- }
- p += 3;
- while (s->statstr) {
- if (!strncmp(p, s->statstr, strlen(s->statstr))) {
- action = s->action;
- if (s->command && (ch != 0)) {
- isdnloop_fake_err(card);
- return;
- }
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- switch (action) {
- case 1:
- /* 0x;BCON_R */
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BCON_I",
- card->rch[ch - 1] + 1);
- isdnloop_fake(card, "BCON_C", ch);
- }
- break;
- case 17:
- /* 0x;BCON_I */
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BCON_C",
- card->rch[ch - 1] + 1);
- }
- break;
- case 2:
- /* 0x;BDIS_R */
- isdnloop_fake(card, "BDIS_C", ch);
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
- card->rch[ch - 1] + 1);
- }
- break;
- case 16:
- /* 0x;DCON_R */
- isdnloop_kill_ctimer(card, ch - 1);
- if (card->rcard[ch - 1]) {
- isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
- isdnloop_fake(card->rcard[ch - 1], "DCON_C",
- card->rch[ch - 1] + 1);
- isdnloop_fake(card, "DCON_C", ch);
- }
- break;
- case 3:
- /* 0x;DDIS_R */
- isdnloop_kill_ctimer(card, ch - 1);
- if (card->rcard[ch - 1]) {
- isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
- isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
- card->rch[ch - 1] + 1);
- card->rcard[ch - 1] = NULL;
- }
- isdnloop_fake(card, "DDIS_C", ch);
- break;
- case 4:
- /* 0x;DSCA_Rdd,yy,zz,oo */
- if (card->ptype != ISDN_PTYPE_1TR6) {
- isdnloop_fake_err(card);
- return;
- }
- /* Fall through */
- case 5:
- /* 0x;DCAL_Rdd,yy,zz,oo */
- p += 6;
- switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
- case 0:
- /* Alerting */
- sprintf(buf, "D%s_I%s,%02d,%02d,%s",
- (action == 4) ? "SCA" : "CAL",
- isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- isdnloop_vstphone(card->rcard[ch - 1],
- cmd.parm.setup.phone, 0));
- isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
- /* Fall through */
- case 3:
- /* si1 does not match, don't alert but start timer */
- isdnloop_start_ctimer(card, ch - 1);
- break;
- case 1:
- /* Remote busy */
- isdnloop_fake(card, "DDIS_I", ch);
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
- isdnloop_fake(card, buf, ch);
- break;
- case 2:
- /* No such user */
- isdnloop_fake(card, "DDIS_I", ch);
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
- isdnloop_fake(card, buf, ch);
- break;
- }
- break;
- case 6:
- /* 0x;EAZC */
- card->eazlist[ch - 1][0] = '\0';
- break;
- case 7:
- /* 0x;EAZ */
- p += 3;
- if (strlen(p) >= sizeof(card->eazlist[0]))
- break;
- strcpy(card->eazlist[ch - 1], p);
- break;
- case 8:
- /* 0x;SEEAZ */
- sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
- isdnloop_fake(card, buf, ch + 1);
- break;
- case 9:
- /* 0x;MSN */
- break;
- case 10:
- /* 0x;MSNALL */
- break;
- case 11:
- /* 0x;SETSIL */
- p += 6;
- i = 0;
- while (strchr("0157", *p)) {
- if (i)
- card->sil[ch - 1] |= si2bit[*p - '0'];
- i = (*p++ == '0');
- }
- if (*p)
- isdnloop_fake_err(card);
- break;
- case 12:
- /* 0x;SEESIL */
- sprintf(buf, "SIN-LIST: ");
- p = buf + 10;
- for (i = 0; i < 3; i++)
- if (card->sil[ch - 1] & (1 << i))
- p += sprintf(p, "%02d", bit2si[i]);
- isdnloop_fake(card, buf, ch + 1);
- break;
- case 13:
- /* 0x;SILC */
- card->sil[ch - 1] = 0;
- break;
- case 14:
- /* 00;FV2ON */
- break;
- case 15:
- /* 00;FV2OFF */
- break;
- }
-}
-
-/*
- * Put command-strings into the of the 'card'. In reality, execute them
- * right in place by calling isdnloop_parse_cmd(). Also copy every
- * command to the read message ringbuffer, preceding it with a '>'.
- * These mesagges can be read at /dev/isdnctrl.
- *
- * Parameter:
- * buf = pointer to command buffer.
- * len = length of buffer data.
- * user = flag: 1 = called form userlevel, 0 called from kernel.
- * card = pointer to card struct.
- * Return:
- * number of bytes transferred (currently always equals len).
- */
-static int
-isdnloop_writecmd(const u_char *buf, int len, int user, isdnloop_card *card)
-{
- int xcount = 0;
- int ocount = 1;
- isdn_ctrl cmd;
-
- while (len) {
- int count = len;
- u_char *p;
- u_char msg[0x100];
-
- if (count > 255)
- count = 255;
- if (user) {
- if (copy_from_user(msg, buf, count))
- return -EFAULT;
- } else
- memcpy(msg, buf, count);
- isdnloop_putmsg(card, '>');
- for (p = msg; count > 0; count--, p++) {
- len--;
- xcount++;
- isdnloop_putmsg(card, *p);
- card->omsg[card->optr] = *p;
- if (*p == '\n') {
- card->omsg[card->optr] = '\0';
- card->optr = 0;
- isdnloop_parse_cmd(card);
- if (len) {
- isdnloop_putmsg(card, '>');
- ocount++;
- }
- } else {
- if (card->optr < 59)
- card->optr++;
- }
- ocount++;
- }
- }
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- return xcount;
-}
-
-/*
- * Delete card's pending timers, send STOP to linklevel
- */
-static void
-isdnloop_stopcard(isdnloop_card *card)
-{
- unsigned long flags;
- isdn_ctrl cmd;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
- card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
- del_timer(&card->st_timer);
- del_timer(&card->rb_timer);
- del_timer(&card->c_timer[0]);
- del_timer(&card->c_timer[1]);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- }
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Stop all cards before unload.
- */
-static void
-isdnloop_stopallcards(void)
-{
- isdnloop_card *p = cards;
-
- while (p) {
- isdnloop_stopcard(p);
- p = p->next;
- }
-}
-
-/*
- * Start a 'card'. Simulate card's boot message and set the phone
- * number(s) of the virtual 'S0-Interface'. Install D-channel
- * poll timer.
- *
- * Parameter:
- * card = pointer to card struct.
- * sdefp = pointer to struct holding ioctl parameters.
- * Return:
- * 0 on success, -E??? otherwise.
- */
-static int
-isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
-{
- unsigned long flags;
- isdnloop_sdef sdef;
- int i;
-
- if (card->flags & ISDNLOOP_FLAGS_RUNNING)
- return -EBUSY;
- if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
- return -EFAULT;
-
- for (i = 0; i < 3; i++) {
- if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i])))
- return -EINVAL;
- }
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- switch (sdef.ptype) {
- case ISDN_PTYPE_EURO:
- if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
- -1)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- card->sil[0] = card->sil[1] = 4;
- if (isdnloop_fake(card, "TEI OK", 0)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- for (i = 0; i < 3; i++) {
- strlcpy(card->s0num[i], sdef.num[i],
- sizeof(card->s0num[0]));
- }
- break;
- case ISDN_PTYPE_1TR6:
- if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
- -1)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- card->sil[0] = card->sil[1] = 4;
- if (isdnloop_fake(card, "TEI OK", 0)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0]));
- card->s0num[1][0] = '\0';
- card->s0num[2][0] = '\0';
- break;
- default:
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
- sdef.ptype);
- return -EINVAL;
- }
- timer_setup(&card->rb_timer, isdnloop_pollbchan, 0);
- timer_setup(&card->st_timer, isdnloop_polldchan, 0);
- card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
- add_timer(&card->st_timer);
- card->flags |= ISDNLOOP_FLAGS_RUNNING;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 0;
-}
-
-/*
- * Main handler for commands sent by linklevel.
- */
-static int
-isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
-{
- ulong a;
- int i;
- char cbuf[80];
- isdn_ctrl cmd;
- isdnloop_cdef cdef;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->parm.num, sizeof(ulong));
- switch (c->arg) {
- case ISDNLOOP_IOCTL_DEBUGVAR:
- return (ulong) card;
- case ISDNLOOP_IOCTL_STARTUP:
- return isdnloop_start(card, (isdnloop_sdef *) a);
- break;
- case ISDNLOOP_IOCTL_ADDCARD:
- if (copy_from_user((char *)&cdef,
- (char *)a,
- sizeof(cdef)))
- return -EFAULT;
- return isdnloop_addcard(cdef.id1);
- break;
- case ISDNLOOP_IOCTL_LEASEDCFG:
- if (a) {
- if (!card->leased) {
- card->leased = 1;
- while (card->ptype == ISDN_PTYPE_UNKNOWN)
- schedule_timeout_interruptible(10);
- schedule_timeout_interruptible(10);
- sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "isdnloop: (%s) Leased-line mode enabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- } else {
- if (card->leased) {
- card->leased = 0;
- sprintf(cbuf, "00;FV2OFF\n");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "isdnloop: (%s) Leased-line mode disabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- }
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if ((c->arg & 255) < ISDNLOOP_BCH) {
- char *p;
- char dcode[4];
-
- a = c->arg;
- p = c->parm.setup.phone;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- snprintf(cbuf, sizeof(cbuf),
- "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
- dcode, p, c->parm.setup.si1,
- c->parm.setup.si2, c->parm.setup.eazmsn);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTD:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- cbuf[0] = 0;
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) a);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BX2T\n", (int) a);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BX2C\n", (int) a);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) a);
- break;
- }
- if (strlen(cbuf))
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTB:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
- break;
- default:
- sprintf(cbuf, "%02d;BCON_R\n", (int) a);
- }
- printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- break;
- case ISDN_CMD_HANGUP:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETEAZ:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO) {
- sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
- c->parm.num[0] ? "N" : "ALL", c->parm.num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
- c->parm.num[0] ? c->parm.num : (u_char *) "0123456789");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_CLREAZ:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO)
- sprintf(cbuf, "%02d;MSNC\n", (int) a);
- else
- sprintf(cbuf, "%02d;EAZC\n", (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETL2:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if ((c->arg & 255) < ISDNLOOP_BCH) {
- a = c->arg;
- switch (a >> 8) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_TRANS:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- default:
- return -EINVAL;
- }
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- card->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_SETL3:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- default:
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/*
- * Find card with given driverId
- */
-static inline isdnloop_card *
-isdnloop_findcard(int driverid)
-{
- isdnloop_card *p = cards;
-
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (isdnloop_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
- isdnloop_card *card = isdnloop_findcard(c->driver);
-
- if (card)
- return isdnloop_command(c, card);
- printk(KERN_ERR
- "isdnloop: if_command called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return isdnloop_writecmd(buf, len, 1, card);
- }
- printk(KERN_ERR
- "isdnloop: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return isdnloop_readstatus(buf, len, card);
- }
- printk(KERN_ERR
- "isdnloop: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- /* ack request stored in skb scratch area */
- *(skb->head) = ack;
- return isdnloop_sendbuf(channel, skb, card);
- }
- printk(KERN_ERR
- "isdnloop: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
-}
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list and register it at linklevel.
- */
-static isdnloop_card *
-isdnloop_initcard(char *id)
-{
- isdnloop_card *card;
- int i;
- card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL);
- if (!card) {
- printk(KERN_WARNING
- "isdnloop: (%s) Could not allocate card-struct.\n", id);
- return (isdnloop_card *) 0;
- }
- card->interface.owner = THIS_MODULE;
- card->interface.channels = ISDNLOOP_BCH;
- card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = if_writecmd;
- card->interface.readstat = if_readstatus;
- card->interface.features = ISDN_FEATURE_L2_X75I |
-#ifdef CONFIG_ISDN_X25
- ISDN_FEATURE_L2_X25DTE |
- ISDN_FEATURE_L2_X25DCE |
-#endif
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- card->ptype = ISDN_PTYPE_UNKNOWN;
- strlcpy(card->interface.id, id, sizeof(card->interface.id));
- card->msg_buf_write = card->msg_buf;
- card->msg_buf_read = card->msg_buf;
- card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
- for (i = 0; i < ISDNLOOP_BCH; i++) {
- card->l2_proto[i] = ISDN_PROTO_L2_X75I;
- skb_queue_head_init(&card->bqueue[i]);
- }
- skb_queue_head_init(&card->dqueue);
- spin_lock_init(&card->isdnloop_lock);
- card->next = cards;
- cards = card;
- if (!register_isdn(&card->interface)) {
- cards = cards->next;
- printk(KERN_WARNING
- "isdnloop: Unable to register %s\n", id);
- kfree(card);
- return (isdnloop_card *) 0;
- }
- card->myid = card->interface.channels;
- return card;
-}
-
-static int
-isdnloop_addcard(char *id1)
-{
- isdnloop_card *card;
- card = isdnloop_initcard(id1);
- if (!card) {
- return -EIO;
- }
- printk(KERN_INFO
- "isdnloop: (%s) virtual card added\n",
- card->interface.id);
- return 0;
-}
-
-static int __init
-isdnloop_init(void)
-{
- if (isdnloop_id)
- return isdnloop_addcard(isdnloop_id);
-
- return 0;
-}
-
-static void __exit
-isdnloop_exit(void)
-{
- isdn_ctrl cmd;
- isdnloop_card *card = cards;
- isdnloop_card *last;
- int i;
-
- isdnloop_stopallcards();
- while (card) {
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- for (i = 0; i < ISDNLOOP_BCH; i++)
- isdnloop_free_queue(card, i);
- card = card->next;
- }
- card = cards;
- while (card) {
- last = card;
- skb_queue_purge(&card->dqueue);
- card = card->next;
- kfree(last);
- }
- printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
-}
-
-module_init(isdnloop_init);
-module_exit(isdnloop_exit);
+++ /dev/null
-/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $
- *
- * Loopback lowlevel module for testing of linklevel.
- *
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef isdnloop_h
-#define isdnloop_h
-
-#define ISDNLOOP_IOCTL_DEBUGVAR 0
-#define ISDNLOOP_IOCTL_ADDCARD 1
-#define ISDNLOOP_IOCTL_LEASEDCFG 2
-#define ISDNLOOP_IOCTL_STARTUP 3
-
-/* Struct for adding new cards */
-typedef struct isdnloop_cdef {
- char id1[10];
-} isdnloop_cdef;
-
-/* Struct for configuring cards */
-typedef struct isdnloop_sdef {
- int ptype;
- char num[3][20];
-} isdnloop_sdef;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-
-#endif /* __KERNEL__ */
-
-#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
-#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
-#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */
-#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */
-#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */
-#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
-#define ISDNLOOP_TIMER_ALERTWAIT (10 * HZ) /* Alert timeout */
-#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */
-#define ISDNLOOP_BCH 2 /* channels per card */
-
-/*
- * Per card driver data
- */
-typedef struct isdnloop_card {
- struct isdnloop_card *next; /* Pointer to next device struct */
- struct isdnloop_card
- *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */
- int rch[ISDNLOOP_BCH]; /* 'remote' channel */
- int myid; /* Driver-Nr. assigned by linklevel */
- int leased; /* Flag: This Adapter is connected */
- /* to a leased line */
- int sil[ISDNLOOP_BCH]; /* SI's to listen for */
- char eazlist[ISDNLOOP_BCH][11];
- /* EAZ's to listen for */
- char s0num[3][20]; /* 1TR6 base-number or MSN's */
- unsigned short flags; /* Statusflags */
- int ptype; /* Protocol type (1TR6 or Euro) */
- struct timer_list st_timer; /* Timer for Status-Polls */
- struct timer_list rb_timer; /* Timer for B-Channel-Polls */
- struct timer_list
- c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */
- int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */
- isdn_if interface; /* Interface to upper layer */
- int iptr; /* Index to imsg-buffer */
- char imsg[60]; /* Internal buf for status-parsing */
- int optr; /* Index to omsg-buffer */
- char omsg[60]; /* Internal buf for cmd-parsing */
- char msg_buf[2048]; /* Buffer for status-messages */
- char *msg_buf_write; /* Writepointer for statusbuffer */
- char *msg_buf_read; /* Readpointer for statusbuffer */
- char *msg_buf_end; /* Pointer to end of statusbuffer */
- int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */
- struct sk_buff_head
- bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
- struct sk_buff_head dqueue; /* D-Channel queue */
- spinlock_t isdnloop_lock;
-} isdnloop_card;
-
-/*
- * Main driver data
- */
-#ifdef __KERNEL__
-static isdnloop_card *cards = (isdnloop_card *) 0;
-#endif /* __KERNEL__ */
-
-/* Utility-Macros */
-
-#define CID (card->interface.id)
-
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* isdnloop_h */
+++ /dev/null
-/* $Id: concap.h,v 1.3.2.2 2004/01/12 23:08:35 keil Exp $
- *
- * Copyright 1997 by Henner Eisen <eis@baty.hanse.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef _LINUX_CONCAP_H
-#define _LINUX_CONCAP_H
-
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-/* Stuff to support encapsulation protocols genericly. The encapsulation
- protocol is processed at the uppermost layer of the network interface.
-
- Based on a ideas developed in a 'synchronous device' thread in the
- linux-x25 mailing list contributed by Alan Cox, Thomasz Motylewski
- and Jonathan Naylor.
-
- For more documetation on this refer to Documentation/isdn/README.concap
-*/
-
-struct concap_proto_ops;
-struct concap_device_ops;
-
-/* this manages all data needed by the encapsulation protocol
- */
-struct concap_proto{
- struct net_device *net_dev; /* net device using our service */
- struct concap_device_ops *dops; /* callbacks provided by device */
- struct concap_proto_ops *pops; /* callbacks provided by us */
- spinlock_t lock;
- int flags;
- void *proto_data; /* protocol specific private data, to
- be accessed via *pops methods only*/
- /*
- :
- whatever
- :
- */
-};
-
-/* Operations to be supported by the net device. Called by the encapsulation
- * protocol entity. No receive method is offered because the encapsulation
- * protocol directly calls netif_rx().
- */
-struct concap_device_ops{
-
- /* to request data is submitted by device*/
- int (*data_req)(struct concap_proto *, struct sk_buff *);
-
- /* Control methods must be set to NULL by devices which do not
- support connection control.*/
- /* to request a connection is set up */
- int (*connect_req)(struct concap_proto *);
-
- /* to request a connection is released */
- int (*disconn_req)(struct concap_proto *);
-};
-
-/* Operations to be supported by the encapsulation protocol. Called by
- * device driver.
- */
-struct concap_proto_ops{
-
- /* create a new encapsulation protocol instance of same type */
- struct concap_proto * (*proto_new) (void);
-
- /* delete encapsulation protocol instance and free all its resources.
- cprot may no loger be referenced after calling this */
- void (*proto_del)(struct concap_proto *cprot);
-
- /* initialize the protocol's data. To be called at interface startup
- or when the device driver resets the interface. All services of the
- encapsulation protocol may be used after this*/
- int (*restart)(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops);
-
- /* inactivate an encapsulation protocol instance. The encapsulation
- protocol may not call any *dops methods after this. */
- int (*close)(struct concap_proto *cprot);
-
- /* process a frame handed down to us by upper layer */
- int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
-
- /* to be called for each data entity received from lower layer*/
- int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
-
- /* to be called when a connection was set up/down.
- Protocols that don't process these primitives might fill in
- dummy methods here */
- int (*connect_ind)(struct concap_proto *cprot);
- int (*disconn_ind)(struct concap_proto *cprot);
- /*
- Some network device support functions, like net_header(), rebuild_header(),
- and others, that depend solely on the encapsulation protocol, might
- be provided here, too. The net device would just fill them in its
- corresponding fields when it is opened.
- */
-};
-
-/* dummy restart/close/connect/reset/disconn methods
- */
-extern int concap_nop(struct concap_proto *cprot);
-
-/* dummy submit method
- */
-extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb);
-#endif
+++ /dev/null
-/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $
- *
- * Main header for the Linux ISDN subsystem (linklevel).
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#ifndef __ISDN_H__
-#define __ISDN_H__
-
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/fcntl.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/mutex.h>
-#include <uapi/linux/isdn.h>
-
-#define ISDN_TTY_MAJOR 43
-#define ISDN_TTYAUX_MAJOR 44
-#define ISDN_MAJOR 45
-
-/* The minor-devicenumbers for Channel 0 and 1 are used as arguments for
- * physical Channel-Mapping, so they MUST NOT be changed without changing
- * the correspondent code in isdn.c
- */
-
-#define ISDN_MINOR_B 0
-#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1)
-#define ISDN_MINOR_CTRL 64
-#define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1))
-#define ISDN_MINOR_PPP 128
-#define ISDN_MINOR_PPPMAX (128 + (ISDN_MAX_CHANNELS-1))
-#define ISDN_MINOR_STATUS 255
-
-#ifdef CONFIG_ISDN_PPP
-
-#ifdef CONFIG_ISDN_PPP_VJ
-# include <net/slhc_vj.h>
-#endif
-
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-
-#include <linux/isdn_ppp.h>
-#endif
-
-#ifdef CONFIG_ISDN_X25
-# include <linux/concap.h>
-#endif
-
-#include <linux/isdnif.h>
-
-#define ISDN_DRVIOCTL_MASK 0x7f /* Mask for Device-ioctl */
-
-/* Until now unused */
-#define ISDN_SERVICE_VOICE 1
-#define ISDN_SERVICE_AB 1<<1
-#define ISDN_SERVICE_X21 1<<2
-#define ISDN_SERVICE_G4 1<<3
-#define ISDN_SERVICE_BTX 1<<4
-#define ISDN_SERVICE_DFUE 1<<5
-#define ISDN_SERVICE_X25 1<<6
-#define ISDN_SERVICE_TTX 1<<7
-#define ISDN_SERVICE_MIXED 1<<8
-#define ISDN_SERVICE_FW 1<<9
-#define ISDN_SERVICE_GTEL 1<<10
-#define ISDN_SERVICE_BTXN 1<<11
-#define ISDN_SERVICE_BTEL 1<<12
-
-/* Macros checking plain usage */
-#define USG_NONE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE)
-#define USG_RAW(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW)
-#define USG_MODEM(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM)
-#define USG_VOICE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)
-#define USG_NET(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET)
-#define USG_FAX(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_FAX)
-#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING)
-#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \
- ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) )
-
-/* Timer-delays and scheduling-flags */
-#define ISDN_TIMER_RES 4 /* Main Timer-Resolution */
-#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 .2 sec */
-#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 1 sec */
-#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */
-#define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
-#define ISDN_TIMER_MODEMREAD 1
-#define ISDN_TIMER_MODEMPLUS 2
-#define ISDN_TIMER_MODEMRING 4
-#define ISDN_TIMER_MODEMXMIT 8
-#define ISDN_TIMER_NETDIAL 16
-#define ISDN_TIMER_NETHANGUP 32
-#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */
-#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
- ISDN_TIMER_MODEMXMIT)
-#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
- ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER)
-
-/* Timeout-Values for isdn_net_dial() */
-#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
-#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
-#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
-
-/* GLOBAL_FLAGS */
-#define ISDN_GLOBAL_STOPPED 1
-
-/*=================== Start of ip-over-ISDN stuff =========================*/
-
-/* Feature- and status-flags for a net-interface */
-#define ISDN_NET_CONNECTED 0x01 /* Bound to ISDN-Channel */
-#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */
-#define ISDN_NET_CALLBACK 0x04 /* activate callback */
-#define ISDN_NET_CBHUP 0x08 /* hangup before callback */
-#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */
-
-#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
-
-/* Phone-list-element */
-typedef struct {
- void *next;
- char num[ISDN_MSNLEN];
-} isdn_net_phone;
-
-/*
- Principles when extending structures for generic encapsulation protocol
- ("concap") support:
- - Stuff which is hardware specific (here i4l-specific) goes in
- the netdev -> local structure (here: isdn_net_local)
- - Stuff which is encapsulation protocol specific goes in the structure
- which holds the linux device structure (here: isdn_net_device)
-*/
-
-/* Local interface-data */
-typedef struct isdn_net_local_s {
- ulong magic;
- struct net_device_stats stats; /* Ethernet Statistics */
- int isdn_device; /* Index to isdn-device */
- int isdn_channel; /* Index to isdn-channel */
- int ppp_slot; /* PPPD device slot number */
- int pre_device; /* Preselected isdn-device */
- int pre_channel; /* Preselected isdn-channel */
- int exclusive; /* If non-zero idx to reserved chan.*/
- int flags; /* Connection-flags */
- int dialretry; /* Counter for Dialout-retries */
- int dialmax; /* Max. Number of Dial-retries */
- int cbdelay; /* Delay before Callback starts */
- int dtimer; /* Timeout-counter for dialing */
- char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
- u_char cbhup; /* Flag: Reject Call before Callback*/
- u_char dialstate; /* State for dialing */
- u_char p_encap; /* Packet encapsulation */
- /* 0 = Ethernet over ISDN */
- /* 1 = RAW-IP */
- /* 2 = IP with type field */
- u_char l2_proto; /* Layer-2-protocol */
- /* See ISDN_PROTO_L2..-constants in */
- /* isdnif.h */
- /* 0 = X75/LAPB with I-Frames */
- /* 1 = X75/LAPB with UI-Frames */
- /* 2 = X75/LAPB with BUI-Frames */
- /* 3 = HDLC */
- u_char l3_proto; /* Layer-3-protocol */
- /* See ISDN_PROTO_L3..-constants in */
- /* isdnif.h */
- /* 0 = Transparent */
- int huptimer; /* Timeout-counter for auto-hangup */
- int charge; /* Counter for charging units */
- ulong chargetime; /* Timer for Charging info */
- int hupflags; /* Flags for charge-unit-hangup: */
- /* bit0: chargeint is invalid */
- /* bit1: Getting charge-interval */
- /* bit2: Do charge-unit-hangup */
- /* bit3: Do hangup even on incoming */
- int outgoing; /* Flag: outgoing call */
- int onhtime; /* Time to keep link up */
- int chargeint; /* Interval between charge-infos */
- int onum; /* Flag: at least 1 outgoing number */
- int cps; /* current speed of this interface */
- int transcount; /* byte-counter for cps-calculation */
- int sqfull; /* Flag: netdev-queue overloaded */
- ulong sqfull_stamp; /* Start-Time of overload */
- ulong slavedelay; /* Dynamic bundling delaytime */
- int triggercps; /* BogoCPS needed for trigger slave */
- isdn_net_phone *phone[2]; /* List of remote-phonenumbers */
- /* phone[0] = Incoming Numbers */
- /* phone[1] = Outgoing Numbers */
- isdn_net_phone *dial; /* Pointer to dialed number */
- struct net_device *master; /* Ptr to Master device for slaves */
- struct net_device *slave; /* Ptr to Slave device for masters */
- struct isdn_net_local_s *next; /* Ptr to next link in bundle */
- struct isdn_net_local_s *last; /* Ptr to last link in bundle */
- struct isdn_net_dev_s *netdev; /* Ptr to netdev */
- struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
- /* be transmitted asap */
- atomic_t frame_cnt; /* number of frames currently */
- /* queued in HL driver */
- /* Ptr to orig. hard_header_cache */
- spinlock_t xmit_lock; /* used to protect the xmit path of */
- /* a particular channel (including */
- /* the frame_cnt */
-
- int pppbind; /* ippp device for bindings */
- int dialtimeout; /* How long shall we try on dialing? (jiffies) */
- int dialwait; /* How long shall we wait after failed attempt? (jiffies) */
- ulong dialstarted; /* jiffies of first dialing-attempt */
- ulong dialwait_timer; /* jiffies of earliest next dialing-attempt */
- int huptimeout; /* How long will the connection be up? (seconds) */
-#ifdef CONFIG_ISDN_X25
- struct concap_device_ops *dops; /* callbacks used by encapsulator */
-#endif
- /* use an own struct for that in later versions */
- ulong cisco_myseq; /* Local keepalive seq. for Cisco */
- ulong cisco_mineseen; /* returned keepalive seq. from remote */
- ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */
- int cisco_keepalive_period; /* keepalive period */
- ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */
- char cisco_line_state; /* state of line according to keepalive packets */
- char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
- struct timer_list cisco_timer;
- struct work_struct tqueue;
-} isdn_net_local;
-
-/* the interface itself */
-typedef struct isdn_net_dev_s {
- isdn_net_local *local;
- isdn_net_local *queue; /* circular list of all bundled
- channels, which are currently
- online */
- spinlock_t queue_lock; /* lock to protect queue */
- void *next; /* Pointer to next isdn-interface */
- struct net_device *dev; /* interface to upper levels */
-#ifdef CONFIG_ISDN_PPP
- ippp_bundle * pb; /* pointer to the common bundle structure
- * with the per-bundle data */
-#endif
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot; /* connection oriented encapsulation protocol */
-#endif
-
-} isdn_net_dev;
-
-/*===================== End of ip-over-ISDN stuff ===========================*/
-
-/*======================= Start of ISDN-tty stuff ===========================*/
-
-#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
-#define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */
-#define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
-
-#ifdef CONFIG_ISDN_AUDIO
-/* For using sk_buffs with audio we need some private variables
- * within each sk_buff. For this purpose, we declare a struct here,
- * and put it always at the private skb->cb data array. A few macros help
- * accessing the variables.
- */
-typedef struct _isdn_audio_data {
- unsigned short dle_count;
- unsigned char lock;
-} isdn_audio_data_t;
-
-#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_data_t *)&skb->cb[0])->dle_count)
-#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_data_t *)&skb->cb[0])->lock)
-#endif
-
-/* Private data of AT-command-interpreter */
-typedef struct atemu {
- u_char profile[ISDN_MODEM_NUMREG]; /* Modem-Regs. Profile 0 */
- u_char mdmreg[ISDN_MODEM_NUMREG]; /* Modem-Registers */
- char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */
- char msn[ISDN_MSNLEN]; /* EAZ/MSN */
- char plmsn[ISDN_LMSNLEN]; /* Listening MSNs Profile 0 */
- char lmsn[ISDN_LMSNLEN]; /* Listening MSNs */
- char cpn[ISDN_MSNLEN]; /* CalledPartyNumber on incoming call */
- char connmsg[ISDN_CMSGLEN]; /* CONNECT-Msg from HL-Driver */
-#ifdef CONFIG_ISDN_AUDIO
- u_char vpar[10]; /* Voice-parameters */
- int lastDLE; /* Flag for voice-coding: DLE seen */
-#endif
- int mdmcmdl; /* Length of Modem-Commandbuffer */
- int pluscount; /* Counter for +++ sequence */
- u_long lastplus; /* Timestamp of last + */
- int carrierwait; /* Seconds of carrier waiting */
- char mdmcmd[255]; /* Modem-Commandbuffer */
- unsigned int charge; /* Charge units of current connection */
-} atemu;
-
-/* Private data (similar to async_struct in <linux/serial.h>) */
-typedef struct modem_info {
- int magic;
- struct tty_port port;
- int x_char; /* xon/xoff character */
- int mcr; /* Modem control register */
- int msr; /* Modem status register */
- int lsr; /* Line status register */
- int line;
- int online; /* 1 = B-Channel is up, drop data */
- /* 2 = B-Channel is up, deliver d.*/
- int dialing; /* Dial in progress or ATA */
- int closing;
- int rcvsched; /* Receive needs schedule */
- int isdn_driver; /* Index to isdn-driver */
- int isdn_channel; /* Index to isdn-channel */
- int drv_index; /* Index to dev->usage */
- int ncarrier; /* Flag: schedule NO CARRIER */
- unsigned char last_cause[8]; /* Last cause message */
- unsigned char last_num[ISDN_MSNLEN];
- /* Last phone-number */
- unsigned char last_l2; /* Last layer-2 protocol */
- unsigned char last_si; /* Last service */
- unsigned char last_lhup; /* Last hangup local? */
- unsigned char last_dir; /* Last direction (in or out) */
- struct timer_list nc_timer; /* Timer for delayed NO CARRIER */
- int send_outstanding;/* # of outstanding send-requests */
- int xmit_size; /* max. # of chars in xmit_buf */
- int xmit_count; /* # of chars in xmit_buf */
- struct sk_buff_head xmit_queue; /* transmit queue */
- atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
-#ifdef CONFIG_ISDN_AUDIO
- int vonline; /* Voice-channel status */
- /* Bit 0 = recording */
- /* Bit 1 = playback */
- /* Bit 2 = playback, DLE-ETX seen */
- struct sk_buff_head dtmf_queue; /* queue for dtmf results */
- void *adpcms; /* state for adpcm decompression */
- void *adpcmr; /* state for adpcm compression */
- void *dtmf_state; /* state for dtmf decoder */
- void *silence_state; /* state for silence detection */
-#endif
-#ifdef CONFIG_ISDN_TTY_FAX
- struct T30_s *fax; /* T30 Fax Group 3 data/interface */
- int faxonline; /* Fax-channel status */
-#endif
- atemu emu; /* AT-emulator data */
- spinlock_t readlock;
-} modem_info;
-
-#define ISDN_MODEM_WINSIZE 8
-
-/* Description of one ISDN-tty */
-typedef struct _isdn_modem {
- int refcount; /* Number of opens */
- struct tty_driver *tty_modem; /* tty-device */
- struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
- struct ktermios *modem_termios[ISDN_MAX_CHANNELS];
- struct ktermios *modem_termios_locked[ISDN_MAX_CHANNELS];
- modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
-} isdn_modem_t;
-
-/*======================= End of ISDN-tty stuff ============================*/
-
-/*======================== Start of V.110 stuff ============================*/
-#define V110_BUFSIZE 1024
-
-typedef struct {
- int nbytes; /* 1 Matrixbyte -> nbytes in stream */
- int nbits; /* Number of used bits in streambyte */
- unsigned char key; /* Bitmask in stream eg. 11 (nbits=2) */
- int decodelen; /* Amount of data in decodebuf */
- int SyncInit; /* Number of sync frames to send */
- unsigned char *OnlineFrame; /* Precalculated V110 idle frame */
- unsigned char *OfflineFrame; /* Precalculated V110 sync Frame */
- int framelen; /* Length of frames */
- int skbuser; /* Number of unacked userdata skbs */
- int skbidle; /* Number of unacked idle/sync skbs */
- int introducer; /* Local vars for decoder */
- int dbit;
- unsigned char b;
- int skbres; /* space to reserve in outgoing skb */
- int maxsize; /* maxbufsize of lowlevel driver */
- unsigned char *encodebuf; /* temporary buffer for encoding */
- unsigned char decodebuf[V110_BUFSIZE]; /* incomplete V110 matrices */
-} isdn_v110_stream;
-
-/*========================= End of V.110 stuff =============================*/
-
-/*======================= Start of general stuff ===========================*/
-
-typedef struct {
- char *next;
- char *private;
-} infostruct;
-
-#define DRV_FLAG_RUNNING 1
-#define DRV_FLAG_REJBUS 2
-#define DRV_FLAG_LOADED 4
-
-/* Description of hardware-level-driver */
-typedef struct _isdn_driver {
- ulong online; /* Channel-Online flags */
- ulong flags; /* Misc driver Flags */
- int locks; /* Number of locks for this driver */
- int channels; /* Number of channels */
- wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */
- int maxbufsize; /* Maximum Buffersize supported */
- unsigned long pktcount; /* Until now: unused */
- int stavail; /* Chars avail on Status-device */
- isdn_if *interface; /* Interface to driver */
- int *rcverr; /* Error-counters for B-Ch.-receive */
- int *rcvcount; /* Byte-counters for B-Ch.-receive */
-#ifdef CONFIG_ISDN_AUDIO
- unsigned long DLEflag; /* Flags: Insert DLE at next read */
-#endif
- struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */
- wait_queue_head_t *rcv_waitq; /* Wait-Queues for B-Channel-Reads */
- wait_queue_head_t *snd_waitq; /* Wait-Queue for B-Channel-Send's */
- char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */
-} isdn_driver_t;
-
-/* Main driver-data */
-typedef struct isdn_devt {
- struct module *owner;
- spinlock_t lock;
- unsigned short flags; /* Bitmapped Flags: */
- int drivers; /* Current number of drivers */
- int channels; /* Current number of channels */
- int net_verbose; /* Verbose-Flag */
- int modempoll; /* Flag: tty-read active */
- spinlock_t timerlock;
- int tflags; /* Timer-Flags: */
- /* see ISDN_TIMER_..defines */
- int global_flags;
- infostruct *infochain; /* List of open info-devs. */
- wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */
- struct timer_list timer; /* Misc.-function Timer */
- int chanmap[ISDN_MAX_CHANNELS]; /* Map minor->device-channel */
- int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */
- int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */
- char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
- /* Remote number of active ch.*/
- int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */
- isdn_driver_t *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */
- isdn_net_dev *netdev; /* Linked list of net-if's */
- char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */
- struct task_struct *profd; /* For iprofd */
- isdn_modem_t mdm; /* tty-driver-data */
- isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */
- isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */
- ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */
- ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */
- int v110emu[ISDN_MAX_CHANNELS]; /* V.110 emulator-mode 0=none */
- atomic_t v110use[ISDN_MAX_CHANNELS]; /* Usage-Semaphore for stream */
- isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */
- struct mutex mtx; /* serialize list access*/
- unsigned long global_features;
-} isdn_dev;
-
-extern isdn_dev *dev;
-
-
-#endif /* __ISDN_H__ */
+++ /dev/null
-/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $
- *
- * Header for the diversion supplementary interface for i4l.
- *
- * Author Werner Cornelius (werner@titro.de)
- * Copyright by Werner Cornelius (werner@titro.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#ifndef _LINUX_ISDN_DIVERTIF_H
-#define _LINUX_ISDN_DIVERTIF_H
-
-#include <linux/isdnif.h>
-#include <linux/types.h>
-#include <uapi/linux/isdn_divertif.h>
-
-/***************************************************************/
-/* structure exchanging data between isdn hl and divert module */
-/***************************************************************/
-typedef struct
- { ulong if_magic; /* magic info and version */
- int cmd; /* command */
- int (*stat_callback)(isdn_ctrl *); /* supplied by divert module when calling */
- int (*ll_cmd)(isdn_ctrl *); /* supplied by hl on return */
- char * (*drv_to_name)(int); /* map a driver id to name, supplied by hl */
- int (*name_to_drv)(char *); /* map a driver id to name, supplied by hl */
- } isdn_divert_if;
-
-/*********************/
-/* function register */
-/*********************/
-extern int DIVERT_REG_NAME(isdn_divert_if *);
-#endif /* _LINUX_ISDN_DIVERTIF_H */
+++ /dev/null
-/* Linux ISDN subsystem, sync PPP, interface to ipppd
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#ifndef _LINUX_ISDN_PPP_H
-#define _LINUX_ISDN_PPP_H
-
-
-
-
-#ifdef CONFIG_IPPP_FILTER
-#include <linux/filter.h>
-#endif
-#include <uapi/linux/isdn_ppp.h>
-
-#define DECOMP_ERR_NOMEM (-10)
-
-#define MP_END_FRAG 0x40
-#define MP_BEGIN_FRAG 0x80
-
-#define MP_MAX_QUEUE_LEN 16
-
-/*
- * We need a way for the decompressor to influence the generation of CCP
- * Reset-Requests in a variety of ways. The decompressor is already returning
- * a lot of information (generated skb length, error conditions) so we use
- * another parameter. This parameter is a pointer to a structure which is
- * to be marked valid by the decompressor and only in this case is ever used.
- * Furthermore, the only case where this data is used is when the decom-
- * pressor returns DECOMP_ERROR.
- *
- * We use this same struct for the reset entry of the compressor to commu-
- * nicate to its caller how to deal with sending of a Reset Ack. In this
- * case, expra is not used, but other options still apply (suppressing
- * sending with rsend, appending arbitrary data, etc).
- */
-
-#define IPPP_RESET_MAXDATABYTES 32
-
-struct isdn_ppp_resetparams {
- unsigned char valid:1; /* rw Is this structure filled at all ? */
- unsigned char rsend:1; /* rw Should we send one at all ? */
- unsigned char idval:1; /* rw Is the id field valid ? */
- unsigned char dtval:1; /* rw Is the data field valid ? */
- unsigned char expra:1; /* rw Is an Ack expected for this Req ? */
- unsigned char id; /* wo Send CCP ResetReq with this id */
- unsigned short maxdlen; /* ro Max bytes to be stored in data field */
- unsigned short dlen; /* rw Bytes stored in data field */
- unsigned char *data; /* wo Data for ResetReq info field */
-};
-
-/*
- * this is an 'old friend' from ppp-comp.h under a new name
- * check the original include for more information
- */
-struct isdn_ppp_compressor {
- struct isdn_ppp_compressor *next, *prev;
- struct module *owner;
- int num; /* CCP compression protocol number */
-
- void *(*alloc) (struct isdn_ppp_comp_data *);
- void (*free) (void *state);
- int (*init) (void *state, struct isdn_ppp_comp_data *,
- int unit,int debug);
-
- /* The reset entry needs to get more exact information about the
- ResetReq or ResetAck it was called with. The parameters are
- obvious. If reset is called without a Req or Ack frame which
- could be handed into it, code MUST be set to 0. Using rsparm,
- the reset entry can control if and how a ResetAck is returned. */
-
- void (*reset) (void *state, unsigned char code, unsigned char id,
- unsigned char *data, unsigned len,
- struct isdn_ppp_resetparams *rsparm);
-
- int (*compress) (void *state, struct sk_buff *in,
- struct sk_buff *skb_out, int proto);
-
- int (*decompress) (void *state,struct sk_buff *in,
- struct sk_buff *skb_out,
- struct isdn_ppp_resetparams *rsparm);
-
- void (*incomp) (void *state, struct sk_buff *in,int proto);
- void (*stat) (void *state, struct compstat *stats);
-};
-
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
-extern int isdn_ppp_dial_slave(char *);
-extern int isdn_ppp_hangup_slave(char *);
-
-typedef struct {
- unsigned long seqerrs;
- unsigned long frame_drops;
- unsigned long overflows;
- unsigned long max_queue_len;
-} isdn_mppp_stats;
-
-typedef struct {
- int mp_mrru; /* unused */
- struct sk_buff * frags; /* fragments sl list -- use skb->next */
- long frames; /* number of frames in the frame list */
- unsigned int seq; /* last processed packet seq #: any packets
- * with smaller seq # will be dropped
- * unconditionally */
- spinlock_t lock;
- int ref_ct;
- /* statistics */
- isdn_mppp_stats stats;
-} ippp_bundle;
-
-#define NUM_RCV_BUFFS 64
-
-struct ippp_buf_queue {
- struct ippp_buf_queue *next;
- struct ippp_buf_queue *last;
- char *buf; /* NULL here indicates end of queue */
- int len;
-};
-
-/* The data structure for one CCP reset transaction */
-enum ippp_ccp_reset_states {
- CCPResetIdle,
- CCPResetSentReq,
- CCPResetRcvdReq,
- CCPResetSentAck,
- CCPResetRcvdAck
-};
-
-struct ippp_ccp_reset_state {
- enum ippp_ccp_reset_states state; /* State of this transaction */
- struct ippp_struct *is; /* Backlink to device stuff */
- unsigned char id; /* Backlink id index */
- unsigned char ta:1; /* The timer is active (flag) */
- unsigned char expra:1; /* We expect a ResetAck at all */
- int dlen; /* Databytes stored in data */
- struct timer_list timer; /* For timeouts/retries */
- /* This is a hack but seems sufficient for the moment. We do not want
- to have this be yet another allocation for some bytes, it is more
- memory management overhead than the whole mess is worth. */
- unsigned char data[IPPP_RESET_MAXDATABYTES];
-};
-
-/* The data structure keeping track of the currently outstanding CCP Reset
- transactions. */
-struct ippp_ccp_reset {
- struct ippp_ccp_reset_state *rs[256]; /* One per possible id */
- unsigned char lastid; /* Last id allocated by the engine */
-};
-
-struct ippp_struct {
- struct ippp_struct *next_link;
- int state;
- spinlock_t buflock;
- struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
- struct ippp_buf_queue *first; /* pointer to (current) first packet */
- struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */
- wait_queue_head_t wq;
- struct task_struct *tk;
- unsigned int mpppcfg;
- unsigned int pppcfg;
- unsigned int mru;
- unsigned int mpmru;
- unsigned int mpmtu;
- unsigned int maxcid;
- struct isdn_net_local_s *lp;
- int unit;
- int minor;
- unsigned int last_link_seqno;
- long mp_seqno;
-#ifdef CONFIG_ISDN_PPP_VJ
- unsigned char *cbuf;
- struct slcompress *slcomp;
-#endif
-#ifdef CONFIG_IPPP_FILTER
- struct bpf_prog *pass_filter; /* filter for packets to pass */
- struct bpf_prog *active_filter; /* filter for pkts to reset idle */
-#endif
- unsigned long debug;
- struct isdn_ppp_compressor *compressor,*decompressor;
- struct isdn_ppp_compressor *link_compressor,*link_decompressor;
- void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
- struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */
- unsigned long compflags;
-};
-
-#endif /* _LINUX_ISDN_PPP_H */
+++ /dev/null
-/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $
- *
- * Linux ISDN subsystem
- * Definition of the interface between the subsystem and its low-level drivers.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#ifndef __ISDNIF_H__
-#define __ISDNIF_H__
-
-
-#include <linux/skbuff.h>
-#include <uapi/linux/isdnif.h>
-
-/***************************************************************************/
-/* Extensions made by Werner Cornelius (werner@ikt.de) */
-/* */
-/* The proceed command holds a incoming call in a state to leave processes */
-/* enough time to check whether ist should be accepted. */
-/* The PROT_IO Command extends the interface to make protocol dependent */
-/* features available (call diversion, call waiting...). */
-/* */
-/* The PROT_IO Command is executed with the desired driver id and the arg */
-/* parameter coded as follows: */
-/* The lower 8 bits of arg contain the desired protocol from ISDN_PTYPE */
-/* definitions. The upper 24 bits represent the protocol specific cmd/stat.*/
-/* Any additional data is protocol and command specific. */
-/* This mechanism also applies to the statcallb callback STAT_PROT. */
-/* */
-/* This suggested extension permits an easy expansion of protocol specific */
-/* handling. Extensions may be added at any time without changing the HL */
-/* driver code and not getting conflicts without certifications. */
-/* The well known CAPI 2.0 interface handles such extensions in a similar */
-/* way. Perhaps a protocol specific module may be added and separately */
-/* loaded and linked to the basic isdn module for handling. */
-/***************************************************************************/
-
-/*****************/
-/* DSS1 commands */
-/*****************/
-#define DSS1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_EURO) /* invoke a supplementary service */
-#define DSS1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_EURO) /* abort a invoke cmd */
-
-/*******************************/
-/* DSS1 Status callback values */
-/*******************************/
-#define DSS1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_EURO) /* Result for invocation */
-#define DSS1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_EURO) /* Error Return for invocation */
-#define DSS1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_EURO) /* Deliver invoke broadcast info */
-
-
-/*********************************************************************/
-/* structures for DSS1 commands and callback */
-/* */
-/* An action is invoked by sending a DSS1_CMD_INVOKE. The ll_id, proc*/
-/* timeout, datalen and data fields must be set before calling. */
-/* */
-/* The return value is a positive hl_id value also delivered in the */
-/* hl_id field. A value of zero signals no more left hl_id capacitys.*/
-/* A negative return value signals errors in LL. So if the return */
-/* value is <= 0 no action in LL will be taken -> request ignored */
-/* */
-/* The timeout field must be filled with a positive value specifying */
-/* the amount of time the INVOKED process waits for a reaction from */
-/* the network. */
-/* If a response (either error or result) is received during this */
-/* intervall, a reporting callback is initiated and the process will */
-/* be deleted, the hl identifier will be freed. */
-/* If no response is received during the specified intervall, a error*/
-/* callback is initiated with timeout set to -1 and a datalen set */
-/* to 0. */
-/* If timeout is set to a value <= 0 during INVOCATION the process is*/
-/* immediately deleted after sending the data. No callback occurs ! */
-/* */
-/* A currently waiting process may be aborted with INVOKE_ABORT. No */
-/* callback will occur when a process has been aborted. */
-/* */
-/* Broadcast invoke frames from the network are reported via the */
-/* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */
-/* are supplied by the network and not by the HL. */
-/*********************************************************************/
-
-/*****************/
-/* NI1 commands */
-/*****************/
-#define NI1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_NI1) /* invoke a supplementary service */
-#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1) /* abort a invoke cmd */
-
-/*******************************/
-/* NI1 Status callback values */
-/*******************************/
-#define NI1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_NI1) /* Result for invocation */
-#define NI1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_NI1) /* Error Return for invocation */
-#define NI1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_NI1) /* Deliver invoke broadcast info */
-
-typedef struct
- { ulong ll_id; /* ID supplied by LL when executing */
- /* a command and returned by HL for */
- /* INVOKE_RES and INVOKE_ERR */
- int hl_id; /* ID supplied by HL when called */
- /* for executing a cmd and delivered */
- /* for results and errors */
- /* must be supplied by LL when aborting*/
- int proc; /* invoke procedure used by CMD_INVOKE */
- /* returned by callback and broadcast */
- int timeout; /* timeout for INVOKE CMD in ms */
- /* -1 in stat callback when timed out */
- /* error value when error callback */
- int datalen; /* length of cmd or stat data */
- u_char *data;/* pointer to data delivered or send */
- } isdn_cmd_stat;
-
-/*
- * Commands from linklevel to lowlevel
- *
- */
-#define ISDN_CMD_IOCTL 0 /* Perform ioctl */
-#define ISDN_CMD_DIAL 1 /* Dial out */
-#define ISDN_CMD_ACCEPTD 2 /* Accept an incoming call on D-Chan. */
-#define ISDN_CMD_ACCEPTB 3 /* Request B-Channel connect. */
-#define ISDN_CMD_HANGUP 4 /* Hangup */
-#define ISDN_CMD_CLREAZ 5 /* Clear EAZ(s) of channel */
-#define ISDN_CMD_SETEAZ 6 /* Set EAZ(s) of channel */
-#define ISDN_CMD_GETEAZ 7 /* Get EAZ(s) of channel */
-#define ISDN_CMD_SETSIL 8 /* Set Service-Indicator-List of channel */
-#define ISDN_CMD_GETSIL 9 /* Get Service-Indicator-List of channel */
-#define ISDN_CMD_SETL2 10 /* Set B-Chan. Layer2-Parameter */
-#define ISDN_CMD_GETL2 11 /* Get B-Chan. Layer2-Parameter */
-#define ISDN_CMD_SETL3 12 /* Set B-Chan. Layer3-Parameter */
-#define ISDN_CMD_GETL3 13 /* Get B-Chan. Layer3-Parameter */
-// #define ISDN_CMD_LOCK 14 /* Signal usage by upper levels */
-// #define ISDN_CMD_UNLOCK 15 /* Release usage-lock */
-#define ISDN_CMD_SUSPEND 16 /* Suspend connection */
-#define ISDN_CMD_RESUME 17 /* Resume connection */
-#define ISDN_CMD_PROCEED 18 /* Proceed with call establishment */
-#define ISDN_CMD_ALERT 19 /* Alert after Proceeding */
-#define ISDN_CMD_REDIR 20 /* Redir a incoming call */
-#define ISDN_CMD_PROT_IO 21 /* Protocol specific commands */
-#define CAPI_PUT_MESSAGE 22 /* CAPI message send down or up */
-#define ISDN_CMD_FAXCMD 23 /* FAX commands to HL-driver */
-#define ISDN_CMD_AUDIO 24 /* DSP, DTMF, ... settings */
-
-/*
- * Status-Values delivered from lowlevel to linklevel via
- * statcallb().
- *
- */
-#define ISDN_STAT_STAVAIL 256 /* Raw status-data available */
-#define ISDN_STAT_ICALL 257 /* Incoming call detected */
-#define ISDN_STAT_RUN 258 /* Signal protocol-code is running */
-#define ISDN_STAT_STOP 259 /* Signal halt of protocol-code */
-#define ISDN_STAT_DCONN 260 /* Signal D-Channel connect */
-#define ISDN_STAT_BCONN 261 /* Signal B-Channel connect */
-#define ISDN_STAT_DHUP 262 /* Signal D-Channel disconnect */
-#define ISDN_STAT_BHUP 263 /* Signal B-Channel disconnect */
-#define ISDN_STAT_CINF 264 /* Charge-Info */
-#define ISDN_STAT_LOAD 265 /* Signal new lowlevel-driver is loaded */
-#define ISDN_STAT_UNLOAD 266 /* Signal unload of lowlevel-driver */
-#define ISDN_STAT_BSENT 267 /* Signal packet sent */
-#define ISDN_STAT_NODCH 268 /* Signal no D-Channel */
-#define ISDN_STAT_ADDCH 269 /* Add more Channels */
-#define ISDN_STAT_CAUSE 270 /* Cause-Message */
-#define ISDN_STAT_ICALLW 271 /* Incoming call without B-chan waiting */
-#define ISDN_STAT_REDIR 272 /* Redir result */
-#define ISDN_STAT_PROT 273 /* protocol IO specific callback */
-#define ISDN_STAT_DISPLAY 274 /* deliver a received display message */
-#define ISDN_STAT_L1ERR 275 /* Signal Layer-1 Error */
-#define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */
-#define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */
-#define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */
-
-/*
- * Audio commands
- */
-#define ISDN_AUDIO_SETDD 0 /* Set DTMF detection */
-#define ISDN_AUDIO_DTMF 1 /* Rx/Tx DTMF */
-
-/*
- * Values for errcode field
- */
-#define ISDN_STAT_L1ERR_SEND 1
-#define ISDN_STAT_L1ERR_RECV 2
-
-/*
- * Values for feature-field of interface-struct.
- */
-/* Layer 2 */
-#define ISDN_FEATURE_L2_X75I (0x0001 << ISDN_PROTO_L2_X75I)
-#define ISDN_FEATURE_L2_X75UI (0x0001 << ISDN_PROTO_L2_X75UI)
-#define ISDN_FEATURE_L2_X75BUI (0x0001 << ISDN_PROTO_L2_X75BUI)
-#define ISDN_FEATURE_L2_HDLC (0x0001 << ISDN_PROTO_L2_HDLC)
-#define ISDN_FEATURE_L2_TRANS (0x0001 << ISDN_PROTO_L2_TRANS)
-#define ISDN_FEATURE_L2_X25DTE (0x0001 << ISDN_PROTO_L2_X25DTE)
-#define ISDN_FEATURE_L2_X25DCE (0x0001 << ISDN_PROTO_L2_X25DCE)
-#define ISDN_FEATURE_L2_V11096 (0x0001 << ISDN_PROTO_L2_V11096)
-#define ISDN_FEATURE_L2_V11019 (0x0001 << ISDN_PROTO_L2_V11019)
-#define ISDN_FEATURE_L2_V11038 (0x0001 << ISDN_PROTO_L2_V11038)
-#define ISDN_FEATURE_L2_MODEM (0x0001 << ISDN_PROTO_L2_MODEM)
-#define ISDN_FEATURE_L2_FAX (0x0001 << ISDN_PROTO_L2_FAX)
-#define ISDN_FEATURE_L2_HDLC_56K (0x0001 << ISDN_PROTO_L2_HDLC_56K)
-
-#define ISDN_FEATURE_L2_MASK (0x0FFFF) /* Max. 16 protocols */
-#define ISDN_FEATURE_L2_SHIFT (0)
-
-/* Layer 3 */
-#define ISDN_FEATURE_L3_TRANS (0x10000 << ISDN_PROTO_L3_TRANS)
-#define ISDN_FEATURE_L3_TRANSDSP (0x10000 << ISDN_PROTO_L3_TRANSDSP)
-#define ISDN_FEATURE_L3_FCLASS2 (0x10000 << ISDN_PROTO_L3_FCLASS2)
-#define ISDN_FEATURE_L3_FCLASS1 (0x10000 << ISDN_PROTO_L3_FCLASS1)
-
-#define ISDN_FEATURE_L3_MASK (0x0FF0000) /* Max. 8 Protocols */
-#define ISDN_FEATURE_L3_SHIFT (16)
-
-/* Signaling */
-#define ISDN_FEATURE_P_UNKNOWN (0x1000000 << ISDN_PTYPE_UNKNOWN)
-#define ISDN_FEATURE_P_1TR6 (0x1000000 << ISDN_PTYPE_1TR6)
-#define ISDN_FEATURE_P_EURO (0x1000000 << ISDN_PTYPE_EURO)
-#define ISDN_FEATURE_P_NI1 (0x1000000 << ISDN_PTYPE_NI1)
-
-#define ISDN_FEATURE_P_MASK (0x0FF000000) /* Max. 8 Protocols */
-#define ISDN_FEATURE_P_SHIFT (24)
-
-typedef struct setup_parm {
- unsigned char phone[32]; /* Remote Phone-Number */
- unsigned char eazmsn[32]; /* Local EAZ or MSN */
- unsigned char si1; /* Service Indicator 1 */
- unsigned char si2; /* Service Indicator 2 */
- unsigned char plan; /* Numbering plan */
- unsigned char screen; /* Screening info */
-} setup_parm;
-
-
-#ifdef CONFIG_ISDN_TTY_FAX
-/* T.30 Fax G3 */
-
-#define FAXIDLEN 21
-
-typedef struct T30_s {
- /* session parameters */
- __u8 resolution;
- __u8 rate;
- __u8 width;
- __u8 length;
- __u8 compression;
- __u8 ecm;
- __u8 binary;
- __u8 scantime;
- __u8 id[FAXIDLEN];
- /* additional parameters */
- __u8 phase;
- __u8 direction;
- __u8 code;
- __u8 badlin;
- __u8 badmul;
- __u8 bor;
- __u8 fet;
- __u8 pollid[FAXIDLEN];
- __u8 cq;
- __u8 cr;
- __u8 ctcrty;
- __u8 minsp;
- __u8 phcto;
- __u8 rel;
- __u8 nbc;
- /* remote station parameters */
- __u8 r_resolution;
- __u8 r_rate;
- __u8 r_width;
- __u8 r_length;
- __u8 r_compression;
- __u8 r_ecm;
- __u8 r_binary;
- __u8 r_scantime;
- __u8 r_id[FAXIDLEN];
- __u8 r_code;
-} __packed T30_s;
-
-#define ISDN_TTY_FAX_CONN_IN 0
-#define ISDN_TTY_FAX_CONN_OUT 1
-
-#define ISDN_TTY_FAX_FCON 0
-#define ISDN_TTY_FAX_DIS 1
-#define ISDN_TTY_FAX_FTT 2
-#define ISDN_TTY_FAX_MCF 3
-#define ISDN_TTY_FAX_DCS 4
-#define ISDN_TTY_FAX_TRAIN_OK 5
-#define ISDN_TTY_FAX_EOP 6
-#define ISDN_TTY_FAX_EOM 7
-#define ISDN_TTY_FAX_MPS 8
-#define ISDN_TTY_FAX_DTC 9
-#define ISDN_TTY_FAX_RID 10
-#define ISDN_TTY_FAX_HNG 11
-#define ISDN_TTY_FAX_DT 12
-#define ISDN_TTY_FAX_FCON_I 13
-#define ISDN_TTY_FAX_DR 14
-#define ISDN_TTY_FAX_ET 15
-#define ISDN_TTY_FAX_CFR 16
-#define ISDN_TTY_FAX_PTS 17
-#define ISDN_TTY_FAX_SENT 18
-
-#define ISDN_FAX_PHASE_IDLE 0
-#define ISDN_FAX_PHASE_A 1
-#define ISDN_FAX_PHASE_B 2
-#define ISDN_FAX_PHASE_C 3
-#define ISDN_FAX_PHASE_D 4
-#define ISDN_FAX_PHASE_E 5
-
-#endif /* TTY_FAX */
-
-#define ISDN_FAX_CLASS1_FAE 0
-#define ISDN_FAX_CLASS1_FTS 1
-#define ISDN_FAX_CLASS1_FRS 2
-#define ISDN_FAX_CLASS1_FTM 3
-#define ISDN_FAX_CLASS1_FRM 4
-#define ISDN_FAX_CLASS1_FTH 5
-#define ISDN_FAX_CLASS1_FRH 6
-#define ISDN_FAX_CLASS1_CTRL 7
-
-#define ISDN_FAX_CLASS1_OK 0
-#define ISDN_FAX_CLASS1_CONNECT 1
-#define ISDN_FAX_CLASS1_NOCARR 2
-#define ISDN_FAX_CLASS1_ERROR 3
-#define ISDN_FAX_CLASS1_FCERROR 4
-#define ISDN_FAX_CLASS1_QUERY 5
-
-typedef struct {
- __u8 cmd;
- __u8 subcmd;
- __u8 para[50];
-} aux_s;
-
-#define AT_COMMAND 0
-#define AT_EQ_VALUE 1
-#define AT_QUERY 2
-#define AT_EQ_QUERY 3
-
-/* CAPI structs */
-
-/* this is compatible to the old union size */
-#define MAX_CAPI_PARA_LEN 50
-
-typedef struct {
- /* Header */
- __u16 Length;
- __u16 ApplId;
- __u8 Command;
- __u8 Subcommand;
- __u16 Messagenumber;
-
- /* Parameter */
- union {
- __u32 Controller;
- __u32 PLCI;
- __u32 NCCI;
- } adr;
- __u8 para[MAX_CAPI_PARA_LEN];
-} capi_msg;
-
-/*
- * Structure for exchanging above infos
- *
- */
-typedef struct {
- int driver; /* Lowlevel-Driver-ID */
- int command; /* Command or Status (see above) */
- ulong arg; /* Additional Data */
- union {
- ulong errcode; /* Type of error with STAT_L1ERR */
- int length; /* Amount of bytes sent with STAT_BSENT */
- u_char num[50]; /* Additional Data */
- setup_parm setup;/* For SETUP msg */
- capi_msg cmsg; /* For CAPI like messages */
- char display[85];/* display message data */
- isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */
- aux_s aux; /* for modem commands/indications */
-#ifdef CONFIG_ISDN_TTY_FAX
- T30_s *fax; /* Pointer to ttys fax struct */
-#endif
- ulong userdata; /* User Data */
- } parm;
-} isdn_ctrl;
-
-#define dss1_io isdn_io
-#define ni1_io isdn_io
-
-/*
- * The interface-struct itself (initialized at load-time of lowlevel-driver)
- *
- * See Documentation/isdn/INTERFACE for a description, how the communication
- * between the ISDN subsystem and its drivers is done.
- *
- */
-typedef struct {
- struct module *owner;
-
- /* Number of channels supported by this driver
- */
- int channels;
-
- /*
- * Maximum Size of transmit/receive-buffer this driver supports.
- */
- int maxbufsize;
-
- /* Feature-Flags for this driver.
- * See defines ISDN_FEATURE_... for Values
- */
- unsigned long features;
-
- /*
- * Needed for calculating
- * dev->hard_header_len = linklayer header + hl_hdrlen;
- * Drivers, not supporting sk_buff's should set this to 0.
- */
- unsigned short hl_hdrlen;
-
- /*
- * Receive-Callback using sk_buff's
- * Parameters:
- * int Driver-ID
- * int local channel-number (0 ...)
- * struct sk_buff *skb received Data
- */
- void (*rcvcallb_skb)(int, int, struct sk_buff *);
-
- /* Status-Callback
- * Parameters:
- * isdn_ctrl*
- * driver = Driver ID.
- * command = One of above ISDN_STAT_... constants.
- * arg = depending on status-type.
- * num = depending on status-type.
- */
- int (*statcallb)(isdn_ctrl*);
-
- /* Send command
- * Parameters:
- * isdn_ctrl*
- * driver = Driver ID.
- * command = One of above ISDN_CMD_... constants.
- * arg = depending on command.
- * num = depending on command.
- */
- int (*command)(isdn_ctrl*);
-
- /*
- * Send data using sk_buff's
- * Parameters:
- * int driverId
- * int local channel-number (0...)
- * int Flag: Need ACK for this packet.
- * struct sk_buff *skb Data to send
- */
- int (*writebuf_skb) (int, int, int, struct sk_buff *);
-
- /* Send raw D-Channel-Commands
- * Parameters:
- * u_char pointer data
- * int length of data
- * int driverId
- * int local channel-number (0 ...)
- */
- int (*writecmd)(const u_char __user *, int, int, int);
-
- /* Read raw Status replies
- * u_char pointer data (volatile)
- * int length of buffer
- * int driverId
- * int local channel-number (0 ...)
- */
- int (*readstat)(u_char __user *, int, int, int);
-
- char id[20];
-} isdn_if;
-
-/*
- * Function which must be called by lowlevel-driver at loadtime with
- * the following fields of above struct set:
- *
- * channels Number of channels that will be supported.
- * hl_hdrlen Space to preserve in sk_buff's when sending. Drivers, not
- * supporting sk_buff's should set this to 0.
- * command Address of Command-Handler.
- * features Bitwise coded Features of this driver. (use ISDN_FEATURE_...)
- * writebuf_skb Address of Skbuff-Send-Handler.
- * writecmd " " D-Channel " which accepts raw D-Ch-Commands.
- * readstat " " D-Channel " which delivers raw Status-Data.
- *
- * The linklevel-driver fills the following fields:
- *
- * channels Driver-ID assigned to this driver. (Must be used on all
- * subsequent callbacks.
- * rcvcallb_skb Address of handler for received Skbuff's.
- * statcallb " " " for status-changes.
- *
- */
-extern int register_isdn(isdn_if*);
-#include <linux/uaccess.h>
-
-#endif /* __ISDNIF_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * wanrouter.h Legacy declarations kept around until X25 is removed
- */
-
-#ifndef _ROUTER_H
-#define _ROUTER_H
-
-#include <uapi/linux/wanrouter.h>
-
-#endif /* _ROUTER_H */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $
- *
- * Main header for the Linux ISDN subsystem (linklevel).
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _UAPI__ISDN_H__
-#define _UAPI__ISDN_H__
-
-#include <linux/ioctl.h>
-#include <linux/tty.h>
-
-#define ISDN_MAX_DRIVERS 32
-#define ISDN_MAX_CHANNELS 64
-
-/* New ioctl-codes */
-#define IIOCNETAIF _IO('I',1)
-#define IIOCNETDIF _IO('I',2)
-#define IIOCNETSCF _IO('I',3)
-#define IIOCNETGCF _IO('I',4)
-#define IIOCNETANM _IO('I',5)
-#define IIOCNETDNM _IO('I',6)
-#define IIOCNETGNM _IO('I',7)
-#define IIOCGETSET _IO('I',8) /* no longer supported */
-#define IIOCSETSET _IO('I',9) /* no longer supported */
-#define IIOCSETVER _IO('I',10)
-#define IIOCNETHUP _IO('I',11)
-#define IIOCSETGST _IO('I',12)
-#define IIOCSETBRJ _IO('I',13)
-#define IIOCSIGPRF _IO('I',14)
-#define IIOCGETPRF _IO('I',15)
-#define IIOCSETPRF _IO('I',16)
-#define IIOCGETMAP _IO('I',17)
-#define IIOCSETMAP _IO('I',18)
-#define IIOCNETASL _IO('I',19)
-#define IIOCNETDIL _IO('I',20)
-#define IIOCGETCPS _IO('I',21)
-#define IIOCGETDVR _IO('I',22)
-#define IIOCNETLCR _IO('I',23) /* dwabc ioctl for LCR from isdnlog */
-#define IIOCNETDWRSET _IO('I',24) /* dwabc ioctl to reset abc-values to default on a net-interface */
-
-#define IIOCNETALN _IO('I',32)
-#define IIOCNETDLN _IO('I',33)
-
-#define IIOCNETGPN _IO('I',34)
-
-#define IIOCDBGVAR _IO('I',127)
-
-#define IIOCDRVCTL _IO('I',128)
-
-/* cisco hdlck device private ioctls */
-#define SIOCGKEEPPERIOD (SIOCDEVPRIVATE + 0)
-#define SIOCSKEEPPERIOD (SIOCDEVPRIVATE + 1)
-#define SIOCGDEBSERINT (SIOCDEVPRIVATE + 2)
-#define SIOCSDEBSERINT (SIOCDEVPRIVATE + 3)
-
-/* Packet encapsulations for net-interfaces */
-#define ISDN_NET_ENCAP_ETHER 0
-#define ISDN_NET_ENCAP_RAWIP 1
-#define ISDN_NET_ENCAP_IPTYP 2
-#define ISDN_NET_ENCAP_CISCOHDLC 3 /* Without SLARP and keepalive */
-#define ISDN_NET_ENCAP_SYNCPPP 4
-#define ISDN_NET_ENCAP_UIHDLC 5
-#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */
-#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt */
-#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE
-
-/* Facility which currently uses an ISDN-channel */
-#define ISDN_USAGE_NONE 0
-#define ISDN_USAGE_RAW 1
-#define ISDN_USAGE_MODEM 2
-#define ISDN_USAGE_NET 3
-#define ISDN_USAGE_VOICE 4
-#define ISDN_USAGE_FAX 5
-#define ISDN_USAGE_MASK 7 /* Mask to get plain usage */
-#define ISDN_USAGE_DISABLED 32 /* This bit is set, if channel is disabled */
-#define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
-#define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */
-
-#define ISDN_MODEM_NUMREG 24 /* Number of Modem-Registers */
-#define ISDN_LMSNLEN 255 /* Length of tty's Listen-MSN string */
-#define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */
-
-#define ISDN_MSNLEN 32
-#define NET_DV 0x06 /* Data version for isdn_net_ioctl_cfg */
-#define TTY_DV 0x06 /* Data version for iprofd etc. */
-
-#define INF_DV 0x01 /* Data version for /dev/isdninfo */
-
-typedef struct {
- char drvid[25];
- unsigned long arg;
-} isdn_ioctl_struct;
-
-typedef struct {
- char name[10];
- char phone[ISDN_MSNLEN];
- int outgoing;
-} isdn_net_ioctl_phone;
-
-typedef struct {
- char name[10]; /* Name of interface */
- char master[10]; /* Name of Master for Bundling */
- char slave[10]; /* Name of Slave for Bundling */
- char eaz[256]; /* EAZ/MSN */
- char drvid[25]; /* DriverId for Bindings */
- int onhtime; /* Hangup-Timeout */
- int charge; /* Charge-Units */
- int l2_proto; /* Layer-2 protocol */
- int l3_proto; /* Layer-3 protocol */
- int p_encap; /* Encapsulation */
- int exclusive; /* Channel, if bound exclusive */
- int dialmax; /* Dial Retry-Counter */
- int slavedelay; /* Delay until slave starts up */
- int cbdelay; /* Delay before Callback */
- int chargehup; /* Flag: Charge-Hangup */
- int ihup; /* Flag: Hangup-Timeout on incoming line */
- int secure; /* Flag: Secure */
- int callback; /* Flag: Callback */
- int cbhup; /* Flag: Reject Call before Callback */
- int pppbind; /* ippp device for bindings */
- int chargeint; /* Use fixed charge interval length */
- int triggercps; /* BogoCPS needed for triggering slave */
- int dialtimeout; /* Dial-Timeout */
- int dialwait; /* Time to wait after failed dial */
- int dialmode; /* Flag: off / on / auto */
-} isdn_net_ioctl_cfg;
-
-#define ISDN_NET_DIALMODE_MASK 0xC0 /* bits for status */
-#define ISDN_NET_DM_OFF 0x00 /* this interface is stopped */
-#define ISDN_NET_DM_MANUAL 0x40 /* this interface is on (manual) */
-#define ISDN_NET_DM_AUTO 0x80 /* this interface is autodial */
-#define ISDN_NET_DIALMODE(x) ((&(x))->flags & ISDN_NET_DIALMODE_MASK)
-
-
-#endif /* _UAPI__ISDN_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $
- *
- * Header for the diversion supplementary interface for i4l.
- *
- * Author Werner Cornelius (werner@titro.de)
- * Copyright by Werner Cornelius (werner@titro.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _UAPI_LINUX_ISDN_DIVERTIF_H
-#define _UAPI_LINUX_ISDN_DIVERTIF_H
-
-/***********************************************************/
-/* magic value is also used to control version information */
-/***********************************************************/
-#define DIVERT_IF_MAGIC 0x25873401
-#define DIVERT_CMD_REG 0x00 /* register command */
-#define DIVERT_CMD_REL 0x01 /* release command */
-#define DIVERT_NO_ERR 0x00 /* return value no error */
-#define DIVERT_CMD_ERR 0x01 /* invalid cmd */
-#define DIVERT_VER_ERR 0x02 /* magic/version invalid */
-#define DIVERT_REG_ERR 0x03 /* module already registered */
-#define DIVERT_REL_ERR 0x04 /* module not registered */
-#define DIVERT_REG_NAME isdn_register_divert
-
-
-#endif /* _UAPI_LINUX_ISDN_DIVERTIF_H */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */
-/* Linux ISDN subsystem, sync PPP, interface to ipppd
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _UAPI_LINUX_ISDN_PPP_H
-#define _UAPI_LINUX_ISDN_PPP_H
-
-#define CALLTYPE_INCOMING 0x1
-#define CALLTYPE_OUTGOING 0x2
-#define CALLTYPE_CALLBACK 0x4
-
-#define IPPP_VERSION "2.2.0"
-
-struct pppcallinfo
-{
- int calltype;
- unsigned char local_num[64];
- unsigned char remote_num[64];
- int charge_units;
-};
-
-#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
-#define PPPIOCBUNDLE _IOW('t',129,int)
-#define PPPIOCGMPFLAGS _IOR('t',130,int)
-#define PPPIOCSMPFLAGS _IOW('t',131,int)
-#define PPPIOCSMPMTU _IOW('t',132,int)
-#define PPPIOCSMPMRU _IOW('t',133,int)
-#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8])
-#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
-#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] )
-
-
-#define SC_MP_PROT 0x00000200
-#define SC_REJ_MP_PROT 0x00000400
-#define SC_OUT_SHORT_SEQ 0x00000800
-#define SC_IN_SHORT_SEQ 0x00004000
-
-#define SC_DECOMP_ON 0x01
-#define SC_COMP_ON 0x02
-#define SC_DECOMP_DISCARD 0x04
-#define SC_COMP_DISCARD 0x08
-#define SC_LINK_DECOMP_ON 0x10
-#define SC_LINK_COMP_ON 0x20
-#define SC_LINK_DECOMP_DISCARD 0x40
-#define SC_LINK_COMP_DISCARD 0x80
-
-#define ISDN_PPP_COMP_MAX_OPTIONS 16
-
-#define IPPP_COMP_FLAG_XMIT 0x1
-#define IPPP_COMP_FLAG_LINK 0x2
-
-struct isdn_ppp_comp_data {
- int num;
- unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
- int optlen;
- int flags;
-};
-
-#endif /* _UAPI_LINUX_ISDN_PPP_H */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */
-/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $
- *
- * Linux ISDN subsystem
- * Definition of the interface between the subsystem and its low-level drivers.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _UAPI__ISDNIF_H__
-#define _UAPI__ISDNIF_H__
-
-
-/*
- * Values for general protocol-selection
- */
-#define ISDN_PTYPE_UNKNOWN 0 /* Protocol undefined */
-#define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */
-#define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */
-#define ISDN_PTYPE_LEASED 3 /* for leased lines */
-#define ISDN_PTYPE_NI1 4 /* US NI-1 protocol */
-#define ISDN_PTYPE_MAX 7 /* Max. 8 Protocols */
-
-/*
- * Values for Layer-2-protocol-selection
- */
-#define ISDN_PROTO_L2_X75I 0 /* X75/LAPB with I-Frames */
-#define ISDN_PROTO_L2_X75UI 1 /* X75/LAPB with UI-Frames */
-#define ISDN_PROTO_L2_X75BUI 2 /* X75/LAPB with UI-Frames */
-#define ISDN_PROTO_L2_HDLC 3 /* HDLC */
-#define ISDN_PROTO_L2_TRANS 4 /* Transparent (Voice) */
-#define ISDN_PROTO_L2_X25DTE 5 /* X25/LAPB DTE mode */
-#define ISDN_PROTO_L2_X25DCE 6 /* X25/LAPB DCE mode */
-#define ISDN_PROTO_L2_V11096 7 /* V.110 bitrate adaption 9600 Baud */
-#define ISDN_PROTO_L2_V11019 8 /* V.110 bitrate adaption 19200 Baud */
-#define ISDN_PROTO_L2_V11038 9 /* V.110 bitrate adaption 38400 Baud */
-#define ISDN_PROTO_L2_MODEM 10 /* Analog Modem on Board */
-#define ISDN_PROTO_L2_FAX 11 /* Fax Group 2/3 */
-#define ISDN_PROTO_L2_HDLC_56K 12 /* HDLC 56k */
-#define ISDN_PROTO_L2_MAX 15 /* Max. 16 Protocols */
-
-/*
- * Values for Layer-3-protocol-selection
- */
-#define ISDN_PROTO_L3_TRANS 0 /* Transparent */
-#define ISDN_PROTO_L3_TRANSDSP 1 /* Transparent with DSP */
-#define ISDN_PROTO_L3_FCLASS2 2 /* Fax Group 2/3 CLASS 2 */
-#define ISDN_PROTO_L3_FCLASS1 3 /* Fax Group 2/3 CLASS 1 */
-#define ISDN_PROTO_L3_MAX 7 /* Max. 8 Protocols */
-
-
-#endif /* _UAPI__ISDNIF_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * wanrouter.h Legacy declarations kept around until X25 is removed
- */
-
-#ifndef _UAPI_ROUTER_H
-#define _UAPI_ROUTER_H
-
-/* 'state' defines */
-enum wan_states
-{
- WAN_UNCONFIGURED, /* link/channel is not configured */
- WAN_DISCONNECTED, /* link/channel is disconnected */
- WAN_CONNECTING, /* connection is in progress */
- WAN_CONNECTED /* link/channel is operational */
-};
-
-#endif /* _UAPI_ROUTER_H */