Hi,

I have modified the XO activation initramfs to attempt to locate a
lease server on an XS on each open infrastructure network that can be
found (early patch attached).

The XS does not bind the server to the IPv6 address correctly (perhaps
we can work on that)., so it currently runs over IPv4

But assuming we want a working IPv4 implementation... we need to
figure out a way of getting the XOs to address themselves in a way
compatible with the school server. The current IPv4 code picks an
address (randomly) at 172.18.16.xx and this does not work with the XS.
I also am quite confused by the XS network interface setting.

We need to choose an appropriate address range which the XOs can
suitably randomly assign themselves in, not covered by DHCP leases,
and make sure that an appropriate interface is "listening" (at least
acting as a gateway) on the XS. At the moment I am using 172.18.1.x
which seems to be free of dhcp assignments.

Thoughts?
Daniel
From: Daniel Drake <d...@laptop.org>

diff --git a/src-olpc/activate.py b/src-olpc/activate.py
index f21b30d..f9b27e7 100644
--- a/src-olpc/activate.py
+++ b/src-olpc/activate.py
@@ -6,10 +6,14 @@ from initutil import blk_mounted, SD_DEV, SD_MNT, USB_DEV, USB_MNT
 from initutil import sd_init, usb_init, net_init
 from socket import *
 from ipv6util import if_nametoindex
+import subprocess
 from subprocess import check_call, call
 sys.path += [ '/act-gui' ] # gui_client is in a subdir
 from gui_client import send
 
+#def send(foo):
+#    print "would send:", foo
+
 def try_blk(device, mnt, fstype='msdos'):
     """Try to mount a block device and read keylist from it."""
     try:
@@ -19,25 +23,60 @@ def try_blk(device, mnt, fstype='msdos'):
     except:
         return None
 
-def select_network_channel (channel):
-    check_call(['/sbin/iwconfig','eth0','mode','ad-hoc','essid','dontcare'])
-    check_call(['/sbin/iwconfig','msh0','channel',str(channel)])
-    check_call(['/bin/ip','link','set','dev','msh0','up']) # rely on ipv6 autoconfig
+def set_addresses (iface):
     # set up link-local address
-    mac = open('/sys/class/net/msh0/address').read().strip().split(':')
+    mac = open('/sys/class/net/%s/address' % iface).read().strip().split(':')
     top = int(mac[0], 16) ^ 2 # universal/local bit complemented
     ll = 'fe80::%02x%s:%sff:fe%s:%s%s' % \
          (top, mac[1], mac[2], mac[3], mac[4], mac[5])
-    call(['/bin/ip', 'addr', 'add', '%s/64' % ll, 'dev', 'msh0'])
+    call(['/bin/ip', 'addr', 'add', '%s/64' % ll, 'dev', iface])
     a = 2+(ord(os.urandom(1)[0])%250)
-    call(['/bin/ip', 'addr', 'add', '172.18.16.%d' % a, 'dev', 'msh0'])
+    call(['/bin/ip', 'addr', 'add', '172.18.1.%d/24' % a,
+          'brd', '172.18.1.255', 'dev', iface])
     # XXX: BSSIDs of all 0, F, or 4 are invalid
-    # set up route to 172.18.0.1
-    call(['/bin/ip', 'route', 'add', '172.18.0.0/23', 'dev', 'msh0'])
-    call(['/bin/ip', 'route', 'add', 'default', 'via', '172.18.0.1'])
+    call(['/bin/ip', 'route', 'add', 'default', 'via', '172.18.1.1', 'dev', iface])
     # should be able to ping 172.18.0.1 after this point.
     # the IPv4 address is a little hacky, prefer ipv6
 
+def select_mesh_channel (channel):
+    check_call(['/sbin/iwconfig','eth0','mode','ad-hoc','essid','dontcare'])
+    check_call(['/sbin/iwconfig','msh0','channel',str(channel)])
+    check_call(['/bin/ip','link','set','dev','msh0','up']) # rely on ipv6 autoconfig
+    set_addresses('msh0')
+
+def select_ibss (ssid):
+    print "attempting connection to open IBSS", ssid
+    check_call(['/bin/ip','link','set','dev','eth0','up']) # rely on ipv6 autoconfig
+    check_call(['/sbin/iwconfig','eth0','mode','managed','essid',ssid])
+
+    # wait for association, max 5 secs
+    for i in range(0, 10):
+        time.sleep(0.5)
+        output = subprocess.Popen(["/sbin/iwconfig", "eth0"],
+                                  stdout=subprocess.PIPE).communicate()[0]
+        lines = output.split("\n")
+        if len(lines) < 2:
+            print "bad iwconfig output?"
+            return False
+
+        ssidpos = lines[0].index("ESSID:")
+        iw_ssid = lines[0][ssidpos + 6:].strip()
+        if iw_ssid != '"' + ssid + '"':
+            if iw_ssid != '""':
+                print "unexpected ESSID value:", iw_ssid
+            continue
+
+        appos = lines[1].find("Access Point: ")
+        if appos == -1:
+            continue
+        iw_ap = lines[1][appos+14:].strip()
+        if iw_ap[0].isdigit():
+            print "connected!"
+            set_addresses("eth0")
+            return True
+
+    return False
+
 def try_to_get_lease(family, addr, serial_num):
     s = socket(family, SOCK_STREAM)
     try:
