Corba-MMIMS
Left Up Right Corbammims

Wir bauen ein /dev/isdncti im Linux- Kern

Grundvorstellung

Um andere nützliche Programme nicht zu stören (isdnlog,imon,...) und es einfach zu haben, wollen wir ein /dev/isdncti bauen.
Alle Anrufe, egal ob unser Rechner beteiligt ist oder nicht, sollen in /dev/isdncti gemeldet werden.
Ein Prozeß soll dann auf /dev/isdncti lesen und dann die Informationen weiter verarbeiten. Die Funktionsweise soll also genau so sein wie von /dev/isdninfo.

Wichtige Entdeckung

Die low-Level-Treiber rufen die Funktion isdn_status_callback in isdn_common.c auf, wenn z.B. ein Anruf ankommt (ISDN_STAT_ICALL). Im Falle des ankommenden Anrufes wird dann das passende Netzwerkinterface oder der passende tty gesucht.

Vor dem Beginn der Suche ist der richtige Ort um die Information in unser /dev/isdncti zu übergeben. In der Struktur setup_parm (isdnif.h) stehen sie schön aufbereitet drin, unabhängig von der verwendeten Karte und dem Protokoll.

Kernmechanismen

Wir ergänzen in include/isdn.h:
   /* CTI-data */
   struct isdn_cti 
   {
      struct sk_buff_head blockliste;
      struct wait_queue *cti_waitq;
      int o;               /* offene Dateien */
   };

   struct isdn_devt
   { /* ... */
     struct isdn_cti cti;
     /* ... */
   };

sk_buff ist eine Listenstruktur, die Nachrichtenpakete (für die Netzwerkimplementierung) verwaltet. Diese wird auch für den Datentransfer beim lesen des B-Channels verwendet:
Blöcke werden mit dev_kfree_skb(skb) nach dem ausliefern freigegeben (vgl. isdn_recieve_skb_callback )
Initialisieren:
skb_queue_head_init(&waitq);
Abfrage nach Länge:
if(skb_queue_empty(waitq)) { ... }
Aushängen:
	skb=skb_dequeue(&waitq);
        skb->data , skb->len;
	dev_kfree_skb(skb);
  
Einhängen: vgl isdn_writebuf_stub
	struct sk_buff *skb = alloc_skb(len,GFP_ATOMIC); 
        if(!skb) fehler ...
        skb_reserve(skb, hl);
        if (user)
                copy_from_user(skb_put(skb, len), buf, len);
        else
                memcpy(skb_put(skb, len), buf, len);
    
skb_queue_tail hängt Paket am Ende an
skb_queue_head hängt Paket am Anfang an
    ulong flags
    save_flags(flags);
    cli();
    /* Aktion */
    restore_flags(flags);

    //    Warteschlangenverwaltung
    if(!(wq = ((struct wait_queue **)
              kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL)))
    {
          printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
    }
    memset((char *)wq,0,sizeof(struct wait_queue *));
    interruptible_sleep_on(waitq); /*vgl. isdn_read_bchan()*/
    wake_up_interruptible(waitq);

Neues in Kern 2.4

Allgemeinere Funktion skb_queue_purge ersetzt isdn_free_queue.
Diese Funktion löscht eine skb_buff_ - Liste

cti_waitq hat nun einen anderen Typ bekommen: statt struct wait_queue haben wir nun: wait_queue_head_t

Wir müssen acht geben, daß kernel_lock() wieder freigegeben wird.

Format aus /dev/isdncti

Felder sind durch Leerzeichen getrennt, die Zeile wird mit dem Zeilentrenner \n getrennt. Ein read liefert genau ein Ereignis.
Das erste Feld ist der Ereignisname:
ICALL
Incomming Call
bei ICALL kommen dann sämtliche Werte aus der Struktur setup_parm aus /usr/src/linux/isdn/isdnif.h:
phone
die Telefonnummer des Anrufers, dieses ist eine Folge von Ziffern oder unknown, falls diese nicht übermittelt wird.
eazmsn
die lokale msn, ebenfalls eine Ziffernfolge
si1 Service Indicator 1 , hexadezimal codiert
Register 18 bei ttyIx, aber umcodiert.
Nach kurzer Analyse des Codes stimmen diese mit den Angaben in ttyIx(4) überein:
1audio, gewöhnliche Telefonanrufe, emprisch bestätigt
5BTX
7
data, Code in isdn_net.c:2091
si2 Service Indicator 2, hexadezimal codiert
bei DSS1 immer 0 , entspricht Register 19 bei ttyIx
plan Numbering plan, hexadezimal codiert
laut isdn_tty.c entspricht es Register 21 bei ttyI(4),
value of octet 3 of calling party number Information Element (Numbering plan). See section 4.5.10 of ITU Q.931.
screen Screening info , hexadezimal codiert laut isdn_tty.c entspricht es Register 22 bei ttyI(4),
value of octet 3a of calling party number Information Element (Screening info). See section 4.5.10 of ITU Q.931.
Beobachtung: bei ISDN (zumindest intern) plan=0x21 screen=0x81
analog plan=0 screen=0xa3

Installation

  1. Hier ist der patch für Linux 2.2.x und für Linux-2.4.x
  2. Kern patchen

    Getestet mit Kern 2.2.13,2.2.14 und 2.2.15 sowie mit Kern 2.4.8 (diff und patch sind toll!!!)

         cd /usr/src/linux
         patch -b -p0 < /tmp/ctipatch.txt
         make modules 
         make modules_install
       
  3. Device einrichten
    mknod -m 444 /dev/isdncti c 45 254
    
  4. Sicherstellen, daß unser neues modul auch geladen wird
         init 1 ; depmod -a ; init 2
         
  5. Test
         cat < /dev/isdncti
         
    Wenn nun angerufen wird, wird eine Zeile geliefert ...

Rudolf Weber Informatik- und Netzwerkverein Ravensburg e.V