Artisan Numérique

/vintage/zaurus/usb/ Connecter le Zaurus à Internet via l'USB

Un Zaurus c'est bien mais avec le réseau c'est un peu plus sympa. Surtout pour télécharger les feeds. Avec un câble usb et Linux à l'autre bout cela se fait très facilement.

Établissement de la connexion entre PC et Zaurus

Déjà première chose, il faut brancher le câble USB entre le Zaurus et le PC :) Une fois connecté, la commande dmesg doit nous donner ceci:

gastondmesg
(...)
usb 4-2: new full speed USB device using uhci_hcd and address 25
usb 4-2: device not accepting address 25, error -71
usb 4-2: new full speed USB device using uhci_hcd and address 26i

Et la commande lsusb ceci :

gastonlsusb
Bus 004 Device 026: ID 04dd:9031 Sharp Corp. Zaurus C-750/C-760 PDA

Cela nous indique que la connexion USB est effective.Le modèle du Zaurus est dans mon cas faux (j'utilise un C-1000) mais peu importe.

Ensuite pour que le PC/Linux reconnaisse le réseau via l'usb, nous devons charger le module usbnet, s'il est déjà chargé la commande vous préviendra :

gastonmodprobe usbnet

Ensuite, la commande dmesg permet de savoir si tout c'est bien passé.

gastondmesg
(...)
usb0: register usbnet at usb-0000:00:1d.3-2, pseudo-MDLM (BLAN) device, 0e:8a:e8:28:5a:6c
usbcore: registered new driver usbnet

Mise en place du sous-réseau

Le but maintenant est de configurer un autre réseau local entre le PC et le Zaurus. Dans la mesure où pdaXrom est paramétré pour automatiquement affecter l'IP 192.168.129.201 au Zaurus lors d'une connection USB, nous allons tout logiquement placer la deuxième IP du PC à 192.168.129.1 toujours sur un masque réseau 255.255.255.0 (comme cela vous pouvez connecter 253 autre Zaurus ;-).

Nous allons tout d'abord vérifier que le Zaurus a bien une interface usb0 existant avec la bonne ip (ne pas oublier le d d'usbd0):

gastonifconfig usbd0
usbd0   Link encap:Ethernet  HWaddr 40:00:01:00:00:01
inet addr: 192.168.129.201  Bcast:192.168.129.255  Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:2049 errors:0 dropped:0 overruns:0 frame:0
TX packets:2532 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:384221 (375.2 Kb)  TX bytes:3040416 (2.8 Mb)

Si cela ne donne pas ce résultat, nous avons un souci.

A ce stade, l'interface usbd0 du Zaurus est active avec une IP mais pas l'interface usb0 du PC. Attention cependant, ce n'est pas vrai sur toutes les distributions Linux. Cetaines font comme le Zaurus et montent automatiquement usb0 dés la détection du câble. Nous allons donc prendre nos précautions et commencer par éteindre l'interface usb0 avant de la rallumer avec la bonne IP :

gastonifconfig usb0 down
ifconfig usb0 192.168.129.1 netmask 255.255.255.0 up

Maintenant, quel qu'ait été l'état d'origine la commande suivante devrait fonctionner comme suit :

gastonifconfig usb0
usb0      Link encap:Ethernet  HWaddr 2A:9C:AB:A1:BF:83
inet adr:192.168.129.1  Bcast:192.168.129.255  Masque:255.255.255.0
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:2488 errors:0 dropped:0 overruns:0 frame:0
TX packets:1969 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 lg file transmission:1000
RX bytes:3009859 (2.8 MiB)  TX bytes:413703 (404.0 KiB)

Si c'est bien le cas tout va bien. Pour rendre cela plus propre, nous allons ajouter une route pour indiquer que les paquets passant par usb0 sont à destination du Zaurus :

gastonroute add -host 192.168.129.201 usb0

Et du côté du Zaurus, indiquer la bonne route vers le PC (passerelle par défaut):

gastonroute add default gw 192.168.129.1

Maintenant que nous avons une IP des deux côtés, il devrait être possible que les deux machines se "ping" mutuellement. Du PC vers le Zaurus :

gastonping 192.168.129.201
PING 192.168.129.201 (192.168.129.201) 56(84) bytes of data.
64 bytes from 192.168.129.201: icmp_seq=1 ttl=64 time=1.27 ms
64 bytes from 192.168.129.201: icmp_seq=2 ttl=64 time=1.90 ms
(...)

