Eigene ioctl-Befehle

Wir haben schon gesehen, daß der Systemaufruf ioctl für Sockets implementiert wird. Beispiele von Socket-ioctl-Befehlen sind SIOCSIFADDR und SIOCSIFMAP. Schauen wir uns jetzt an, wie das dritte Argument des Systemaufrufs vom Netzwerk-Code verwendet wird.

Wenn der Systemaufruf ioctl an einem Socket aufgerufen wird, dann ist die Befehlsnummer eines der in <linux/sockios.h> definierten Symbole, und die Funktion sock_ioctl ruft direkt eine protokollspezifische Funktion auf (wobei sich der Begriff “Protokoll” hier auf das verwendete Netzwerk-Protokoll wie IP oder AppleTalk bezieht).

Jeder ioctl-Befehl, der von der Protokoll-Schicht nicht erkannt wird, wird an die Geräteschicht weitergereicht. Diese gerätebezogenen ioctl-Befehle akzeptieren ein drittes Argument aus dem User-Space, das den Typ struct ifreq * hat. Diese Struktur ist in <linux/if.h> definiert. Auch die Befehle SIOCSIFADDR und SIOCSIFMAP arbeiten mit dieser Struktur. Das zusätzliche Argument von SIOCSIFMAP ist einfach nur ein Feld von ifreq, auch wenn es als ifmap definiert ist.

Außer den standardisierten Befehlen kann jede Schnittstelle eigene ioctl-Befehle definieren. Die Schnittstelle plip ermöglicht beispielsweise das Einstellen der internen Timeout-Werte über ioctl. Die ioctl-Implementation für Sockets erkennt 16 zusätzliche Befehle, die schnittstellenspezifisch sind: SIOCDEVPRIVATE bis SIOCDEVPRIVATE+15.

Wenn einer dieser Befehle erkannt wird, dann wird dev->do_ioctl im zugehörigen Schnittstellen-Treiber aufgerufen. Diese Funktion bekommt den gleichen struct ifreq *-Zeiger wie die allgemeine ioctl-Funktion:


int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);

Der Zeiger ifr zeigt auf eine Adresse im Kernel Space, die eine Kopie der vom Benutzer übergebenen Struktur enthält. Nach dem Rücksprung von do_ioctl wird diese Struktur in den User-Space zurückkopiert. Der Treiber kann daher die privaten Befehle sowohl zum Empfangen wie auch zur Herausgabe von Daten verwenden.

Die treiberspezifischen Befehle können die Felder in struct ifreq verwenden, aber diese haben bereits eine standardisierte Bedeutung, und es ist unwahrscheinlich, daß der Treiber die Struktur für seine Zwecke umfunktionieren kann. Das Feld ifr_data ist ein Element des Typs caddr_t (ein Zeiger), das für gerätespezifische Bedürfnisse verwendet werden kann. Der Treiber und die Programme, die die ioctl-Befehle des Treibers aufrufen, sollten sich über die Benutzung von ifr_data einig sein. Beispielsweise verwendet pppstats gerätespezifische Befehle, um Informationen vom ppp-Schnittstellentreiber zu bekommen.

Es lohnt sich nicht, hier eine Implementation von do_ioctl zu zeigen, aber mit den Informationen in diesem Kapitel und den Kernel-Beispielen sollten Sie in der Lage sein, eine Implementation zu schreiben, wenn Sie eine benötigen. Beachten Sie jedoch, daß die Implementation von plip ifr_data falsch verwendet und daher nicht als Beispiel für eine ioctl-Implementation herangezogen werden sollte.