@@ -55,23 +94,87 @@ def try_to_get_lease(family, addr, serial_num):
     finally:
         s.close()
 
-def try_network (channel, serial_num):
+def contact_lease_server (iface, serial_num):
+    # try to contact the lease server
+    for family, addr in [ (AF_INET6,('fe80::abcd:ef01',191,
+                                     0, if_nametoindex(iface))),
+                          (AF_INET, ('172.18.0.1',191)), ] * 4:
+        try:
+            l = try_to_get_lease(family, addr, serial_num)
+            if l is not None:
+                return l
+        except:
+            pass
+    return None # unsuccessful
+
+def try_mesh_network (channel, serial_num):
     """Try to get a keylist from the server on the given wireless channel."""
-    select_network_channel(channel)
+    select_mesh_channel(channel)
     try:
         time.sleep(4) # let network settle down
-        # try to contact the school server.
-        for family, addr in [ (AF_INET6,('fe80::abcd:ef01',191,
-                                         0, if_nametoindex('msh0'))),
-                              (AF_INET, ('172.18.0.1',191)), ] * 4:
-            try:
-                l = try_to_get_lease(family, addr, serial_num)
-                if l is not None: return l
-            except: pass
-        return None # unsuccessful.
+        return contact_lease_server('msh0', serial_num)
     finally:
         call(['/bin/ip','link','set','dev','msh0','down'])
 
+def try_ibss_network (ssid, serial_num):
+    """Try to get a keylist from the server on a given IBSS network."""
+    try:
+        associated = select_ibss(ssid)
+        if associated:
+            time.sleep(4) # let network settle down
+            return contact_lease_server('eth0', serial_num)
+        else:
+            return None
+    finally:
+        call(['/bin/ip','link','set','dev','eth0','down'])
+
+def _find_open_ibss_nets(iface):
+    output = subprocess.Popen(["/sbin/iwlist", iface, "scan"], stdout=subprocess.PIPE).communicate()[0]
+    nets = []
+    this_essid = ""
+
+    for line in output.split("\n"):
+        line = line.strip()
+
+        if line.startswith("ESSID:\""):
+            this_essid = line[7:-1]
+            continue
+
+        if line.startswith("Mode:"):
+            if line != "Mode:Master" and line != "Mode:Managed":
+                # ignore non-IBSS networks
+                this_essid = ""
+            continue
+
+        if line == "Encryption key:off":
+            if len(this_essid) > 0:
+                if this_essid not in nets:
+                    nets.append(this_essid)
+                this_essid = ""
+
+    return nets
+
+def find_open_ibss_nets (iface="eth0"):
+    """
+    Scans for networks and returns list of SSIDs for open IBSSs
+    """
+
+    check_call(['/bin/ip','link','set','dev','eth0','up'])
+    try:
+        return _find_open_ibss_nets(iface)
+    finally:
+        call(['/bin/ip','link','set','dev','eth0','down'])
+
+
+def check_stolen(keylist):
+    if keylist != 'STOLEN':
+        return False
+
+    send('wireless fail')
+    send('wireless stolen')
+    send('stolen')
+    send('freeze 1')
+    return True
 
 def activate (serial_num, uuid):
     """Try to perform activation.
@@ -129,23 +232,33 @@ def activate (serial_num, uuid):
         try:
             send('wireless start')
             net_init()
+
+            candidates = find_open_ibss_nets()
+            print "open IBSS candidates:", candidates
+            for ssid in candidates:
+                keylist = try_ibss_network(ssid, serial_num)
+                if not keylist:
+                    continue
+                if check_stolen(keylist):
+                    return None
+                try:
+                    # return minimized lease
+                    return find_lease(serial_num, uuid, keylist)
+                except:
+                    continue
+
             for chan in [1, 6, 11, 1, 6, 11]:
                 send('wireless state '+str(chan))
-                keylist = try_network(chan, serial_num)
+                keylist = try_mesh_network(chan, serial_num)
                 if keylist:
                     send('wireless success')
-                    if keylist == 'STOLEN':
-                        send('wireless fail')
-                        send('wireless stolen')
-                        send('stolen')
-                        send('freeze 1')
+                    if check_stolen(keylist):
                         return None # machine's been reported STOLEN!
                     try:
                         # return minimized lease
                         return find_lease(serial_num, uuid, keylist)
                     except:
-                        send('wireless fail')
-                        send('wireless lock')
+                        continue
             else:
                 send('wireless fail')
         except:
_______________________________________________
Server-devel mailing list
server-de...@lists.laptop.org
http://lists.laptop.org/listinfo/server-devel

Reply via email to