Puis du Zaurus vers le PC :

gastonping 192.168.129.1
PING 192.168.129.1 (192.168.129.1): 56 octets data
64 octets from 192.168.129.1: icmp_seq=0 ttl=64 time=7.3 ms
64 octets from 192.168.129.1: icmp_seq=1 ttl=64 time=1.2 ms
(...)

Voilà, deuxième étape réussie, les deux engins causent.

Connexion du Zaurus à Internet

Avant de commencer un peu de topologie. Je pars ici du principe que votre PC est normalement déjà connecté à Internet, relié à un routeur/modem adsl avec une liaison ethernet. La carte réseau dédié à cette liaison est appelé par la suite eth0. Le Modem/routeur et votre PC forment un réseau local sur la plage d'IP 192.168.1.0 / 255.255.255.0. L'adresse du PC est 192.168.1.2 et celle du routeur 192.168.1.1. Avant de poursuivre, vous devez connaitre ces deux IP dans votre cas, de même que le numéro de la carte réseau (ici eth0).

Tout d'abord il nous faut le paquet "iptables". Taper "iptables" en tant que root pour vérifier et l'installer le cas échéant (sous mandriva "urpmi iptables").

Maintenant, nous allons utiliser iptables pour permettre au sous réseau de communiquer avec notre routeur. Pour commencer, nous allons nétoyer la table NAT :

gastoniptables  -t nat -F

Puis nous allons substituer l'addresse de notre PC aux adresses sources des paquets sortants du lan Zaurus-PC :

gastoniptables  -t nat -A POSTROUTING -j SNAT -o eth0 --to 192.168.1.2

Ceci fait, toutes les paquets du Zaurus sont routées vers le PC. Il faut maintenant indiquer au PC de router ces paquets vers sa passerelle, et donc, vers internet.

gastonecho 1 > /proc/sys/net/ipv4/ip_forward

Si l'appel à iptable ne passe pas, vous pouvez faire à peu prés la même chose par :

gastoniptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE -s 192.168.129.210/32

Normalement, à ce stade, il est possible de "pinger" votre routeur du Zaurus

gastonping 192.168.1.1

PING 192.168.1.1 (192.168.1.1): 56 octets data
64 octets from 192.168.1.1: icmp_seq=0 ttl=254 time=6.0 ms

C'est presque gagné, il ne reste plus qu'à fournir au Zaurus le serveur de noms (DNS). La solution la plus simple, dans la mesure où votre PC et le Zaurus accèdent au Net de la même manière est de recopier le fichier /etc/resolv.conf dans le fichier équivalent sur le Zaurus.

Maintenant pour vérifier que le Zaurus a bien accès au net :

gastonping www.free.fr

PING www.free.fr (212.27.48.10): 56 octets data
64 octets from 212.27.48.10: icmp_seq=0 ttl=117 time=21.2 ms
(...)

Et voilà, c'est gagné :)

Automatisation avec udev

Tout ceci vu, il est assez simple de faire un script pour automatiser cela. Cependant, il nous reste deux problèmes. Tout d'abord comment faire pour que l'usb0 soit monté et configuré automatiquement à chaque connection du Zaurus. Sur ce point, c'est Dab qui a éclairé ma lanterne avec son script qui utilise udev - beaucoup plus simple que ma version ivman.

Sans rentrer dans les méandres d'udev, nous dirons qu'il permet de répondre au même besoin d'hotplug, c'est à dire détecter l'arrivée d'un périphérique et d'effectuer des actions en fonction. Il s'agit d'un démon (udevd) qui va lire une base de règles en /etc/udev/rules.d. Ce dossier contient des fichiers et chaque fichier une série de règles.

Une règle consiste à définir des critères à vérifier avant d'effectuer une action. En effet, lorsque l'on connecte le Zaurus, une interface USB est montée et udev peut en extraire des informations. Une de ces informations est le modèle du Zaurus connecté (SL-C1000 dans mon cas). Ainsi nous pouvons écrire une règle du type

ACTION=="add", SUBSYSTEM=="usb", SYSFS{product}=="SL-C1000", RUN+="/usr/bin/zaurus"

