**************************************************************************** *********************************ATTENTION********************************** **************************************************************************** Ce logiciel est en version beta et est fourni tel quel. Il fonctionne au niveau du noyau du système d'exploitation et peut donc engendrer la perte d'une partie ou de la totalité de vos données. Les auteurs de ce logiciel ainsi que ceux qui ont travaillé dessus (y compris moi-même) en laissent la responsabilité totale à l'utilisateur. Autrement dit, vous êtes libre de ne pas l'utiliser, mais si vous le faites, c'est sous votre entière responsabilité. **************************************************************************** **************************************************************************** **************************************************************************** I. Introduction Ceci est la refonte du driver pour Linux des modems basés sur le chipset Eagle 8051 d'Analog. Le modem Sagem F@st 800 et les modems ADSL de USRobotics sont notamment basés sur ce chipset. Toutefois, seul le modem F@st 800 a été réellement testé. La dernière version de ce driver pourra être téléchargée à partir de la page suivante : http://casteyde.christian.free.fr/sagem/index.html Vous trouverez un forum dédié au support des drivers Sagem à l'adresse suivante : http://www.eagle-usb.fr.st/ Le code du driver a été partiellement nettoyé/réécrit et a été rendu complètement compatible avec la GPL par récriture des parties non libres, afin de permettre les extensions et modifications ultérieures. Un certain nombre d'abérations ont également été corrigées dans l'organisation des sources et dans le code lui-même dans le cadre du nettoyage. Enfin, les bugs les plus graves ont été corrigés afin de rendre le driver utilisable. Le code de communication avec l'espace utilisateur a été réécrit pour blinder le module en cas d'erreur de la part des clients. Les principale modifications sont les suivantes : - correction du memory leak en pppoa ; - correction de la perte de connexion en cas de trafic montant élevé ; - correction des plantages de pppoa et contrôle des tailles des paquets reçus de l'interface du driver ; - correction des race conditions à l'initialisation ; - ajout des codes de contrôles ioctl nécessaires pour un usage sûr ; - contrôle de la validité des firmwares envoyés au noyau ; - support des noyaux 2.4.x ; - simplification et corrections diverses du code du module ; - extraction du firmware du module ; - réécriture des fichiers hotplug ; - réécriture du programme d'installation ; - réécriture complète en GPL de adictrl avec support d'une option pour obtenir de l'aide et amélioration des messages d'erreur. C'est surtout ce dernier point qui va provoquer des incompatibilités avec le driver original d'ADI, aussi les informations qui suivent vous seront utiles pour installer cette version. II. Installation Avant tout, le driver demande un certain nombre de fonctionnalités au niveau du noyau pour fonctionner. Ces fonctionnalités sont les suivantes : - support du chargement des modules du noyau avec les informations de version (options "Enable loadable module suppor", "Set version information on all module symbols" et "Kernel module loader") ; - support pour le chargement des périphériques à chaud (si l'on veut que le driver soit chargé automatiquement au démarrage, option "Support for hot-pluggable devices") ; - support du réseau (normalement, c'est assuré sur tous les noyaux) ; - support ppp (options "PPP (point-to-point protocol) support", "PPP support for async serial ports", et éventuellement "PPP support for sync tty ports" si vous voulez utiliser le mode de connexion synchrone de pppd) ; - support USB (options "Support for USB", "Preliminary USB device filesystem" et le support pour l'un des contrôleurs UHCI ou pour le contrôleur OHCI). Pour ceux dont le contrôleur USB est UHCI, il est recommandé d'utiliser le pilote alternatif JE du noyau. Les en-têtes du noyau doivent se trouver dans le répertoire /usr/src/linux, ou celui-ci doit être un lien symbolique vers ce répertoire. Les systèmes de fichiers virtuels /proc et /proc/bus/usb doivent être montés. Pour automatiser cela, il suffit d'ajouter les lignes suivantes dans le fichier /etc/fstab : none /proc proc defaults 0 0 usbdevfs /proc/bus/usb usbdevfs defaults 0 0 Le démon pppd version 2.4.1 ou plus doit également être installé. L'installation du driver en soi doit se faire de la manière suivante : 1. Compilation du driver make clean make 2. Installation du driver make install Cette étape nécessite d'être sous le compte root. Elle vous demandera les paramètres de connexion à votre fournisseur d'accès pour générer les fichiers de configuration /etc/ppp/options, /etc/ppp/pap-secrets et /etc/ppp/chap-secrets. Une fois les drivers installés, vous pourrez vous connecter à l'aide du script /usr/sbin/startadsl et terminer la connexion avec le script /usr/sbin/stopadsl. Ces scripts ne peuvent être exécutés que dans le compte root. 3. Configuration de la connexion automatique Cette version n'installe pas les scripts d'automatisation de la connexion en raison des différences entre les distributions et les goûts de chacun quant à la manière de réaliser cette automatisation. Cependant, un script de reconnexion automatique est fourni dans le répertoire scripts/adsl. Ce script se nomme adsl.inittab et est écrit pour être utilisé directement à partir du fichier de configuration /etc/inittab. Pour l'installer, il suffit de le copier dans le répertoire /usr/sbin et d'ajouter la ligne suivante dans le fichier /etc/inittab : adsl:2345:respawn:/usr/sbin/adsl.inittab Cela permettra de lancer la connexion automatique (et de gérer les reconnexions) dans les niveaux d'exécution 2, 3, 4 et 5. Note : L'installation ne prend pas en charge les drivers USRobotics pour l'instant. Le driver est fourni avec les fichiers BNM du code du DSP de ces modems et les fichiers de configuration, tels qu'ils sont fournis par USRobotics. Leur utilisation nécessite de reconstruire le fichier binaire contenant le code du DSP approprié au modèle de modem utilisé à l'aide de l'outil buildDSP, et d'installer le fichier généré et le fichier d'options adéquat dans le répertoire /etc/analog. III. Désinstallation Aucun outil de désinstallation n'est fourni dans cette version. La désinstallation doit donc être effectuée manuellement. Pour information, le driver installe les fichiers suivants : /lib/modules/version/kernel/drivers/usb/adiusbadsl.o /usr/sbin/adictrl /usr/sbin/startadsl /usr/sbin/stopadsl /usr/sbin/showstat /etc/analog/adiusbadsl.conf /etc/analog/firmware.bin /etc/analog/DSPcode.bin /etc/hotplug/usb/adiusbfirmware /etc/hotplug/usb/adiusbdsp /etc/ppp/options.adsl /etc/ppp/options.mire Il modifie également les fichiers de configuration suivants : /etc/ppp/pap-secrets (ajout du mot de passe de la connexion) /etc/ppp/chap-secrets (ajout du mot de passe de la connexion) /etc/hotplug/usb.usermap (ajout des entrées pour les périphériques pris en charge par les fichiers hotplug du driver). IV. Utilisation Le driver initial chargeait le firmware dans le modem dès sa détection, car ce firmware était codé en dur. À présent, ce firmware a été extrait (afin de rendre le module complètement GPL), ce qui implique qu'il doit être chargé depuis le mode utilisateur une fois le modem détecté par le module. Cela peut être réalisé avec la commande adictrl -f [fichier] où "fichier" est le fichier du firmware. La valeur par défaut est /etc/analog/firmware.bin. Il s'agit d'un fichier binaire généré par le programme driver/firmware/buildFirmware et contenant, surprise, le firmware du modem. Attention : Le firmware doit être chargé au plus tôt après la connexion du modem. En effet, le modem peut se bloquer si le firmware n'est pas chargé dès les premières minutes et qu'il est relié au réseau téléphonique. Il s'agit d'un bug du modem, s'il se produit, il faut le débrancher et le rebrancher. Le module ne conserve pas le firmware. Il est donc nécessaire de relancer adictrl après chaque rebranchement du modem. Une fois le firmware chargé dans le modem, celui-ci attend le code du DSP ADSL, qui doit être chargé avec la commande : adictrl -d [fichier] où "fichier" est le fichier binaire contenant le code du DSP. Ce fichier peut être généré à l'aide du programme driver/firmware/buildDSP à partir des fichiers .BNM. Par défaut il s'agit de /etc/analog/DSPcode.bin. Le module conserve le code du DSP en mémoire car le modem peut en avoir besoin à tout instant. Cependant, il n'est pas renvoyé automatiquement lors du rebranchement du modem, aussi est-il nécessaire de relancer adictrl explicitement dans ce cas. Cette commande envoie également les options du fichier /etc/analog/adiusbadsl.conf au module. Le fichier d'option peut être changé indépendamment à l'aide de l'option '-o' de adictrl. Toutefois, les options ne peuvent pas être rechargées tant que l'interface réseau du modem est en cours d'utilisation. Le modem s'initialise dès qu'il reçoit le code du DSP. Une fois l'initialisation terminée, il est possible de se connecter. À tout instant, il est possible de visualiser l'état du modem à l'aide du fichier : /proc/driver/adimodem (attention, ce fichier était placé au préalable directement dans /proc). La commande showstat permet d'afficher le contenu de ce fichier plus facilement. Il est possible de se synchroniser avec le modem grâce à la commande suivante : atictrl -s qui ne se termine que lorsque le modem passe dans l'état "operational". Pour se connecter, il suffit de monter l'interface réseau ethX du modem (attention, cette interface était nommée "ADIModem" auparavant), où X est un numéro dépendant du nombre d'interfaces Ethernet déjà installées dans votre système. Il s'agit généralement de 0 (pas de carte réseau) ou de 1 (une carte résau). Cette interface réseau est créée à la demande à l'aide de l'option -i de adictrl : adictrl -i Cette commande affiche également le nom de l'interface réseau utilisée. Elle peut être appelée plusieurs fois, une seule interface est créée, lors du premier appel. Ceci permet de s'assurer que le nom de l'interface réseau choisi par le driver ne décale pas les noms des éventuelles autres cartes réseaux installées sur le système. Le montage de l'interface réseau se fait classiquement à l'aide de la commande ifconfig : /sbin/ifconfig ethX 192.168.60.30 up Le choix de l'adresse IP utilisée n'a aucune importance, du moment qu'elle n'entre pas en conflit avec une adresse existante. Il est recommandé de n'utiliser que des adresses réservées aux réseaux privés. Lorsque l'interface réseau est montée, la commande /usr/sbin/pppd pty "/usr/sbin/pppoa -I ethX" file /etc/ppp/options.adsl lance la connexion, pourvu que les options et les paramètres de connexion aient été correctement définis dans /etc/ppp/options.adsl et /etc/ppp/pap-secrets ou /etc/ppp/chap-secrets. Vous trouverez des exemples de ces fichiers dans le répertoire scripts/ppp. Le programme d'installation génère normalement ces scripts correctement à condition que vous lui fournissiez votre login et votre mot de passe. Les opérations de connexion/déconnexion peuvent être automatisées à l'aide des scripts startadsl et stopadsl. Le script startmire permet de se connecter à la mire ADSL de France télécom afin de tester la connexion ADSL. Il faut également utiliser la commande stopadsl pour se déconnecter de la mire. Remarques : L'ordre des opérations est important. Le code du driver et d'adictrl a été modifié pour empêcher les mauvaises manipulation. En particulier, il est impossible de recharger les options ou le code du DSP dans le modem tant que l'interface réseau est montée. Le débranchement du modem provoque la disparition de l'interface réseau. Les scripts de connexions automatique doivent donc en tenir compte. V. Fonctionnement Je décris dans cette section ce que j'ai compris du fonctionnement du driver. Cette description n'est peut-être pas très précise ni rigoureusement exacte, mais elle permettra peut-être aux personnes désirant modifier ou améliorer le driver d'en comprendre plus rapidement l'architecture. Le driver est un driver de périphérique USB prenant en charge les modems ADSL USB basés sur le chipset Eagle 8051 d'Analog. Les périphériques sont identifiés par la liste des identifiants de vendeurs et de périphérique déclarés dans le fichier AdiUsbAdsl.h. La liste des périphériques est déclarée dans le fichier AdiUsbAdsl.c pour que depmod puisse les localiser. Ces périphériques disposent de deux identifiants (ce qui apparemment est classique dans le monde USB), le premier correspondant au périphérique sans firmware chargé, et le deuxième au périphérique avec firmware. Lorsque les périphériques de chaque type sont détectés par le système, la fonction adi_probe est appelée pour déterminer si le module les prend en charge. Le module gère les périphériques sans firmware simplement en leur envoyant leur firmware. Une fois le firmware chargé, le périphérique disparaît et réapparaît sous son deuxième identifiant. C'est là que les opérations intéressantes sont faites. Le module commence par sélectionner la bonne configuration USB et initialise ses structures de données (état du modem et buffers de réception). Puis il charge le code du DSP dans le modem et l'initialise. Lorsque cette initialisation est terminée, les scripts clients peuvent créer une interface réseau de type Ethernet par laquelle les programmes pppoa et pppoe pourront envoyer et recevoir leurs paquets. À noter que la disparition du périphérique implique la destruction de l'interface réseau automatiquement. J'ignore complètement ce qui se passe du côté des programmes clients à ce moment. De toutes façons, débrancher le modem en cours d'utilisaiton ne constitue normalement pas un cadre d'utilisation normal. L'outil de configuration adictrl communique avec le module par l'intermédiaire des fichiers spéciaux de périphériques créés dans le système de fichiers usbdevfs. Pour cela, il recherche les périphériques qu'il peut contrôler dans le répertoire /proc/bus/usb, qui contient un sous-répertoire par bus USB. Lorsque le périphérique cible est localisé, une commande ioctl est envoyée pour passer ou récupérer les informations du module. La liste des commandes ioctl prises en charge par le module est déclarée dans le fichier AdiUsbAdsl.h. Entre autres opérations, adictrl permet de charger le firmware, le mode de fonctionnement et le code du DSP à charger dans le modem. Le mode de fonctionnemnet indique principalement l'encapsulation utilisée pour envoyer et recevoir les paquets, ainsi que les canaux VPI/VCI ATM utilisé par le fournisseur d'accès. Le code du DSP quant à lui est le programme qui permet au modem de communiquer avec le module d'un côté et avec le terminal ADSL de l'autre. La communication avec le terminal ADSL se fait en ATM (Asynchronous Transfer Mode). Le code du DSP est envoyé dès que possible au modem. Apparemment, ce code est trop volumineux pour tenir dans le modem (ou pour être chargé en une seule étape), il est donc découpé en pages (elles-mêmes découpées en "blocs") qui peuvent être demandées par le modem de manière asynchrone. Le code de chargement doit donc être traité en partie dans l'interruption de traitement des événements provenant du modem. Cette interruption est donc installée juste avant l'envoi du code du DSP, qui consiste en fait à envoyer la première page du DSP. Cette interruption est gérée en câblant un URB (en gros une requête d'entrée / sortie USB) sur une des interfaces USB du modem. Cette interruption gère également les notifications de changement d'état du modem. Son point d'entrée dans le module est la fonction adi_irq. L'amorçage du modem se fait dans la fonction BootTheModem (fichier Boot.c). Une fois le modem booté, son état est susceptible d'évoluer le temps qu'il se synchronise / resynchronise. La gestion des états du modem est prise en charge dans les fichiers Sm.c et Me.c (Sate machine et Management entity respectivement). Les chanbements d'état sont captés par le code de l'ISR du module (Interrupt Service Routine). Le code de gestion de l'état du modem contient un timer qui a pour but de vérifier régulièrement si le modem est vivant. Dans le cas contraire, le modem est rebooté par le driver, ce qui provoque la relecture des pages du DSP. Le module conserve donc en permanence les pages du DSP en mémoire (500 Ko environ). Un code ioctl permet de synchroniser les processus utilisteurs avec l'état du modem. Lorsque le modem est synchronisé, ces processus peuvent communiquer avec l'interface Ethernet du module. La manière de procéder est toujours la même : il faut ouvrir l'interface en mode packet, c'est à dire de telle sorte à pouvoir lire et écrire les paquets Ethernet directement. Pour cela, il faut bien sûr être dans le compte root. Les outils pppoa et pppoe font exactement cela : ils communiquent avec le démon pppd par leur flux d'entrée et de sortie d'un côté, et avec l'interface réseau de l'autre côté. La différence entre ces deux outils réside dans l'encapulation utilisée pour envoyer les paquets PPP au point d'accès du fournisseur d'accès (le "peer"). Les paquets en émission sont donc encapsulés dans une trame Ethernet étendue d'informations complémentaires. Ces informations sont dépendantes du type d'encapsulation utilisé. Grosso modo, l'encapsulation pppoa est plus légère que celle utilisée par pppoe. Les paquets Ethernet sont également traités au niveau de l'interface réseau de manière spécifique en fonction de l'encapsulation utilisée. En gros, les paquets de type pppoe sont transmis tels quels à la couche ATM, avec les en-têtes Ethernet. Les paquets pppoa en revanche sont "nettoyés" de leurs en-têtes Ethernet et sont donc plus petits. Le module utilise un buffer de réception constitué de plusieurs URBs en lecture. Ces URBs sont câblés sur l'interface des données du modem et sont traitées par une fonction de réception de données appelée en asynchrone par les couches USB. Toutefois, ce traitement est effectué de manière synchrone dans le contexte d'appel du driver USB. Le traitement des données en entrée est réalisé dans le fichier Pipes.c. Grâce à ce buffer, les données peuvent arriver plus vite que le module ne peut les traiter. Dès qu'une donnée est arrivée, la fonction de réception récupère les données dans l'URB qui lui est fourni en paramètre et envoie ces données au code de désencapsulation ATM (fonction UniProcessInboundData). Lorsque les données sont reconstituées par le code ATM du module, la fonction ReadSendItUp du fichier Pipes.c est appelée. Cette fonction effectue le traitement adéquat pour reconstituer les paquets Ethernet. Pour l'encapsulation pppoe, ce traitement consiste à analyser l'en-tête Ethernet reçu de la couche ATM, et pour l'encapsulation pppoa, elle consiste à reconstruire un en-tête virtuel (puique l'encapsulation pppoa fait l'économie de ces en-têtes). Une fois ces traitements effectués, le paquet Ethernet est retransmis directement aux couches réseau supérieures de Linux via la méthode netif_rx de Linux. Le noyau les achemine alors vers pppoa ou pppoe (ceux-ci retirant leur propre encapsulation et transmettant ensuite les paquets PPP à pppd). Le code ATM du module n'a pas été analysé. Il semble que ce soit un code de découpage de paquets conforme au protocole AAL5. Il réalise donc (encore) une encapsulation des données fournies par l'interface réseau du module pour les placer dans des cellules ATM. À noter que l'encapsulation AAL5 se fait en plusieurs endroits : premièrement les en-têtes permettant de définir l'encapsulation utilisée sont traités dans le fichier Mpoa.c, puis le découpage en cellules est réalisé dans les fichiers Uni.c et Sar.c. On notera ici aussi qu'outre le transfert complet des paquets Ethernet, l'encodage AAL5 ajoute un en-tête de 10 octets pour le protocole PPPoE (à prendre sur la bande passante), alors que l'encodage pour le protocole PPPoA / VC ne prend rien. En clair, l'encapsulation PPPoA revient à dire que les paquets PPP sont transmis directement à la couche ATM, via un petit détour par l'interface Ethernet du module. L'encapsulation PPPoE se fait au niveau de pppoe lui-même, et les paquets Ethernet ainsi générés sont envoyés (avec leur en-tête et tout et tout) à la couche ATM. Il s'agit donc de "PPPoEoA" (PPP over Ethernet over ATM). Cela implique un MTU (Maximum Transmit Unit) plus faible au niveau du démon pppd. Si je ne me suis pas trompé dans mes calculs, pppoa utilise 14 octets d'en-tête Ethernet + 2 octets d'encapsulation, soit un MTU de 1500 - 2 = 1498 (les paquets Ethernet faisant 1514 octets au maximum). pppoe quant à lui utilise 6 octets d'encapsulation, ce qui donne un MTU de 1494. À ces octets d'encapsulation, il faut ajouter deux octets d'en-tête ajoutés par PPP (pour les deux protocoles), ce qui fait respectivement un MTU de 1496 et 1492. De plus, le protocole PPPoA n'utilise pas d'octets d'encapsulation au niveau ATM alors que le protocole PPPoE en utilise 10. Je recommande donc l'utilisation du protocole PPPoA, car c'est celle qui consomme le moins de bande passante (au détriment d'une reconstitution d'en-tête Ethernet à la réception, les deux protocoles construisant ces en-têtes à l'émission). La différence théorique entre les deux protocoles est a priori de 1.9% (un paquet de 1492 octets est transféré en 1514+10=1524 octets avec PPPoE, soit 32 octets de frais ; PPPoA ne réclame que 4 octets de frais, la différence est donc de 28 octets pour 1492, qu'il faut corriger d'un facteur 1496/1492 en raison du MTU plus faible de PPPoE). Là, j'ai environ 50% de chances de me planter et de raconter n'importe quoi. Voilà voilà... Bon surf, C. Casteyde (casteyde.christian@free.fr)