826656ee96c69da380b9504ca26b80d7a9936cf1
[platform/upstream/connman.git] / test / p2p-on-supplicant
1 #!/usr/bin/python
2
3 from os import O_NONBLOCK
4 from sys import stdin, stdout, exit, version_info, argv
5 from fcntl import fcntl, F_GETFL, F_SETFL
6 import glib
7 import dbus
8 import dbus.mainloop.glib
9 import gobject
10 import argparse
11
12 WPA_NAME='fi.w1.wpa_supplicant1'
13 WPA_INTF='fi.w1.wpa_supplicant1'
14 WPA_PATH='/fi/w1/wpa_supplicant1'
15 WPA_IF_INTF = WPA_INTF + '.Interface'
16 WPA_P2P_INTF = WPA_IF_INTF + '.P2PDevice'
17 WPA_GROUP_INTF = WPA_INTF + '.Group'
18 WPA_PEER_INTF = WPA_INTF + '.Peer'
19 DBUS_PROPERTIES_INTF = 'org.freedesktop.DBus.Properties'
20
21 P2P_GROUP_CAPAB_GROUP_OWNER = 1 << 0
22
23 class ArgFields:
24     for field in ('help', 'metavar'):
25         exec('{}="{}"'.format(field, field))
26
27 class InputLine:
28     def __init__(self, handler):
29         self.line = ''
30         self.handler = handler
31
32         flags = fcntl(stdin.fileno(), F_GETFL)
33         flags |= O_NONBLOCK
34         fcntl(stdin.fileno(), F_SETFL, flags)
35         glib.io_add_watch(stdin, glib.IO_IN, self.input_cb)
36
37         self.prompt()
38
39     def prompt(self):
40         self.line = ''
41         print '> ',
42         stdout.flush()
43
44     def input_cb(self, fd, event):
45         if event != glib.IO_IN:
46             return
47
48         self.line += fd.read();
49         for line in self.line.split('\n'):
50             line = line.strip()
51             if len(line) == 0:
52                 break
53
54             self.handler(line.strip())
55
56         self.prompt()
57
58         return True
59
60 def error_print(ex):
61     print 'Command Error: %s' % ex
62
63 def checkarg(nb_args = 0, min_args = False):
64     def under(function):
65         def wrapper(*args, **kwargs):
66             resuls = True
67
68             if min_args:
69                 result = len(args[1]) < nb_args
70             else:
71                 result = len(args[1]) != nb_args
72
73             if result:
74                 raise Exception('Command %s takes %s arguments' %
75                                     (function.__name__, nb_args))
76             return function(*args, **kwargs)
77         return wrapper
78     return under
79
80 def print_dict(d):
81     for k in d:
82         try:
83             if type(d[k]) is dbus.Byte:
84                 print 'Key %s --> 0x%x' % (k, d[k])
85             else:
86                 print 'Key %s --> %s' % (k, d[k])
87         except:
88             print "Error: Key %s content cannot be printed" % k
89             pass
90
91 def print_tuple(t):
92     for e in t:
93         if type(e) is dbus.Dictionary:
94             print_dict(e)
95         else:
96             print 'Element: %s' % e
97
98 class Wpa_s:
99     def __init__(self, bus, iface_name, command):
100         self.wpa = dbus.Interface(bus.get_object(WPA_NAME, WPA_PATH), WPA_INTF)
101         bus.add_signal_receiver(self.__wpa_property_changed, path=WPA_PATH,
102                                 member_keyword='signal')
103         bus.add_signal_receiver(self.__InterfaceAdded, path=WPA_PATH,
104                                 signal_name='InterfaceAdded')
105         bus.add_signal_receiver(self.__InterfaceRemoved, path=WPA_PATH,
106                                 signal_name='InterfaceRemoved')
107         self.__reset()
108
109         self.bus = bus
110
111         self.debug = False
112
113         self.line_in = InputLine(self.__command)
114
115         if iface_name:
116             try:
117                 self.create_if([iface_name])
118             except:
119                 print "Error creating interface: %s" % iface_name
120
121         if len(command.strip(' ')):
122             self.__command(command)
123
124     def help(self, args):
125         list = self.command_list.keys()
126         list.sort()
127         for key in list:
128             help = ''
129             if (self.command_list[key].has_key(ArgFields.help)):
130                 help = self.command_list[key][ArgFields.help]
131
132             print "%s\t%s" % (key.rjust(25), help.ljust(50))
133
134     def __command(self, cmd_line):
135         cmd = cmd_line.split(' ')
136
137         try:
138             func = getattr(self, cmd[0])
139         except Exception, e:
140             print 'Error: command unknown - %s' % e
141             return
142
143         try:
144             func(cmd[1:])
145         except Exception, e:
146             error_print(e)
147
148     def __wpa_property_changed(*args, **kwargs):
149         print 'WPA - Signal:  %s' % kwargs.get('signal')
150
151     def __if_property_changed(*args, **kwargs):
152         signal = kwargs.get('signal')
153         print 'IF - Signal:  %s' % signal
154
155         if signal == 'BSSAdded':
156             return
157
158         if args[0].debug:
159             print_tuple(args[1:])
160
161     def __p2p_property_changed(*args, **kwargs):
162         print 'IF P2P - Signal:  %s' % kwargs.get('signal')
163         if args[0].debug:
164             print_tuple(args[1:])
165
166     """
167         It should be: __DeviceFound(self, object_path, properties)
168         wpa_supplicant's DBus API is buggy here:
169             - no properties are given
170     """
171     def __DeviceFound(self, object_path):
172         self.peers[object_path] = None
173
174         peer = self.bus.get_object(WPA_INTF, object_path)
175         peer_if = dbus.Interface(peer, DBUS_PROPERTIES_INTF)
176
177         self.peers[object_path] = peer_if.GetAll(WPA_PEER_INTF)
178
179     def __DeviceLost(self, object_path):
180         if object_path in self.peers:
181             del self.peers[object_path]
182
183     def __PeerJoined(self, object_path):
184         print 'Peer %s joined' % object_path
185
186     def __PeerDisconnected(self, object_path):
187         print 'Peer %s disconnected' % object_path
188
189     def __group_if_property_changed(*args, **kwargs):
190         print 'Group - ',
191         args[0].__if_property_changed(*args, **kwargs)
192
193     def __group_if_p2p_property_changed(*args, **kwargs):
194         print 'Group - ',
195         args[0].__p2p_property_changed(*args, **kwargs)
196
197     def __GroupFinished(self, ifname, role):
198         print 'Group running on %s is being removed' % ifname
199         self.group_obj = self.group_if = self.group_iface_path = None
200
201     def __InvitationResult(self, response):
202         print 'Invitation result status: %d ' % response['status']
203
204         if response.has_key('bssid'):
205             print 'bssid: %s' % response['bssid']
206
207         if self.debug:
208             print_dict(response)
209
210     def __GroupStarted(self, properties):
211         self.group_obj = properties['group_object']
212         self.bus.add_signal_receiver(self.__PeerJoined,
213                                 dbus_interface=WPA_GROUP_INTF,
214                                 path=self.group_obj,
215                                 signal_name='PeerJoined')
216         self.bus.add_signal_receiver(self.__PeerDisconnected,
217                                 dbus_interface=WPA_GROUP_INTF,
218                                 path=self.group_obj,
219                                 signal_name='PeerDisconnected')
220
221         self.group_iface_path = properties['interface_object']
222         self.group_if = dbus.Interface(self.bus.get_object(WPA_INTF,
223                                        self.group_iface_path),
224                                        WPA_P2P_INTF)
225         self.bus.add_signal_receiver(self.__group_if_property_changed,
226                                 dbus_interface=WPA_IF_INTF,
227                                 path=self.group_iface_path,
228                                 member_keyword='signal')
229         self.bus.add_signal_receiver(self.__group_if_p2p_property_changed,
230                                 dbus_interface=WPA_P2P_INTF,
231                                 path=self.group_iface_path,
232                                 member_keyword='signal')
233         self.bus.add_signal_receiver(self.__GroupFinished,
234                                 dbus_interface=WPA_P2P_INTF,
235                                 path=self.group_iface_path,
236                                 member_keyword='signal')
237         self.bus.add_signal_receiver(self.__InvitationResult,
238                                 dbus_interface=WPA_P2P_INTF,
239                                 path=self.iface_path,
240                                 signal_name='InvitationResult')
241
242         if self.debug:
243             group = dbus.Interface(self.bus.get_object(WPA_INTF,
244                                                        self.group_obj),
245                                                        DBUS_PROPERTIES_INTF)
246             print_dict(group.GetAll(WPA_GROUP_INTF))
247
248     def __ServiceDiscoveryResponse(self, response):
249         peer = response['peer_object']
250         if peer in self.peers:
251             print 'Peer %s has this TLVs:' % (self.peers[peer]['DeviceName'])
252             print response['tlvs']
253
254     def __InterfaceAdded(self, path, properties):
255         print 'Interface %s Added (%s)' % (properties['Ifname'], path)
256         if self.debug:
257             print_dict(properties)
258             p2p = dbus.Interface(self.bus.get_object(WPA_INTF,
259                                  path), DBUS_PROPERTIES_INTF)
260             print_dict(p2p.GetAll(WPA_P2P_INTF))
261
262     def __InterfaceRemoved(self, path):
263         print 'Interface Removed (%s)' % (path)
264
265     def __listen_if_signals(self):
266         self.bus.add_signal_receiver(self.__if_property_changed,
267                                 dbus_interface=WPA_IF_INTF,
268                                 path=self.iface_path,
269                                 member_keyword='signal')
270         self.bus.add_signal_receiver(self.__p2p_property_changed,
271                                 dbus_interface=WPA_P2P_INTF,
272                                 path=self.iface_path,
273                                 member_keyword='signal')
274         self.bus.add_signal_receiver(self.__GroupStarted,
275                                 dbus_interface=WPA_P2P_INTF,
276                                 path=self.iface_path,
277                                 signal_name='GroupStarted')
278         self.bus.add_signal_receiver(self.__DeviceFound,
279                                 dbus_interface=WPA_P2P_INTF,
280                                 path=self.iface_path,
281                                 signal_name='DeviceFound')
282         self.bus.add_signal_receiver(self.__DeviceLost,
283                                 dbus_interface=WPA_P2P_INTF,
284                                 path=self.iface_path,
285                                 signal_name='DeviceLost')
286         self.bus.add_signal_receiver(self.__ServiceDiscoveryResponse,
287                                 dbus_interface=WPA_P2P_INTF,
288                                 path=self.iface_path,
289                                 signal_name='ServiceDiscoveryResponse')
290
291     def __reset(self):
292         self.iface_path = self.iface_name = self.iface = None
293         self.p2p = self.group_if = self.group_obj = None
294         self.peers = {}
295
296     def __set_if(self, iface_name):
297         self.iface = dbus.Interface(self.bus.get_object(WPA_INTF,
298                                     self.iface_path), WPA_IF_INTF)
299         self.p2p = dbus.Interface(self.bus.get_object(WPA_INTF,
300                                     self.iface_path), WPA_P2P_INTF)
301
302         p2p_if = dbus.Interface(self.p2p, DBUS_PROPERTIES_INTF)
303         p2p_if.Set(WPA_P2P_INTF, 'P2PDeviceConfig',
304                    dbus.Dictionary({ 'DeviceName' : 'ConnManP2P' },
305                                    signature='sv'))
306         print 'Interface %s: %s' % (iface_name, self.iface_path)
307         self.iface_name = iface_name
308         self.__listen_if_signals()
309
310     @checkarg()
311     def enable_debug(self, args):
312         self.debug = True
313
314     @checkarg()
315     def disable_debug(self, args):
316         self.debug = False
317
318     @checkarg(nb_args=1)
319     def create_if(self, args):
320         self.__reset()
321         self.iface_path = self.wpa.CreateInterface(({ 'Ifname' : args[0]} ))
322         self.__set_if(args[0])
323
324     @checkarg(nb_args=1)
325     def get_if(self, args):
326         self.__reset()
327         self.iface_path = self.wpa.GetInterface(args[0])
328         self.__set_if(args[0])
329
330     @checkarg()
331     def del_if(self, args = None):
332         if not self.iface_path:
333             return
334
335         self.wpa.RemoveInterface(self.iface_path)
336         print 'Interface %s removed' % self.iface_name
337         self.__reset()
338
339     @checkarg()
340     def scan(self, args = None):
341         if not self.iface:
342             return
343
344         self.iface.Scan(({ 'Type': 'passive' }))
345         print 'Scan started'
346
347     @checkarg()
348     def quit(self, args = None):
349         self.del_if(args)
350         exit(0)
351
352     @checkarg(nb_args=1)
353     def set_command_list(self, command_list):
354         self.command_list = command_list[0]
355
356     @checkarg()
357     def p2p_find(self, args = None):
358         if not self.p2p:
359             return
360
361         self.p2p.Find(({}))
362
363     @checkarg()
364     def p2p_stop_find(self, args = None):
365         if not self.p2p:
366             return
367
368         self.p2p.StopFind()
369
370     @checkarg()
371     def p2p_peers(self, args = None):
372         if not self.iface:
373             return
374
375         for p in self.peers:
376             print 'Peer Name=%s' % (self.peers[p]['DeviceName'])
377
378     def __find_peer(self, peer_name, ret_object_path = False):
379         if len(self.peers) == 0:
380             return None
381
382         peer = None
383         for p in self.peers:
384             if self.peers[p]['DeviceName'] == peer_name:
385                 peer = self.peers[p]
386                 break
387
388         if not peer:
389             print 'No peer found under the name: %s' % peer_name
390             p = None
391
392         if ret_object_path:
393             return p
394         else:
395             return peer
396
397     @checkarg(nb_args = 1)
398     def p2p_peer(self, args):
399         peer = self.__find_peer(args[0])
400         if peer:
401             print_dict(peer)
402
403     @checkarg(nb_args = 1)
404     def p2p_connect(self, args):
405         if not self.p2p:
406             return
407
408         peer = self.__find_peer(args[0])
409         if not peer:
410             return
411
412         peer_path = self.__find_peer(args[0], True)
413
414         if (peer['groupcapability'] & P2P_GROUP_CAPAB_GROUP_OWNER ==
415                                             P2P_GROUP_CAPAB_GROUP_OWNER):
416             print 'Joining an existing P2P group'
417             pin = self.p2p.Connect(({ 'peer' : peer_path,
418                                       'wps_method' : 'pbc',
419                                       'join' : True,
420                                       'go_intent' : 0 }))
421         else:
422             print 'Associating with another P2P device'
423             pin = self.p2p.Connect(({ 'peer' : peer_path,
424                                       'wps_method' : 'pbc',
425                                       'join' : False,
426                                       'go_intent' : 7 }))
427             if not pin:
428                 print 'WPS PIN in use: %s' % pin
429
430     @checkarg(nb_args = 1)
431     def p2p_disconnect(self, args):
432         if not self.p2p:
433             return
434
435         peer = self.__find_peer(args[0])
436         if not peer:
437             return
438
439         if not self.group_if:
440             print 'Peer %s is not connected' % (peer['DeviceName'])
441             return
442
443         self.group_if.Disconnect()
444
445     @checkarg()
446     def p2p_group_add(self, args):
447         if not self.p2p:
448             return
449
450         self.p2p.GroupAdd(({ 'persistent' : dbus.Boolean(1) }))
451
452     @checkarg()
453     def p2p_group_remove(self, args):
454         if not self.group_if:
455             return
456
457         self.group_if.Disconnect()
458
459     @checkarg()
460     def p2p_group(self, args):
461         if not self.group_obj:
462             return
463
464         group = dbus.Interface(self.bus.get_object(WPA_INTF,
465                                self.group_obj), DBUS_PROPERTIES_INTF)
466         print_dict(group.GetAll(WPA_GROUP_INTF))
467
468     @checkarg()
469     def p2p_flush(self, args):
470         if not self.p2p:
471             return
472
473         self.p2p.Flush()
474
475     @checkarg()
476     def p2p_serv_disc_req(self, args = None):
477         if not self.p2p:
478             return
479
480         """ We request all kind of services """
481         sd_req = dbus.Array(signature='y', variant_level=1)
482         for a in [2,0,0,1]:
483             sd_req.append(dbus.Byte(a))
484
485         ref = self.p2p.ServiceDiscoveryRequest(({ 'tlv' : sd_req }))
486         print 'Service discovery reference: %s' % ref
487
488     @checkarg(nb_args = 1)
489     def p2p_serv_disc_cancel_req(self, args):
490         if not self.p2p:
491             return
492
493         self.p2p.ServiceDiscoveryCancelRequest(int(args[0]))
494
495     @checkarg(nb_args = 3)
496     def p2p_service_add(self, args):
497         if not self.p2p:
498             return
499
500         service = { 'service_type' : args[0] }
501         if args[0] == 'upnp':
502             service['version'] = args[1]
503             service['service'] = args[2]
504         elif args[0] == 'bonjour':
505             service['query'] = args[1]
506             service['response'] = args[2]
507         else:
508             print 'Unknown service: %s' % args[0]
509             return
510
511         self.p2p.AddService((service))
512
513     @checkarg(nb_args = 2, min_args = True)
514     def p2p_service_del(self, args):
515         if not self.p2p:
516             return
517
518         service = { 'service_type' : args[0] }
519         if args[0] == 'upnp':
520             service['version'] = args[1]
521             service['service'] = args[2]
522         elif args[0] == 'bonjour':
523             service['query'] = args[1]
524         else:
525             print 'Unknown service: %s' % args[0]
526             return
527
528         self.p2p.DeleteService((service))
529
530     @checkarg()
531     def p2p_service_flush(self, args = None):
532         if not self.p2p:
533             return
534
535         self.p2p.FlushService()
536
537     @checkarg(nb_args = 1)
538     def p2p_invite(self, args):
539         if not self.p2p or not self.group_if:
540             return
541
542         peer_path = self.__find_peer(args[0], True)
543
544         if not peer_path:
545             return
546
547         self.group_if.Invite({ 'peer' : peer_path})
548
549 def build_args(parser):
550     parser.add_argument('-d', default=False, action='store_true',
551                        dest='debug', help='enable debug')
552     parser.add_argument('-i', metavar='<interface>', dest='ifname',
553                         help='interface name')
554
555     command = {}
556     command['quit'] = {}
557     command['enable_debug'] = {}
558     command['disable_debug'] = {}
559     command['create_if'] = {ArgFields.help:'<iface_name> - create interface'}
560     command['get_if'] = {ArgFields.help:'<iface_name> - get interface'}
561     command['del_if'] = {ArgFields.help:'removes current interface'}
562     command['scan'] = {}
563     command['p2p_find'] = {}
564     command['p2p_stop_find'] = {}
565     command['p2p_flush'] = {}
566     command['p2p_group_add'] = {ArgFields.help:'adds an autonomous group'}
567     command['p2p_group_remove'] = {}
568     command['p2p_group'] = {}
569     command['p2p_peers'] = {}
570     command['p2p_peer'] = {ArgFields.help:'<p2p device name> - get info for a '
571                                 'peer'}
572     command['p2p_connect'] = {ArgFields.help:'<p2p device name>'}
573     command['p2p_disconnect'] = {ArgFields.help:'<p2p device name>'}
574     command['p2p_serv_disc_req'] = {}
575     command['p2p_serv_disc_cancel_req'] = {ArgFields.help:'<identifier>'}
576     command['p2p_service_add'] = {ArgFields.help:'<service type> '
577                                   '<version/query> <service/response>'}
578     command['p2p_service_del'] = {ArgFields.help:'<service type> '
579                                   '<version/query> [<service>]'}
580     command['p2p_service_flush'] = {}
581     command['p2p_invite'] = {ArgFields.help:'<p2p device name>'}
582
583     command_list = command.keys()
584     command_list.sort()
585     subparsers = parser.add_subparsers(help='commands', dest='command')
586     subparsers.add_parser('')
587     for key in command_list:
588         help=None
589         metavar=None
590         if command[key].has_key(ArgFields.help):
591             help = command[key][ArgFields.help]
592         if command[key].has_key(ArgFields.metavar):
593             metavar = command[key][ArgFields.metavar]
594         command_parser = subparsers.add_parser(key, help=help)
595         command_parser.add_argument(key, nargs='*', metavar=metavar, help=help)
596
597     return command
598
599 def main():
600     if version_info.major != 2:
601         print 'You need to run this under Python 2.x'
602         exit(1)
603
604     parser = argparse.ArgumentParser(description='Connman P2P Test')
605
606     command_list = build_args(parser)
607
608     argv[1:] += ['']
609
610     args = parser.parse_args(argv[1:])
611
612     dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
613
614     opts = []
615     if args.command:
616         opts = getattr(args, args.command)
617
618     params = ''
619     if opts and len(opts[0]):
620         params = ' ' + ''.join(opts)
621
622     bus = dbus.SystemBus()
623
624     mainloop = gobject.MainLoop()
625
626     wpa_s = Wpa_s(bus, args.ifname, args.command + params)
627
628     if (args.debug):
629             wpa_s.enable_debug([])
630
631     wpa_s.set_command_list([command_list])
632
633     mainloop.run()
634
635 if __name__ == '__main__':
636     main()