Ce qui consiste à dire à udev de lancer le script /usr/bin/zaurus à chaque détection (ajout en fait) d'un périphérique usb du nom de SL-C1000. Dans le même esprit on peut écrire une règle de suppression pour faire le ménage. Mais là les choses se corsent un peu. En effet, lorsque l'on retire la prise, udev n'est plus en mesure de connaître le modèle qui y était connecté. Il faudra donc penser lors de l'ajout à noter sur le disque le chemin du périphérique pour vérifier que c'est bien lui que l'on retire. La règle de suppression est donc très vague :

ACTION=="remove", SUBSYSTEM=="usb", RUN+="/usr/bin/zaurus"

Elle est appelée à chaque retrait d'un périphérique USB et c'est le script qui va vérifier que c'est bien le Zaurus que l'on retire.

Gérer les noms avec dhcps

Comme je le disais plus haut, il y a deux problèmes avec notre automatisation. Le premier est maintenant réglé, reste celui du DNS. En effet, comment faire pour que le Zaurus sache résoudre les noms en IP. Nous pourrions rentrer cela en dur dans le Zaurus (en /etc/resolv.conf) mais l'inconvénient c'est que cela ne marchera pas au bureau comme chez vous. La vraie bonne solution est l'utilisation d'un serveur DNS "à la volée". En effet, dans la mesure ou l'interface usb0 n'existe sur le PC QUE lorsque le Zaurus est connecté, nous ne pouvons pas laissé un serveur dhcp actif sur une interface réseau qui n'existe pas. Il faut donc lancer le serveur après la création d'usb0 et le détruire lorsque usb0 disparaît.

Autre petit point à régler, le Zaurus doit être configuré de sorte à chercher un serveur DHCP à chaque connexion du câble. Ce point se règle très facilement en modifiant comme suit le fichier /etc/hotplug/usbdnet.conf :

DHCPS=no
DHCPC=yes

Ainsi le client DHCP du Zaurus s'activera à la prochaine connection.

Le script terminé...

