Ticket #230: 0001-Add-OLPC-mesh-support-230.2.patch
File 0001-Add-OLPC-mesh-support-230.2.patch, 35.2 KB (added by dsd, 13 years ago) |
---|
-
extensions/deviceicon/network.py
From 9225172b62f9bc7b1c7e006a23a81383d578d212 Mon Sep 17 00:00:00 2001 From: Daniel Drake <dsd@laptop.org> Date: Thu, 24 Dec 2009 16:28:01 +0000 Subject: [PATCH] Add OLPC mesh support (#230) This is supported in NetworkManager-0.8. The behaviour is designed to mimic XO-1, except it does not look for mesh portals other than the school server. --- extensions/deviceicon/network.py | 164 +++++++++++++++++++++++++-- src/jarabe/desktop/meshbox.py | 230 ++++++++++++++++++++++++++++++++++++-- src/jarabe/model/Makefile.am | 1 + src/jarabe/model/network.py | 32 +++++- src/jarabe/model/olpcmesh.py | 198 ++++++++++++++++++++++++++++++++ 5 files changed, 600 insertions(+), 25 deletions(-) create mode 100644 src/jarabe/model/olpcmesh.py diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py index 3c17253..ba72d04 100644
a b from sugar.graphics.toolbutton import ToolButton 35 35 from sugar.graphics.tray import TrayIcon 36 36 from sugar.graphics import xocolor 37 37 from sugar.util import unique_id 38 from sugar import profile 38 39 39 40 from jarabe.model import network 40 41 from jarabe.model.network import Settings … … _NM_PATH = '/org/freedesktop/NetworkManager' 50 51 _NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device' 51 52 _NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired' 52 53 _NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless' 54 _NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh' 53 55 _NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint' 54 56 _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' 55 57 … … class WirelessPalette(Palette): 81 83 gobject.TYPE_NONE, ([])), 82 84 } 83 85 84 def __init__(self, primary_text ):86 def __init__(self, primary_text, can_create=True): 85 87 Palette.__init__(self, label=primary_text) 86 88 87 89 self._disconnect_item = None … … class WirelessPalette(Palette): 112 114 self._disconnect_item.connect('activate', self.__disconnect_activate_cb) 113 115 self.menu.append(self._disconnect_item) 114 116 115 self._adhoc_item = gtk.MenuItem(_('Create new wireless network')) 116 self._adhoc_item.connect('activate', self.__adhoc_activate_cb) 117 self.menu.append(self._adhoc_item) 118 self._adhoc_item.show() 117 if can_create: 118 self._adhoc_item = gtk.MenuItem(_('Create new wireless network')) 119 self._adhoc_item.connect('activate', self.__adhoc_activate_cb) 120 self.menu.append(self._adhoc_item) 121 self._adhoc_item.show() 119 122 120 123 def set_connecting(self): 121 124 self.props.secondary_text = _('Connecting...') 122 125 123 def set_connected(self, frequency, iaddress):126 def _set_connected(self, iaddress): 124 127 self.set_content(self._info) 125 128 self.props.secondary_text = _('Connected') 126 self._set_channel(frequency)127 129 self._set_ip_address(iaddress) 128 130 self._disconnect_item.show() 129 131 132 def set_connected_with_frequency(self, frequency, iaddress): 133 self._set_connected(iaddress) 134 self._set_frequency(frequency) 135 136 def set_connected_with_channel(self, channel, iaddress): 137 self._set_connected(iaddress) 138 self._set_channel(channel) 139 130 140 def set_disconnected(self): 131 141 self.props.primary_text = '' 132 142 self.props.secondary_text = '' … … class WirelessPalette(Palette): 139 149 def __adhoc_activate_cb(self, menuitem): 140 150 self.emit('create-connection') 141 151 142 def _set_ channel(self, frequency):152 def _set_frequency(self, frequency): 143 153 try: 144 154 channel = frequency_to_channel(frequency) 145 155 except KeyError: 146 156 channel = 0 157 self._set_channel(channel) 158 159 def _set_channel(self, channel): 147 160 self._channel_label.set_text("%s: %d" % (_("Channel"), channel)) 148 161 149 162 def _set_ip_address(self, ip_address): … … class WirelessDeviceView(ToolButton): 386 399 self._icon.props.pulsing = True 387 400 elif state == network.DEVICE_STATE_ACTIVATED: 388 401 address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address') 389 self._palette.set_connected (self._frequency, address)402 self._palette.set_connected_with_frequency(self._frequency, address) 390 403 self._icon.props.pulsing = False 391 404 else: 392 405 self._icon.props.badge_name = None … … class WirelessDeviceView(ToolButton): 468 481 def __activate_error_cb(self, err): 469 482 logging.debug('Failed to create network: %s', err) 470 483 484 485 class OlpcMeshDeviceView(ToolButton): 486 _ICON_NAME = 'network-mesh' 487 FRAME_POSITION_RELATIVE = 302 488 489 def __init__(self, device): 490 ToolButton.__init__(self) 491 492 self._bus = dbus.SystemBus() 493 self._device = device 494 self._device_props = None 495 self._device_state = None 496 self._channel = 0 497 498 self._icon = PulsingIcon(icon_name=self._ICON_NAME) 499 self._icon.props.pulse_color = xocolor.XoColor( \ 500 "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(), 501 style.COLOR_TRANSPARENT.get_svg())) 502 self._icon.props.base_color = profile.get_color() 503 504 self.set_icon_widget(self._icon) 505 self._icon.show() 506 507 self.set_palette_invoker(FrameWidgetInvoker(self)) 508 self._palette = WirelessPalette(_("Mesh Network")) 509 self._palette.connect('deactivate-connection', 510 self.__deactivate_connection) 511 self.set_palette(self._palette) 512 self._palette.set_group_id('frame') 513 514 self._device_props = dbus.Interface(self._device, 515 'org.freedesktop.DBus.Properties') 516 self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, 517 reply_handler=self.__get_device_props_reply_cb, 518 error_handler=self.__get_device_props_error_cb) 519 self._device_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel', 520 reply_handler=self.__get_active_channel_reply_cb, 521 error_handler=self.__get_active_channel_error_cb) 522 523 self._bus.add_signal_receiver(self.__state_changed_cb, 524 signal_name='StateChanged', 525 path=self._device.object_path, 526 dbus_interface=_NM_DEVICE_IFACE) 527 self._bus.add_signal_receiver(self.__wireless_properties_changed_cb, 528 signal_name='PropertiesChanged', 529 path=device.object_path, 530 dbus_interface=_NM_OLPC_MESH_IFACE) 531 532 def disconnect(self): 533 self._bus.remove_signal_receiver(self.__state_changed_cb, 534 signal_name='StateChanged', 535 path=self._device.object_path, 536 dbus_interface=_NM_DEVICE_IFACE) 537 self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb, 538 signal_name='PropertiesChanged', 539 path=self._device.object_path, 540 dbus_interface=_NM_OLPC_MESH_IFACE) 541 542 def __get_device_props_reply_cb(self, properties): 543 if 'State' in properties: 544 self._device_state = properties['State'] 545 self._update() 546 547 def __get_device_props_error_cb(self, err): 548 logging.error('Error getting the device properties: %s', err) 549 550 def __get_active_channel_reply_cb(self, channel): 551 self._channel = channel 552 self._update_text() 553 554 def __get_active_channel_error_cb(self, err): 555 logging.error('Error getting the active channel: %s', err) 556 557 def __state_changed_cb(self, new_state, old_state, reason): 558 self._device_state = new_state 559 self._update() 560 561 def __wireless_properties_changed_cb(self, properties): 562 if 'ActiveChannel' in properties: 563 self._channel = properties['ActiveChannel'] 564 self._update_text() 565 566 def _update_text(self): 567 self._palette.props.primary_text = _("Mesh Network") + " " + str(self._channel) 568 569 def _update(self): 570 state = self._device_state 571 572 if state == network.DEVICE_STATE_PREPARE or \ 573 state == network.DEVICE_STATE_CONFIG or \ 574 state == network.DEVICE_STATE_NEED_AUTH or \ 575 state == network.DEVICE_STATE_IP_CONFIG: 576 self._palette.set_connecting() 577 self._icon.props.pulsing = True 578 elif state == network.DEVICE_STATE_ACTIVATED: 579 address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address') 580 self._palette.set_connected_with_channel(self._channel, address) 581 self._icon.props.pulsing = False 582 583 def __deactivate_connection(self, palette, data=None): 584 obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) 585 netmgr = dbus.Interface(obj, _NM_IFACE) 586 netmgr_props = dbus.Interface( 587 netmgr, 'org.freedesktop.DBus.Properties') 588 active_connections_o = netmgr_props.Get(_NM_IFACE, 589 'ActiveConnections') 590 591 for conn_o in active_connections_o: 592 # The connection path for a mesh connection is the device itself. 593 obj = self._bus.get_object(_NM_IFACE, conn_o) 594 props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') 595 ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') 596 597 try: 598 obj = self._bus.get_object(_NM_IFACE, ap_op) 599 props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') 600 type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') 601 if type == network.DEVICE_TYPE_802_11_OLPC_MESH: 602 netmgr.DeactivateConnection(conn_o) 603 break 604 except dbus.exceptions.DBusException: 605 pass 606 607 471 608 class WiredDeviceView(TrayIcon): 472 609 473 610 _ICON_NAME = 'network-wired' … … class WiredDeviceView(TrayIcon): 487 624 488 625 489 626 class WirelessDeviceObserver(object): 490 def __init__(self, device, tray ):627 def __init__(self, device, tray, view_class=WirelessDeviceView): 491 628 self._device = device 492 629 self._device_view = None 493 630 self._tray = tray 494 631 495 self._device_view = WirelessDeviceView(self._device)632 self._device_view = view_class(self._device) 496 633 self._tray.add_device(self._device_view) 497 634 498 635 def disconnect(self): … … class NetworkManagerObserver(object): 593 730 elif device_type == network.DEVICE_TYPE_802_11_WIRELESS: 594 731 device = WirelessDeviceObserver(nm_device, self._tray) 595 732 self._devices[device_op] = device 733 elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH: 734 device = WirelessDeviceObserver(nm_device, self._tray, view_class=OlpcMeshDeviceView) 735 self._devices[device_op] = device 596 736 597 737 def __device_added_cb(self, device_op): 598 738 self._check_device(device_op) -
src/jarabe/desktop/meshbox.py
diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py index 76880b8..70c836a 100644
a b from sugar.graphics.menuitem import MenuItem 36 36 from sugar.activity.activityhandle import ActivityHandle 37 37 from sugar.activity import activityfactory 38 38 from sugar.util import unique_id 39 from sugar import profile 39 40 40 41 from jarabe.model import neighborhood 41 42 from jarabe.view.buddyicon import BuddyIcon … … from jarabe.model.network import Settings 51 52 from jarabe.model.network import IP4Config 52 53 from jarabe.model.network import WirelessSecurity 53 54 from jarabe.model.network import AccessPoint 55 from jarabe.model.network import OlpcMesh as OlpcMeshSettings 56 from jarabe.model.olpcmesh import OlpcMeshManager 54 57 55 58 _NM_SERVICE = 'org.freedesktop.NetworkManager' 56 59 _NM_IFACE = 'org.freedesktop.NetworkManager' 57 60 _NM_PATH = '/org/freedesktop/NetworkManager' 58 61 _NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device' 59 62 _NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless' 63 _NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh' 60 64 _NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint' 61 65 _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' 62 66 63 _ ICON_NAME = 'network-wireless'64 67 _AP_ICON_NAME = 'network-wireless' 68 _OLPC_MESH_ICON_NAME = 'network-mesh' 65 69 66 70 class WirelessNetworkView(CanvasPulsingIcon): 67 71 def __init__(self, initial_ap): … … class WirelessNetworkView(CanvasPulsingIcon): 149 153 and self._name[-15] == '#' 150 154 151 155 def _create_palette(self): 152 icon_name = get_icon_state(_ ICON_NAME, self._strength)156 icon_name = get_icon_state(_AP_ICON_NAME, self._strength) 153 157 self._palette_icon = Icon(icon_name=icon_name, 154 158 icon_size=style.STANDARD_ICON_SIZE, 155 159 badge_name=self.props.badge_name) … … class WirelessNetworkView(CanvasPulsingIcon): 224 228 if self._mode == network.NM_802_11_MODE_INFRA: 225 229 connection.set_connected() 226 230 227 icon_name = '%s-connected' % _ ICON_NAME231 icon_name = '%s-connected' % _AP_ICON_NAME 228 232 else: 229 icon_name = _ ICON_NAME233 icon_name = _AP_ICON_NAME 230 234 231 235 icon_name = get_icon_state(icon_name, self._strength) 232 236 if icon_name: … … class WirelessNetworkView(CanvasPulsingIcon): 419 423 return None 420 424 return self._access_points[ap_path] 421 425 426 def is_olpc_mesh(self): 427 return self._mode == network.NM_802_11_MODE_ADHOC \ 428 and self.name == "olpc-mesh" 429 430 def remove_all_aps(self): 431 for ap in self._access_points.values(): 432 ap.disconnect() 433 self._access_points = {} 434 self._active_ap = None 435 self.update_strength() 436 422 437 def disconnect(self): 423 438 self._bus.remove_signal_receiver(self.__device_state_changed_cb, 424 439 signal_name='StateChanged', … … class WirelessNetworkView(CanvasPulsingIcon): 430 445 dbus_interface=_NM_WIRELESS_IFACE) 431 446 432 447 448 class OlpcMeshView(CanvasPulsingIcon): 449 def __init__(self, mesh_mgr, channel): 450 CanvasPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME, 451 size=style.STANDARD_ICON_SIZE, cache=True) 452 self._bus = dbus.SystemBus() 453 self._channel = channel 454 self._mesh_mgr = mesh_mgr 455 self._disconnect_item = None 456 self._connect_item = None 457 self._greyed_out = False 458 self._name = '' 459 self._device_state = None 460 self._connection = None 461 self._active = False 462 device = mesh_mgr.meshdev 463 464 self.connect('button-release-event', self.__button_release_event_cb) 465 466 interface_props = dbus.Interface(device, 467 'org.freedesktop.DBus.Properties') 468 interface_props.Get(_NM_DEVICE_IFACE, 'State', 469 reply_handler=self.__get_device_state_reply_cb, 470 error_handler=self.__get_device_state_error_cb) 471 interface_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel', 472 reply_handler=self.__get_active_channel_reply_cb, 473 error_handler=self.__get_active_channel_error_cb) 474 475 self._bus.add_signal_receiver(self.__device_state_changed_cb, 476 signal_name='StateChanged', 477 path=device.object_path, 478 dbus_interface=_NM_DEVICE_IFACE) 479 self._bus.add_signal_receiver(self.__wireless_properties_changed_cb, 480 signal_name='PropertiesChanged', 481 path=device.object_path, 482 dbus_interface=_NM_OLPC_MESH_IFACE) 483 484 pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(), 485 style.COLOR_TRANSPARENT.get_svg())) 486 self.props.pulse_color = pulse_color 487 self.props.base_color = profile.get_color() 488 self._palette = self._create_palette() 489 self.set_palette(self._palette) 490 491 def _create_palette(self): 492 p = palette.Palette(_("Mesh Network") + " " + str(self._channel)) 493 494 self._connect_item = MenuItem(_('Connect'), 'dialog-ok') 495 self._connect_item.connect('activate', self.__connect_activate_cb) 496 p.menu.append(self._connect_item) 497 498 self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject') 499 self._disconnect_item.connect('activate', 500 self._disconnect_activate_cb) 501 p.menu.append(self._disconnect_item) 502 503 return p 504 505 def __get_device_state_reply_cb(self, state): 506 self._device_state = state 507 self._update() 508 509 def __get_device_state_error_cb(self, err): 510 logging.error('Error getting the device state: %s', err) 511 512 def __device_state_changed_cb(self, new_state, old_state, reason): 513 self._device_state = new_state 514 self._update() 515 516 def __get_active_channel_reply_cb(self, channel): 517 self._active = (channel == self._channel) 518 self._update() 519 520 def __get_active_channel_error_cb(self, err): 521 logging.error('Error getting the active channel: %s', err) 522 523 def __wireless_properties_changed_cb(self, properties): 524 if 'ActiveChannel' in properties: 525 channel = properties['ActiveChannel'] 526 self._active = (channel == self._channel) 527 self._update() 528 529 def _update(self): 530 if self._active: 531 state = self._device_state 532 else: 533 state = network.DEVICE_STATE_UNKNOWN 534 535 if state == network.DEVICE_STATE_PREPARE or \ 536 state == network.DEVICE_STATE_CONFIG or \ 537 state == network.DEVICE_STATE_NEED_AUTH or \ 538 state == network.DEVICE_STATE_IP_CONFIG: 539 if self._disconnect_item: 540 self._disconnect_item.show() 541 self._connect_item.hide() 542 self._palette.props.secondary_text = _('Connecting...') 543 self.props.pulsing = True 544 elif state == network.DEVICE_STATE_ACTIVATED: 545 if self._disconnect_item: 546 self._disconnect_item.show() 547 self._connect_item.hide() 548 self._palette.props.secondary_text = _('Connected') 549 self.props.pulsing = False 550 else: 551 if self._disconnect_item: 552 self._disconnect_item.hide() 553 self._connect_item.show() 554 self._palette.props.secondary_text = None 555 self.props.pulsing = False 556 557 def _update_color(self): 558 if self._greyed_out: 559 self.props.base_color = XoColor('#D5D5D5,#D5D5D5') 560 else: 561 self.props.base_color = profile.get_color() 562 563 def _disconnect_activate_cb(self, item): 564 pass 565 566 def __connect_activate_cb(self, icon): 567 self._connect() 568 569 def __button_release_event_cb(self, icon, event): 570 self._connect() 571 572 def _connect(self): 573 self._mesh_mgr.user_activate_channel(self._channel) 574 575 def __activate_reply_cb(self, connection): 576 logging.debug('Connection activated: %s', connection) 577 578 def __activate_error_cb(self, err): 579 logging.error('Failed to activate connection: %s', err) 580 581 def set_filter(self, query): 582 self._greyed_out = (query != '') 583 self._update_color() 584 585 def disconnect(self): 586 self._bus.remove_signal_receiver(self.__device_state_changed_cb, 587 signal_name='StateChanged', 588 path=self._device.object_path, 589 dbus_interface=_NM_DEVICE_IFACE) 590 self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb, 591 signal_name='PropertiesChanged', 592 path=self._device.object_path, 593 dbus_interface=_NM_OLPC_MESH_IFACE) 594 595 433 596 class ActivityView(hippo.CanvasBox): 434 597 def __init__(self, model): 435 598 hippo.CanvasBox.__init__(self) … … class NetworkManagerObserver(object): 729 892 device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') 730 893 if device_type == network.DEVICE_TYPE_802_11_WIRELESS: 731 894 self._devices[device_o] = DeviceObserver(self._box, device) 895 elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH: 896 self._box.enable_olpc_mesh(device) 732 897 733 898 def _get_device_path_error_cb(self, err): 734 899 logging.error('Failed to get device type: %s', err) … … class NetworkManagerObserver(object): 741 906 observer = self._devices[device_o] 742 907 observer.disconnect() 743 908 del self._devices[device_o] 744 909 return 910 911 device = self._bus.get_object(_NM_SERVICE, device_o) 912 props = dbus.Interface(device, 'org.freedesktop.DBus.Properties') 913 device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') 914 if device_type == network.DEVICE_TYPE_802_11_OLPC_MESH: 915 self._box.disable_olpc_mesh(device) 745 916 746 917 class MeshBox(gtk.VBox): 747 918 __gtype_name__ = 'SugarMeshBox' … … class MeshBox(gtk.VBox): 756 927 self._model = neighborhood.get_model() 757 928 self._buddies = {} 758 929 self._activities = {} 759 self._mesh = {}930 self._mesh = [] 760 931 self._buddy_to_activity = {} 761 932 self._suspended = True 762 933 self._query = '' … … class MeshBox(gtk.VBox): 901 1072 del self.wireless_networks[hash] 902 1073 903 1074 def _ap_props_changed_cb(self, ap, old_hash): 1075 # if we have mesh hardware, ignore OLPC mesh networks that appear as 1076 # normal wifi networks 1077 if len(self._mesh) > 0 and ap.mode == network.NM_802_11_MODE_ADHOC \ 1078 and ap.name == "olpc-mesh": 1079 logging.debug("ignoring OLPC mesh IBSS") 1080 ap.disconnect() 1081 return 1082 904 1083 if old_hash is None: # new AP finished initializing 905 1084 self._add_ap_to_network(ap) 906 1085 return … … class MeshBox(gtk.VBox): 935 1114 self._remove_net_if_empty(net, ap.network_hash()) 936 1115 return 937 1116 938 logging.error('Can not remove access point %s', ap_o) 1117 # it's not an error if the AP isn't found, since we might have ignored 1118 # it (e.g. olpc-mesh adhoc network) 1119 logging.debug('Can not remove access point %s' % ap_o) 1120 1121 def _add_olpc_mesh_icon(self, mesh_mgr, channel): 1122 icon = OlpcMeshView(mesh_mgr, channel) 1123 self._layout.add(icon) 1124 self._mesh.append(icon) 1125 1126 def enable_olpc_mesh(self, meshdev): 1127 mesh_mgr = OlpcMeshManager(meshdev) 1128 self._add_olpc_mesh_icon(mesh_mgr, 1) 1129 self._add_olpc_mesh_icon(mesh_mgr, 6) 1130 self._add_olpc_mesh_icon(mesh_mgr, 11) 1131 1132 # the OLPC mesh can be recognised as a "normal" wifi network. remove 1133 # any such normal networks if they have been created 1134 for hash, net in self.wireless_networks.iteritems(): 1135 if not net.is_olpc_mesh(): 1136 continue 1137 1138 logging.debug("removing OLPC mesh IBSS") 1139 net.remove_all_aps() 1140 net.disconnect() 1141 self._layout.remove(net) 1142 del self.wireless_networks[hash] 1143 1144 def disable_olpc_mesh(self, meshdev): 1145 for icon in self._mesh: 1146 icon.disconnect() 1147 self._layout.remove(icon) 1148 self._mesh = [] 939 1149 940 1150 def suspend(self): 941 1151 if not self._suspended: 942 1152 self._suspended = True 943 for net in self.wireless_networks.values() :1153 for net in self.wireless_networks.values() + self._mesh: 944 1154 net.props.paused = True 945 1155 946 1156 def resume(self): 947 1157 if self._suspended: 948 1158 self._suspended = False 949 for net in self.wireless_networks.values() :1159 for net in self.wireless_networks.values() + self._mesh: 950 1160 net.props.paused = False 951 1161 952 1162 def _toolbar_query_changed_cb(self, toolbar, query): -
src/jarabe/model/Makefile.am
diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am index 399db65..18d44da 100644
a b sugar_PYTHON = \ 6 6 filetransfer.py \ 7 7 friends.py \ 8 8 invites.py \ 9 olpcmesh.py \ 9 10 owner.py \ 10 11 neighborhood.py \ 11 12 network.py \ -
src/jarabe/model/network.py
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py index 10b73ab..b3c30d9 100644
a b from sugar import env 29 29 30 30 DEVICE_TYPE_802_3_ETHERNET = 1 31 31 DEVICE_TYPE_802_11_WIRELESS = 2 32 DEVICE_TYPE_802_11_OLPC_MESH = 6 32 33 33 34 DEVICE_STATE_UNKNOWN = 0 34 35 DEVICE_STATE_UNMANAGED = 1 … … class WirelessSecurity(object): 103 104 return wireless_security 104 105 105 106 class Wireless(object): 107 nm_name = "802-11-wireless" 108 106 109 def __init__(self): 107 110 self.ssid = None 108 111 self.security = None … … class Wireless(object): 119 122 wireless['band'] = self.band 120 123 return wireless 121 124 125 126 class OlpcMesh(object): 127 nm_name = "802-11-olpc-mesh" 128 129 def __init__(self, channel, anycast_addr): 130 self.channel = channel 131 self.anycast_addr = anycast_addr 132 133 def get_dict(self): 134 ret = { 135 "ssid": dbus.ByteArray("olpc-mesh"), 136 "channel": self.channel, 137 } 138 139 if self.anycast_addr: 140 ret["dhcp-anycast-address"] = dbus.ByteArray(self.anycast_addr) 141 return ret 142 143 122 144 class Connection(object): 123 145 def __init__(self): 124 146 self.id = None … … class IP4Config(object): 147 169 return ip4_config 148 170 149 171 class Settings(object): 150 def __init__(self ):172 def __init__(self, wireless_cfg=None): 151 173 self.connection = Connection() 152 self.wireless = Wireless()153 174 self.ip4_config = None 154 175 self.wireless_security = None 155 176 177 if wireless_cfg is not None: 178 self.wireless = wireless_cfg 179 else: 180 self.wireless = Wireless() 181 156 182 def get_dict(self): 157 183 settings = {} 158 184 settings['connection'] = self.connection.get_dict() 159 settings[ '802-11-wireless'] = self.wireless.get_dict()185 settings[self.wireless.nm_name] = self.wireless.get_dict() 160 186 if self.wireless_security is not None: 161 187 settings['802-11-wireless-security'] = \ 162 188 self.wireless_security.get_dict() -
new file src/jarabe/model/olpcmesh.py
diff --git a/src/jarabe/model/olpcmesh.py b/src/jarabe/model/olpcmesh.py new file mode 100644 index 0000000..26c8b53
- + 1 # Copyright (C) 2009 One Laptop per Child 2 # 3 # This program is free software; you can redistribute it and/or modify 4 # it under the terms of the GNU General Public License as published by 5 # the Free Software Foundation; either version 2 of the License, or 6 # (at your option) any later version. 7 # 8 # This program is distributed in the hope that it will be useful, 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 # GNU General Public License for more details. 12 # 13 # You should have received a copy of the GNU General Public License 14 # along with this program; if not, write to the Free Software 15 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 16 17 import logging 18 19 import dbus 20 import gobject 21 22 from jarabe.model import network 23 from jarabe.model.network import Settings 24 from jarabe.model.network import OlpcMesh as OlpcMeshSettings 25 from sugar.util import unique_id 26 27 _NM_SERVICE = 'org.freedesktop.NetworkManager' 28 _NM_IFACE = 'org.freedesktop.NetworkManager' 29 _NM_PATH = '/org/freedesktop/NetworkManager' 30 _NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device' 31 _NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh' 32 33 _XS_ANYCAST = "\xc0\x27\xc0\x27\xc0\x00" 34 35 DEVICE_STATE_UNKNOWN = 0 36 DEVICE_STATE_UNMANAGED = 1 37 DEVICE_STATE_UNAVAILABLE = 2 38 DEVICE_STATE_DISCONNECTED = 3 39 DEVICE_STATE_PREPARE = 4 40 DEVICE_STATE_CONFIG = 5 41 DEVICE_STATE_NEED_AUTH = 6 42 DEVICE_STATE_IP_CONFIG = 7 43 DEVICE_STATE_ACTIVATED = 8 44 DEVICE_STATE_FAILED = 9 45 46 class OlpcMeshManager(object): 47 def __init__(self, meshdev): 48 self._bus = dbus.SystemBus() 49 self.meshdev = meshdev 50 51 # let's make sure we know the companion device early on 52 # (synchronous request) 53 props = dbus.Interface(meshdev, 'org.freedesktop.DBus.Properties') 54 ethdev_o = props.Get(_NM_OLPC_MESH_IFACE, 'Companion') 55 self.ethdev = self._bus.get_object(_NM_SERVICE, ethdev_o) 56 57 # asynchronously learn about mesh status 58 props.Get(_NM_DEVICE_IFACE, 'State', 59 reply_handler=self.__get_mesh_state_reply_cb, 60 error_handler=self.__get_state_error_cb) 61 # and companion 62 props = dbus.Interface(self.ethdev, 'org.freedesktop.DBus.Properties') 63 props.Get(_NM_DEVICE_IFACE, 'State', 64 reply_handler=self.__get_eth_state_reply_cb, 65 error_handler=self.__get_state_error_cb) 66 67 # this is a stack of connections that we'll iterate through until 68 # we find one that works 69 self._connection_queue = [] 70 71 self._bus.add_signal_receiver(self.__ethdev_state_changed_cb, 72 signal_name='StateChanged', 73 path=self.ethdev.object_path, 74 dbus_interface=_NM_DEVICE_IFACE) 75 76 self._bus.add_signal_receiver(self.__mshdev_state_changed_cb, 77 signal_name='StateChanged', 78 path=self.meshdev.object_path, 79 dbus_interface=_NM_DEVICE_IFACE) 80 81 self._idle_source = 0 82 self._meshdev_state = DEVICE_STATE_UNKNOWN 83 self._ethdev_state = DEVICE_STATE_UNKNOWN 84 85 if len(network.get_settings().connections) == 0: 86 # if there are no configured APs, start meshing immediately 87 self.start_automesh() 88 else: 89 # otherwise, start our timer system which basically looks for 10 90 # seconds of inactivity on both devices, then starts automesh 91 self._idle_source = gobject.timeout_add_seconds(10, self._idle_check) 92 93 def __get_state_error_cb(self, err): 94 logging.debug('Error getting the device state: %s', err) 95 96 def __get_mesh_state_reply_cb(self, state): 97 self._meshdev_state = state 98 self._maybe_schedule_idle_check() 99 100 def __get_eth_state_reply_cb(self, state): 101 self._ethdev_state = state 102 self._maybe_schedule_idle_check() 103 104 def __ethdev_state_changed_cb(self, new_state, old_state, reason): 105 self._ethdev_state = new_state 106 self._maybe_schedule_idle_check() 107 108 # If a connection is activated on the eth device, stop trying our 109 # automatic connections 110 if new_state >= DEVICE_STATE_PREPARE \ 111 and new_state <= DEVICE_STATE_ACTIVATED \ 112 and len(self._connection_queue) > 0: 113 self._connection_queue = [] 114 115 def __mshdev_state_changed_cb(self, new_state, old_state, reason): 116 self._meshdev_state = new_state 117 self._maybe_schedule_idle_check() 118 119 if new_state == DEVICE_STATE_FAILED: 120 # try next connection in queue 121 self._activate_from_queue() 122 elif new_state == DEVICE_STATE_ACTIVATED \ 123 and len(self._connection_queue) > 0: 124 # clear connection queue, we were successful 125 self._connection_queue = [] 126 127 def _maybe_schedule_idle_check(self): 128 # if both devices are disconnected, wait 10 seconds for some activity 129 # and if nothing happens then we can start automatic meshing 130 if self._meshdev_state == DEVICE_STATE_DISCONNECTED \ 131 and self._ethdev_state == DEVICE_STATE_DISCONNECTED: 132 if self._idle_source != 0: 133 gobject.source_remove(self._idle_source) 134 self._idle_source = gobject.timeout_add_seconds(10, self._idle_check) 135 136 def _idle_check(self): 137 if self._meshdev_state == DEVICE_STATE_DISCONNECTED \ 138 and self._ethdev_state == DEVICE_STATE_DISCONNECTED: 139 logging.debug("starting automesh due to inactivity") 140 self.start_automesh() 141 return False 142 143 def _make_connection(self, channel, anycast_addr=None): 144 settings = Settings(wireless_cfg=OlpcMeshSettings(channel, anycast_addr)) 145 if not anycast_addr: 146 settings.ip4_config = network.IP4Config() 147 settings.ip4_config.method = 'link-local' 148 settings.connection.id = 'olpc-mesh-' + str(channel) 149 settings.connection.uuid = unique_id() 150 settings.connection.type = '802-11-olpc-mesh' 151 connection = network.add_connection(settings.connection.id, settings) 152 return connection 153 154 def __activate_reply_cb(self, connection): 155 logging.debug('Connection activated: %s', connection) 156 157 def __activate_error_cb(self, err): 158 logging.error('Failed to activate connection: %s', err) 159 160 def activate_connection(self, channel, anycast_addr=None): 161 logging.debug("activate channel %d anycast %s" % (channel, repr(anycast_addr))) 162 obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) 163 netmgr = dbus.Interface(obj, _NM_IFACE) 164 connection = self._make_connection(channel, anycast_addr) 165 166 netmgr.ActivateConnection(network.SETTINGS_SERVICE, connection.path, 167 self.meshdev.object_path, 168 self.meshdev.object_path, 169 reply_handler=self.__activate_reply_cb, 170 error_handler=self.__activate_error_cb) 171 172 def _activate_from_queue(self): 173 if len(self._connection_queue) == 0: 174 return 175 176 channel, anycast = self._connection_queue.pop() 177 self.activate_connection(channel, anycast) 178 179 # Activate a mesh connection on a user-specified channel 180 # Looks for XS first, then resorts to simple mesh 181 def user_activate_channel(self, channel): 182 # Empties any existing queue in order to abort any connection attempt 183 # that was already happening 184 self._connection_queue = [ (channel, None), (channel, _XS_ANYCAST) ] 185 self._activate_from_queue() 186 187 # Start meshing, intended for when there are no better networks to 188 # connect to. First looks for XS on all channels, then falls back to 189 # simple mesh on channel 1. 190 def start_automesh(self): 191 # Empties any existing queue in order to abort any connection attempt 192 # that was already happening 193 self._connection_queue = [ 194 (1, None), 195 (11, _XS_ANYCAST), (6, _XS_ANYCAST), (1, _XS_ANYCAST) 196 ] 197 self._activate_from_queue() 198