Voilà le résultat de ce long périple avec ce script qui en reprends toutes les étapes (à placer par exemple en /sbin :

#!/bin/sh
# Script de connexion usb pour le Zaurus
# Auteur: site.artisan@ _bad_karma-lab.net (enlever le bad_)
# Version: 3.0
# Avec l'aide de Sieur Dab
# Licence GPL

# configuration de la connexion
dhcpd_conf=/tmp/dhcpd-zaurus.conf
dhcpd_leases=/tmp/dhcpd-zaurus.leases
dhcpd_pid=/tmp/dhcpd-zaurus.pid
SYSCONFIG="/etc/sysconfig/zaurus"
[ -f $SYSCONFIG ] && . $SYSCONFIG
[ ! $HOST_IP ] && HOST_IP="192.168.129.1"
[ ! $ZAURUS_IP ] && ZAURUS_IP="192.168.129.201"
[ ! $HOST_IF ] && HOST_IF="eth0"
[ ! $DHCPC ] && DHCPC="yes"
PATH=$PATH:/sbin:/usr/bin:/usr/sbin
export PATH

# petite notification
notify()
{
mplayer -ao alsa -quiet /usr/share/sounds/KDE_Pop.ogg 2> /dev/null 1> /dev/null
  logger -t zaurus "$1"
  }

  killDhcp()
  {
  if [ -f $dhcpd_pid ] ; then
  kill -9 `cat $dhcpd_pid`
  fi
  }

  runDhcp()
  {
  killDhcp
  unset nameServers
  for dns in `cat /etc/resolv.conf  | grep nameserver | cut -d" " -f2` ; do
  if [ ! $nameServers ] ; then
  nameServers=$dns
  else
  nameServers="$dns, $nameServers"
  fi
  done
  IP1=`echo $HOST_IP | cut -d. -f1`
  IP2=`echo $HOST_IP | cut -d. -f2`
  IP3=`echo $HOST_IP | cut -d. -f3`
  IP4=`echo $HOST_IP | cut -d. -f4`
  echo "ddns-update-style none;" > $dhcpd_conf
subNet=$IP1.$IP2.$IP3
echo "subnet $subNet.0 netmask 255.255.255.0 {" >> $dhcpd_conf
  echo "local-address $HOST_IP;" >> $dhcpd_conf
  echo "option routers $HOST_IP;" >> $dhcpd_conf
  echo "option subnet-mask 255.255.255.0;" >> $dhcpd_conf
  echo "option domain-name-servers $nameServers;" >> $dhcpd_conf
  echo "range dynamic-bootp $ZAURUS_IP $ZAURUS_IP;" >> $dhcpd_conf
  echo "default-lease-time 600;" >> $dhcpd_conf
  echo "max-lease-time 7200;" >> $dhcpd_conf
  echo "}" >> $dhcpd_conf
  > $dhcpd_leases
initlog -c "dhcpd -cf $dhcpd_conf -lf $dhcpd_leases -pf $dhcpd_pid usb0"
}

sendDns()
{
# paramétrage du zaurus pour le dns
zaurusScript="
cat > /etc/resolv.conf ;
typeset -i num ;
num=\`route | grep $HOST_IP | wc -l\` ;
if [ \$num -eq 0 ] ; then
route add default gw $HOST_IP ;
fi"
cat /etc/resolv.conf | ssh root@zaurus "$zaurusScript"
}

# Zaurus connecté
connected()
{
if [ $MODALIAS ] ; then
exit;
fi
echo $DEVPATH > /tmp/zaurusDevPath
modprobe usbnet

# montage d'usb0
ifconfig usb0 down
ifconfig usb0 $HOST_IP netmask 255.255.255.0 mtu 1000 up
route add -host $ZAURUS_IP usb0

# paramétrage du routage
iptables  -t nat -F
# Si cette ligne ne passe pas, la commenter et décommenter la suivante :
# iptables -t nat -A POSTROUTING -j SNAT -o $interface_internet --to `host $HOSTNAME | cut -d" " -f 4`
iptables -t nat -A POSTROUTING -o $HOST_IF -j MASQUERADE -s $ZAURUS_IP/32
echo 1 > /proc/sys/net/ipv4/ip_forward

if [ "$DHCPC" == "yes" ] ; then
runDhcp
else
sendDns
fi
notify "Le Zaurus est connecté"
return $RETVAL
}


# Zaurus déconnecté
disconnected()
{
oldPath=`cat /tmp/zaurusDevPath`
if [ $oldPath == $DEVPATH ] ; then
notify "Le Zaurus est déconnecté"
killDhcp
ifconfig usb0 down
iptables -t nat -F
echo 0 > /proc/sys/net/ipv4/ip_forward
rmmod usbnet
fi
return $RETVAL
}

# Stock la variable dans la config
store()
{
variableName=$2
default=${!variableName}
echo -n "$1 [$default] ou 'Enter' :"
read data
if [[ ! $data ]]; then
data=$default;
fi
echo "$variableName=$data" >> $SYSCONFIG
  }

  # installation udev
  install()
  {
  > $SYSCONFIG

store "Interface d'acces a Internet" HOST_IF
store "Adresse IP usb0 du PC" HOST_IP
store "Adresse IP usb0 du Zaurus" ZAURUS_IP
store "Paramétrage via dhcpd" DHCPC


if [ ! $ZAURUS ] ; then
for vendor in `find /sys -name "idVendor"` ; do
if [ `cat $vendor` == "04dd" ] ; then
path=`dirname $vendor`
product=`cat $path/product`
if [ `echo $product | grep "^SL-"` ] ; then
ZAURUS=$product
fi
fi
done
fi
store "Votre type de Zaurus" ZAURUS
. $SYSCONFIG
echo "ACTION==\"add\", SUBSYSTEM==\"usb\", SYSFS{product}==\"$ZAURUS\", RUN+=\"$0\"" > /etc/udev/rules.d/00-zaurus.rules
echo "ACTION==\"remove\", SUBSYSTEM==\"usb\", RUN+=\"$0\"" >> /etc/udev/rules.d/00-zaurus.rules
  /sbin/udevrulescompile
  /etc/rc.d/init.d/udev restart
  }

  if [ "$1" != "usb" ] ; then
  ACTION=$1
  fi

  case "$ACTION" in
  add)
  connected
  ;;
  remove)
  disconnected
  ;;
  install)
  install
  ;;
  *)
  echo "Error with $ACTION"
  echo "ACTION {add|remove|install}\n"
  exit 1
  esac

  exit $?

Première chose à faire, lancer le script en mode paramétrage :

gaston/sbin/zaurus install

Une fois fait, un fichier de configuration a été créé en /etc/sysconfig/zaurus. Les règles udev ont été écrites en /etc/udev/rules.d/00-zaurus.rules et udev est normalement redémarré. Il ne reste plus qu'à brancher et faire la traditionnelle prière à Ste Gretta pour que tout fonctionne comme prévu.