]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/fst_module_aux.py
tests: Remove unused import subprocess
[thirdparty/hostap.git] / tests / hwsim / fst_module_aux.py
CommitLineData
41a256ec
AN
1# FST tests related classes
2# Copyright (c) 2015, Qualcomm Atheros, Inc.
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7import logging
41a256ec
AN
8import os
9import signal
10import time
11import re
12
13import hostapd
14import wpaspy
15import utils
16from wpasupplicant import WpaSupplicant
17
18import fst_test_common
19
20logger = logging.getLogger()
21
22def parse_fst_iface_event(ev):
23 """Parses FST iface event that comes as a string, e.g.
24 "<3>FST-EVENT-IFACE attached ifname=wlan9 group=fstg0"
25 Returns a dictionary with parsed "event_type", "ifname", and "group"; or
26 None if not an FST event or can't be parsed."""
27 event = {}
28 if ev.find("FST-EVENT-IFACE") == -1:
29 return None
30 if ev.find("attached") != -1:
31 event['event_type'] = 'attached'
32 elif ev.find("detached") != -1:
33 event['event_type'] = 'detached'
34 else:
35 return None
36 f = re.search("ifname=(\S+)", ev)
37 if f is not None:
38 event['ifname'] = f.group(1)
39 f = re.search("group=(\S+)", ev)
40 if f is not None:
41 event['group'] = f.group(1)
42 return event
43
44def parse_fst_session_event(ev):
45 """Parses FST session event that comes as a string, e.g.
46 "<3>FST-EVENT-SESSION event_type=EVENT_FST_SESSION_STATE session_id=0 reason=REASON_STT"
47 Returns a dictionary with parsed "type", "id", and "reason"; or None if not
48 a FST event or can't be parsed"""
49 event = {}
50 if ev.find("FST-EVENT-SESSION") == -1:
51 return None
52 event['new_state'] = '' # The field always exists in the dictionary
53 f = re.search("event_type=(\S+)", ev)
54 if f is None:
55 return None
56 event['type'] = f.group(1)
57 f = re.search("session_id=(\d+)", ev)
58 if f is not None:
59 event['id'] = f.group(1)
60 f = re.search("old_state=(\S+)", ev)
61 if f is not None:
62 event['old_state'] = f.group(1)
63 f = re.search("new_state=(\S+)", ev)
64 if f is not None:
65 event['new_state'] = f.group(1)
66 f = re.search("reason=(\S+)", ev)
67 if f is not None:
68 event['reason'] = f.group(1)
69 return event
70
85eb89fe 71def start_two_ap_sta_pairs(apdev, rsn=False):
41a256ec
AN
72 """auxiliary function that creates two pairs of APs and STAs"""
73 ap1 = FstAP(apdev[0]['ifname'], 'fst_11a', 'a',
74 fst_test_common.fst_test_def_chan_a,
75 fst_test_common.fst_test_def_group,
76 fst_test_common.fst_test_def_prio_low,
85eb89fe 77 fst_test_common.fst_test_def_llt, rsn=rsn)
41a256ec
AN
78 ap1.start()
79 ap2 = FstAP(apdev[1]['ifname'], 'fst_11g', 'g',
80 fst_test_common.fst_test_def_chan_g,
81 fst_test_common.fst_test_def_group,
82 fst_test_common.fst_test_def_prio_high,
85eb89fe 83 fst_test_common.fst_test_def_llt, rsn=rsn)
41a256ec
AN
84 ap2.start()
85
86 sta1 = FstSTA('wlan5',
87 fst_test_common.fst_test_def_group,
88 fst_test_common.fst_test_def_prio_low,
85eb89fe 89 fst_test_common.fst_test_def_llt, rsn=rsn)
41a256ec
AN
90 sta1.start()
91 sta2 = FstSTA('wlan6',
92 fst_test_common.fst_test_def_group,
93 fst_test_common.fst_test_def_prio_high,
85eb89fe 94 fst_test_common.fst_test_def_llt, rsn=rsn)
41a256ec
AN
95 sta2.start()
96
97 return ap1, ap2, sta1, sta2
98
99def stop_two_ap_sta_pairs(ap1, ap2, sta1, sta2):
100 sta1.stop()
101 sta2.stop()
102 ap1.stop()
103 ap2.stop()
104
85eb89fe 105def connect_two_ap_sta_pairs(ap1, ap2, dev1, dev2, rsn=False):
41a256ec
AN
106 """Connects a pair of stations, each one to a separate AP"""
107 dev1.scan(freq=fst_test_common.fst_test_def_freq_a)
108 dev2.scan(freq=fst_test_common.fst_test_def_freq_g)
109
85eb89fe
JM
110 if rsn:
111 dev1.connect(ap1, psk="12345678",
112 scan_freq=fst_test_common.fst_test_def_freq_a)
113 dev2.connect(ap2, psk="12345678",
114 scan_freq=fst_test_common.fst_test_def_freq_g)
115 else:
116 dev1.connect(ap1, key_mgmt="NONE",
117 scan_freq=fst_test_common.fst_test_def_freq_a)
118 dev2.connect(ap2, key_mgmt="NONE",
119 scan_freq=fst_test_common.fst_test_def_freq_g)
41a256ec
AN
120
121def disconnect_two_ap_sta_pairs(ap1, ap2, dev1, dev2):
122 dev1.disconnect()
123 dev2.disconnect()
124
125def external_sta_connect(sta, ap, **kwargs):
126 """Connects the external station to the given AP"""
127 if not isinstance(sta, WpaSupplicant):
128 raise Exception("Bad STA object")
129 if not isinstance(ap, FstAP):
130 raise Exception("Bad AP object to connect to")
131 hap = ap.get_instance()
132 sta.connect(ap.get_ssid(), **kwargs)
133
134def disconnect_external_sta(sta, ap, check_disconnect=True):
135 """Disconnects the external station from the AP"""
136 if not isinstance(sta, WpaSupplicant):
137 raise Exception("Bad STA object")
138 if not isinstance(ap, FstAP):
139 raise Exception("Bad AP object to connect to")
140 sta.request("DISCONNECT")
141 if check_disconnect:
142 hap = ap.get_instance()
143 ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
144 if ev is None:
145 raise Exception("No disconnection event received from %s" % ap.get_ssid())
146
147#
148# FstDevice class
149# This is the parent class for the AP (FstAP) and STA (FstSTA) that implements
150# FST functionality.
151#
152class FstDevice:
85eb89fe 153 def __init__(self, iface, fst_group, fst_pri, fst_llt=None, rsn=False):
41a256ec
AN
154 self.iface = iface
155 self.fst_group = fst_group
156 self.fst_pri = fst_pri
157 self.fst_llt = fst_llt # None llt means no llt parameter will be set
158 self.instance = None # Hostapd/WpaSupplicant instance
159 self.peer_obj = None # Peer object, must be a FstDevice child object
160 self.new_peer_addr = None # Peer MAC address for new session iface
161 self.old_peer_addr = None # Peer MAC address for old session iface
162 self.role = 'initiator' # Role: initiator/responder
163 s = self.grequest("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
164 if not s.startswith('OK'):
165 raise utils.HwsimSkip("FST not supported")
85eb89fe 166 self.rsn = rsn
41a256ec
AN
167
168 def ifname(self):
169 return self.iface
170
171 def get_instance(self):
172 """Gets the Hostapd/WpaSupplicant instance"""
173 raise Exception("Virtual get_instance() called!")
174
175 def get_own_mac_address(self):
176 """Gets the device's own MAC address"""
177 raise Exception("Virtual get_own_mac_address() called!")
178
179 def get_new_peer_addr(self):
180 return self.new_peer_addr
181
182 def get_old_peer_addr(self):
183 return self.old_peer_addr
184
185 def get_actual_peer_addr(self):
186 """Gets the peer address. A connected AP/station address is returned."""
187 raise Exception("Virtual get_actual_peer_addr() called!")
188
189 def grequest(self, req):
190 """Send request on the global control interface"""
191 raise Exception, "Virtual grequest() called!"
192
193 def wait_gevent(self, events, timeout=None):
194 """Wait for a list of events on the global interface"""
195 raise Exception("Virtual wait_gevent() called!")
196
197 def request(self, req):
198 """Issue a request to the control interface"""
199 h = self.get_instance()
200 return h.request(req)
201
202 def wait_event(self, events, timeout=None):
203 """Wait for an event from the control interface"""
204 h = self.get_instance()
205 if timeout is not None:
206 return h.wait_event(events, timeout=timeout)
207 else:
208 return h.wait_event(events)
209
210 def set_old_peer_addr(self, peer_addr=None):
211 """Sets the peer address"""
212 if peer_addr is not None:
213 self.old_peer_addr = peer_addr
214 else:
215 self.old_peer_addr = self.get_actual_peer_addr()
216
217 def set_new_peer_addr(self, peer_addr=None):
218 """Sets the peer address"""
219 if peer_addr is not None:
220 self.new_peer_addr = peer_addr
221 else:
222 self.new_peer_addr = self.get_actual_peer_addr()
223
224 def add_peer(self, obj, old_peer_addr=None, new_peer_addr=None):
225 """Add peer for FST session(s). 'obj' is a FstDevice subclass object.
226 The method must be called before add_session().
227 If peer_addr is not specified, the address of the currently connected
228 station is used."""
229 if not isinstance(obj, FstDevice):
230 raise Exception("Peer must be a FstDevice object")
231 self.peer_obj = obj
232 self.set_old_peer_addr(old_peer_addr)
233 self.set_new_peer_addr(new_peer_addr)
234
235 def get_peer(self):
236 """Returns peer object"""
237 return self.peer_obj
238
239 def set_fst_parameters(self, group_id=None, pri=None, llt=None):
240 """Change/set new FST parameters. Can be used to start FST sessions with
241 different FST parameters than defined in the configuration file."""
242 if group_id is not None:
243 self.fst_group = group_id
244 if pri is not None:
245 self.fst_pri = pri
246 if llt is not None:
247 self.fst_llt = llt
248
249 def get_local_mbies(self, ifname=None):
250 if_name = ifname if ifname is not None else self.iface
251 return self.grequest("FST-MANAGER TEST_REQUEST GET_LOCAL_MBIES " + if_name)
252
253 def add_session(self):
254 """Adds an FST session. add_peer() must be called calling this
255 function"""
256 if self.peer_obj is None:
257 raise Exception("Peer wasn't added before starting session")
8fb84690 258 self.dump_monitor()
41a256ec
AN
259 grp = ' ' + self.fst_group if self.fst_group != '' else ''
260 sid = self.grequest("FST-MANAGER SESSION_ADD" + grp)
261 sid = sid.strip()
262 if sid.startswith("FAIL"):
263 raise Exception("Cannot add FST session with groupid ==" + grp)
8fb84690 264 self.dump_monitor()
41a256ec
AN
265 return sid
266
267 def set_session_param(self, params):
268 request = "FST-MANAGER SESSION_SET"
269 if params is not None and params != '':
270 request = request + ' ' + params
271 return self.grequest(request)
272
d6d549c4
JM
273 def get_session_params(self, sid):
274 request = "FST-MANAGER SESSION_GET " + sid
275 res = self.grequest(request)
276 if res.startswith("FAIL"):
277 return None
278 params = {}
279 for i in res.splitlines():
280 p = i.split('=')
281 params[p[0]] = p[1]
282 return params
283
284 def iface_peers(self, ifname):
285 grp = self.fst_group if self.fst_group != '' else ''
286 res = self.grequest("FST-MANAGER IFACE_PEERS " + grp + ' ' + ifname)
287 if res.startswith("FAIL"):
288 return None
289 return res.splitlines()
290
291 def get_peer_mbies(self, ifname, peer_addr):
292 return self.grequest("FST-MANAGER GET_PEER_MBIES %s %s" % (ifname, peer_addr))
293
294 def list_ifaces(self):
295 grp = self.fst_group if self.fst_group != '' else ''
296 res = self.grequest("FST-MANAGER LIST_IFACES " + grp)
297 if res.startswith("FAIL"):
298 return None
299 ifaces = []
300 for i in res.splitlines():
301 p = i.split(':')
302 iface = {}
303 iface['name'] = p[0]
304 iface['priority'] = p[1]
305 iface['llt'] = p[2]
306 ifaces.append(iface)
307 return ifaces
308
309 def list_groups(self):
310 res = self.grequest("FST-MANAGER LIST_GROUPS")
311 if res.startswith("FAIL"):
312 return None
313 return res.splitlines()
314
41a256ec
AN
315 def configure_session(self, sid, new_iface, old_iface = None):
316 """Calls session_set for a number of parameters some of which are stored
317 in "self" while others are passed to this function explicitly. If
318 old_iface is None, current iface is used; if old_iface is an empty
319 string."""
8fb84690 320 self.dump_monitor()
41a256ec
AN
321 oldiface = old_iface if old_iface is not None else self.iface
322 s = self.set_session_param(sid + ' old_ifname=' + oldiface)
323 if not s.startswith("OK"):
324 raise Exception("Cannot set FST session old_ifname: " + s)
325 if new_iface is not None:
326 s = self.set_session_param(sid + " new_ifname=" + new_iface)
327 if not s.startswith("OK"):
328 raise Exception("Cannot set FST session new_ifname:" + s)
329 if self.new_peer_addr is not None and self.new_peer_addr != '':
330 s = self.set_session_param(sid + " new_peer_addr=" + self.new_peer_addr)
331 if not s.startswith("OK"):
332 raise Exception("Cannot set FST session peer address:" + s + " (new)")
333 if self.old_peer_addr is not None and self.old_peer_addr != '':
334 s = self.set_session_param(sid + " old_peer_addr=" + self.old_peer_addr)
335 if not s.startswith("OK"):
336 raise Exception("Cannot set FST session peer address:" + s + " (old)")
337 if self.fst_llt is not None and self.fst_llt != '':
338 s = self.set_session_param(sid + " llt=" + self.fst_llt)
339 if not s.startswith("OK"):
340 raise Exception("Cannot set FST session llt:" + s)
8fb84690 341 self.dump_monitor()
41a256ec
AN
342
343 def send_iface_attach_request(self, ifname, group, llt, priority):
344 request = "FST-ATTACH " + ifname + ' ' + group
345 if llt is not None:
346 request += " llt=" + llt
347 if priority is not None:
348 request += " priority=" + priority
349 res = self.grequest(request)
350 if not res.startswith("OK"):
351 raise Exception("Cannot attach FST iface: " + res)
352
353 def send_iface_detach_request(self, ifname):
354 res = self.grequest("FST-DETACH " + ifname)
355 if not res.startswith("OK"):
356 raise Exception("Cannot detach FST iface: " + res)
357
358 def send_session_setup_request(self, sid):
359 s = self.grequest("FST-MANAGER SESSION_INITIATE " + sid)
360 if not s.startswith('OK'):
361 raise Exception("Cannot send setup request: %s" % s)
362 return s
363
364 def send_session_setup_response(self, sid, response):
365 request = "FST-MANAGER SESSION_RESPOND " + sid + " " + response
366 s = self.grequest(request)
367 if not s.startswith('OK'):
368 raise Exception("Cannot send setup response: %s" % s)
369 return s
370
371 def send_test_session_setup_request(self, fsts_id,
372 additional_parameter = None):
373 request = "FST-MANAGER TEST_REQUEST SEND_SETUP_REQUEST " + fsts_id
374 if additional_parameter is not None:
375 request += " " + additional_parameter
376 s = self.grequest(request)
377 if not s.startswith('OK'):
378 raise Exception("Cannot send FST setup request: %s" % s)
379 return s
380
381 def send_test_session_setup_response(self, fsts_id,
382 response, additional_parameter = None):
383 request = "FST-MANAGER TEST_REQUEST SEND_SETUP_RESPONSE " + fsts_id + " " + response
384 if additional_parameter is not None:
385 request += " " + additional_parameter
386 s = self.grequest(request)
387 if not s.startswith('OK'):
388 raise Exception("Cannot send FST setup response: %s" % s)
389 return s
390
391 def send_test_ack_request(self, fsts_id):
392 s = self.grequest("FST-MANAGER TEST_REQUEST SEND_ACK_REQUEST " + fsts_id)
393 if not s.startswith('OK'):
394 raise Exception("Cannot send FST ack request: %s" % s)
395 return s
396
397 def send_test_ack_response(self, fsts_id):
398 s = self.grequest("FST-MANAGER TEST_REQUEST SEND_ACK_RESPONSE " + fsts_id)
399 if not s.startswith('OK'):
400 raise Exception("Cannot send FST ack response: %s" % s)
401 return s
402
403 def send_test_tear_down(self, fsts_id):
404 s = self.grequest("FST-MANAGER TEST_REQUEST SEND_TEAR_DOWN " + fsts_id)
405 if not s.startswith('OK'):
406 raise Exception("Cannot send FST tear down: %s" % s)
407 return s
408
409 def get_fsts_id_by_sid(self, sid):
410 s = self.grequest("FST-MANAGER TEST_REQUEST GET_FSTS_ID " + sid)
411 if s == ' ' or s.startswith('FAIL'):
4390030a 412 raise Exception("Cannot get fsts_id for sid == %s" % sid)
41a256ec
AN
413 return int(s)
414
415 def wait_for_iface_event(self, timeout):
416 while True:
417 ev = self.wait_gevent(["FST-EVENT-IFACE"], timeout)
418 if ev is None:
419 raise Exception("No FST-EVENT-IFACE received")
420 event = parse_fst_iface_event(ev)
421 if event is None:
422 # We can't parse so it's not our event, wait for next one
423 continue
424 return event
425
426 def wait_for_session_event(self, timeout, events_to_ignore=[],
427 events_to_count=[]):
428 while True:
429 ev = self.wait_gevent(["FST-EVENT-SESSION"], timeout)
430 if ev is None:
431 raise Exception("No FST-EVENT-SESSION received")
432 event = parse_fst_session_event(ev)
433 if event is None:
434 # We can't parse so it's not our event, wait for next one
435 continue
436 if len(events_to_ignore) > 0:
437 if event['type'] in events_to_ignore:
438 continue
439 elif len(events_to_count) > 0:
440 if not event['type'] in events_to_count:
441 continue
442 return event
443
444 def initiate_session(self, sid, response="accept"):
445 """Initiates FST session with given session id 'sid'.
446 'response' is the session respond answer: "accept", "reject", or a
447 special "timeout" value to skip the response in order to test session
448 timeouts.
449 Returns: "OK" - session has been initiated, otherwise the reason for the
450 reset: REASON_REJECT, REASON_STT."""
451 strsid = ' ' + sid if sid != '' else ''
452 s = self.grequest("FST-MANAGER SESSION_INITIATE"+ strsid)
453 if not s.startswith('OK'):
454 raise Exception("Cannot initiate fst session: %s" % s)
455 ev = self.peer_obj.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
456 if ev is None:
457 raise Exception("No FST-EVENT-SESSION received")
458 # We got FST event
459 event = parse_fst_session_event(ev)
460 if event == None:
461 raise Exception("Unrecognized FST event: " % ev)
462 if event['type'] != 'EVENT_FST_SETUP':
463 raise Exception("Expected FST_SETUP event, got: " + event['type'])
464 ev = self.peer_obj.wait_gevent(["FST-EVENT-SESSION"], timeout=5)
465 if ev is None:
466 raise Exception("No FST-EVENT-SESSION received")
467 event = parse_fst_session_event(ev)
468 if event == None:
469 raise Exception("Unrecognized FST event: " % ev)
470 if event['type'] != 'EVENT_FST_SESSION_STATE':
471 raise Exception("Expected EVENT_FST_SESSION_STATE event, got: " + event['type'])
472 if event['new_state'] != "SETUP_COMPLETION":
473 raise Exception("Expected new state SETUP_COMPLETION, got: " + event['new_state'])
474 if response == '':
475 return 'OK'
476 if response != "timeout":
477 s = self.peer_obj.grequest("FST-MANAGER SESSION_RESPOND "+ event['id'] + " " + response) # Or reject
478 if not s.startswith('OK'):
479 raise Exception("Error session_respond: %s" % s)
480 # Wait for EVENT_FST_SESSION_STATE events. We should get at least 2
481 # events. The 1st event will be EVENT_FST_SESSION_STATE
482 # old_state=INITIAL new_state=SETUP_COMPLETED. The 2nd event will be
483 # either EVENT_FST_ESTABLISHED with the session id or
484 # EVENT_FST_SESSION_STATE with new_state=INITIAL if the session was
485 # reset, the reason field will tell why.
486 result = ''
487 while result == '':
488 ev = self.wait_gevent(["FST-EVENT-SESSION"], timeout=5)
489 if ev is None:
490 break # No session event received
491 event = parse_fst_session_event(ev)
492 if event == None:
493 # We can't parse so it's not our event, wait for next one
494 continue
495 if event['type'] == 'EVENT_FST_ESTABLISHED':
496 result = "OK"
497 break
498 elif event['type'] == "EVENT_FST_SESSION_STATE":
499 if event['new_state'] == "INITIAL":
500 # Session was reset, the only reason to get back to initial
501 # state.
502 result = event['reason']
503 break
504 if result == '':
505 raise Exception("No event for session respond")
506 return result
507
508 def transfer_session(self, sid):
509 """Transfers the session. 'sid' is the session id. 'hsta' is the
510 station-responder object.
511 Returns: REASON_SWITCH - the session has been transferred successfully
512 or a REASON_... reported by the reset event."""
513 request = "FST-MANAGER SESSION_TRANSFER"
8fb84690 514 self.dump_monitor()
41a256ec
AN
515 if sid != '':
516 request += ' ' + sid
517 s = self.grequest(request)
518 if not s.startswith('OK'):
519 raise Exception("Cannot transfer fst session: %s" % s)
520 result = ''
521 while result == '':
522 ev = self.peer_obj.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
523 if ev is None:
524 raise Exception("Missing session transfer event")
525 # We got FST event. We expect TRANSITION_CONFIRMED state and then
526 # INITIAL (reset) with the reason (e.g. "REASON_SWITCH").
527 # Right now we'll be waiting for the reset event and record the
528 # reason.
529 event = parse_fst_session_event(ev)
530 if event == None:
531 raise Exception("Unrecognized FST event: " % ev)
532 if event['new_state'] == 'INITIAL':
533 result = event['reason']
8fb84690 534 self.dump_monitor()
41a256ec
AN
535 return result
536
537 def wait_for_tear_down(self):
538 ev = self.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
539 if ev is None:
540 raise Exception("No FST-EVENT-SESSION received")
541 # We got FST event
542 event = parse_fst_session_event(ev)
543 if event == None:
544 raise Exception("Unrecognized FST event: " % ev)
545 if event['type'] != 'EVENT_FST_SESSION_STATE':
546 raise Exception("Expected EVENT_FST_SESSION_STATE event, got: " + event['type'])
547 if event['new_state'] != "INITIAL":
548 raise Exception("Expected new state INITIAL, got: " + event['new_state'])
549 if event['reason'] != 'REASON_TEARDOWN':
550 raise Exception("Expected reason REASON_TEARDOWN, got: " + event['reason'])
551
552 def teardown_session(self, sid):
553 """Tears down FST session with a given session id ('sid')"""
554 strsid = ' ' + sid if sid != '' else ''
555 s = self.grequest("FST-MANAGER SESSION_TEARDOWN" + strsid)
556 if not s.startswith('OK'):
557 raise Exception("Cannot tear down fst session: %s" % s)
558 self.peer_obj.wait_for_tear_down()
559
560
561 def remove_session(self, sid, wait_for_tear_down=True):
562 """Removes FST session with a given session id ('sid')"""
563 strsid = ' ' + sid if sid != '' else ''
564 s = self.grequest("FST-MANAGER SESSION_REMOVE" + strsid)
565 if not s.startswith('OK'):
566 raise Exception("Cannot remove fst session: %s" % s)
567 if wait_for_tear_down == True:
568 self.peer_obj.wait_for_tear_down()
569
570 def remove_all_sessions(self):
571 """Removes FST session with a given session id ('sid')"""
572 grp = ' ' + self.fst_group if self.fst_group != '' else ''
573 s = self.grequest("FST-MANAGER LIST_SESSIONS" + grp)
574 if not s.startswith('FAIL'):
575 for sid in s.splitlines():
576 sid = sid.strip()
577 if len(sid) != 0:
578 self.remove_session(sid, wait_for_tear_down=False)
579
580
581#
582# FstAP class
583#
584class FstAP (FstDevice):
585 def __init__(self, iface, ssid, mode, chan, fst_group, fst_pri,
85eb89fe 586 fst_llt=None, rsn=False):
41a256ec
AN
587 """If fst_group is empty, then FST parameters will not be set
588 If fst_llt is empty, the parameter will not be set and the default value
589 is expected to be configured."""
590 self.ssid = ssid
591 self.mode = mode
592 self.chan = chan
593 self.reg_ctrl = fst_test_common.HapdRegCtrl()
594 self.reg_ctrl.add_ap(iface, self.chan)
595 self.global_instance = hostapd.HostapdGlobal()
85eb89fe 596 FstDevice.__init__(self, iface, fst_group, fst_pri, fst_llt, rsn)
41a256ec 597
d99ed42a 598 def start(self, return_early=False):
41a256ec
AN
599 """Starts AP the "standard" way as it was intended by hostapd tests.
600 This will work only when FST supports fully dynamically loading
601 parameters in hostapd."""
602 params = {}
603 params['ssid'] = self.ssid
604 params['hw_mode'] = self.mode
605 params['channel'] = self.chan
606 params['country_code'] = 'US'
85eb89fe
JM
607 if self.rsn:
608 params['wpa'] = '2'
609 params['wpa_key_mgmt'] = 'WPA-PSK'
610 params['rsn_pairwise'] = 'CCMP'
611 params['wpa_passphrase'] = '12345678'
41a256ec
AN
612 self.hapd=hostapd.add_ap(self.iface, params)
613 if not self.hapd.ping():
614 raise Exception("Could not ping FST hostapd")
615 self.reg_ctrl.start()
616 self.get_global_instance()
d99ed42a
JM
617 if return_early:
618 return self.hapd
41a256ec
AN
619 if len(self.fst_group) != 0:
620 self.send_iface_attach_request(self.iface, self.fst_group,
621 self.fst_llt, self.fst_pri)
622 return self.hapd
623
624 def stop(self):
625 """Removes the AP, To be used when dynamic fst APs are implemented in
626 hostapd."""
627 if len(self.fst_group) != 0:
628 self.remove_all_sessions()
78185978
JM
629 try:
630 self.send_iface_detach_request(self.iface)
631 except Exception, e:
632 logger.info(str(e))
41a256ec
AN
633 self.reg_ctrl.stop()
634 del self.global_instance
635 self.global_instance = None
636
637 def get_instance(self):
638 """Return the Hostapd/WpaSupplicant instance"""
639 if self.instance is None:
640 self.instance = hostapd.Hostapd(self.iface)
641 return self.instance
642
643 def get_global_instance(self):
644 return self.global_instance
645
646 def get_own_mac_address(self):
647 """Gets the device's own MAC address"""
648 h = self.get_instance()
649 status = h.get_status()
650 return status['bssid[0]']
651
652 def get_actual_peer_addr(self):
653 """Gets the peer address. A connected station address is returned."""
654 # Use the device instance, the global control interface doesn't have
655 # station address
656 h = self.get_instance()
657 sta = h.get_sta(None)
658 if sta is None or 'addr' not in sta:
659 # Maybe station is not connected?
660 addr = None
661 else:
662 addr=sta['addr']
663 return addr
664
665 def grequest(self, req):
666 """Send request on the global control interface"""
667 logger.debug("FstAP::grequest: " + req)
668 h = self.get_global_instance()
669 return h.request(req)
670
671 def wait_gevent(self, events, timeout=None):
672 """Wait for a list of events on the global interface"""
673 h = self.get_global_instance()
674 if timeout is not None:
675 return h.wait_event(events, timeout=timeout)
676 else:
677 return h.wait_event(events)
678
679 def get_ssid(self):
680 return self.ssid
681
8fb84690
JM
682 def dump_monitor(self):
683 """Dump control interface monitor events"""
684 if self.instance:
685 self.instance.dump_monitor()
686
41a256ec
AN
687#
688# FstSTA class
689#
690class FstSTA (FstDevice):
85eb89fe 691 def __init__(self, iface, fst_group, fst_pri, fst_llt=None, rsn=False):
41a256ec
AN
692 """If fst_group is empty, then FST parameters will not be set
693 If fst_llt is empty, the parameter will not be set and the default value
694 is expected to be configured."""
85eb89fe 695 FstDevice.__init__(self, iface, fst_group, fst_pri, fst_llt, rsn)
41a256ec
AN
696 self.connected = None # FstAP object the station is connected to
697
698 def start(self):
699 """Current implementation involves running another instance of
700 wpa_supplicant with fixed FST STAs configurations. When any type of
701 dynamic STA loading is implemented, rewrite the function similarly to
702 FstAP."""
703 h = self.get_instance()
704 h.interface_add(self.iface, drv_params="force_connect_cmd=1")
705 if not h.global_ping():
706 raise Exception("Could not ping FST wpa_supplicant")
707 if len(self.fst_group) != 0:
708 self.send_iface_attach_request(self.iface, self.fst_group,
709 self.fst_llt, self.fst_pri)
710 return None
711
712 def stop(self):
713 """Removes the STA. In a static (temporary) implementation does nothing,
714 the STA will be removed when the fst wpa_supplicant process is killed by
715 fstap.cleanup()."""
716 h = self.get_instance()
8fb84690 717 h.dump_monitor()
41a256ec
AN
718 if len(self.fst_group) != 0:
719 self.remove_all_sessions()
720 self.send_iface_detach_request(self.iface)
8fb84690 721 h.dump_monitor()
41a256ec
AN
722 h.interface_remove(self.iface)
723 h.close_ctrl()
724 del h
725 self.instance = None
726
727 def get_instance(self):
728 """Return the Hostapd/WpaSupplicant instance"""
729 if self.instance is None:
730 self.instance = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
731 return self.instance
732
733 def get_own_mac_address(self):
734 """Gets the device's own MAC address"""
735 h = self.get_instance()
736 status = h.get_status()
737 return status['address']
738
739 def get_actual_peer_addr(self):
740 """Gets the peer address. A connected station address is returned"""
741 h = self.get_instance()
742 status = h.get_status()
743 return status['bssid']
744
745 def grequest(self, req):
746 """Send request on the global control interface"""
747 logger.debug("FstSTA::grequest: " + req)
748 h = self.get_instance()
749 return h.global_request(req)
750
751 def wait_gevent(self, events, timeout=None):
752 """Wait for a list of events on the global interface"""
753 h = self.get_instance()
754 if timeout is not None:
755 return h.wait_global_event(events, timeout=timeout)
756 else:
757 return h.wait_global_event(events)
758
759 def scan(self, freq=None, no_wait=False, only_new=False):
760 """Issue Scan with given parameters. Returns the BSS dictionary for the
761 AP found (the 1st BSS found. TODO: What if the AP required is not the
762 1st in list?) or None if no BSS found. None call be also a result of
763 no_wait=True. Note, request("SCAN_RESULTS") can be used to get all the
764 results at once."""
765 h = self.get_instance()
8fb84690 766 h.dump_monitor()
41a256ec
AN
767 h.scan(None, freq, no_wait, only_new)
768 r = h.get_bss('0')
8fb84690 769 h.dump_monitor()
41a256ec
AN
770 return r
771
772 def connect(self, ap, **kwargs):
773 """Connects to the given AP"""
774 if not isinstance(ap, FstAP):
775 raise Exception("Bad AP object to connect to")
776 h = self.get_instance()
777 hap = ap.get_instance()
8fb84690 778 h.dump_monitor()
41a256ec 779 h.connect(ap.get_ssid(), **kwargs)
8fb84690 780 h.dump_monitor()
41a256ec
AN
781 self.connected = ap
782
783 def connect_to_external_ap(self, ap, ssid, check_connection=True, **kwargs):
784 """Connects to the given external AP"""
785 if not isinstance(ap, hostapd.Hostapd):
786 raise Exception("Bad AP object to connect to")
787 h = self.get_instance()
8fb84690 788 h.dump_monitor()
41a256ec
AN
789 h.connect(ssid, **kwargs)
790 self.connected = ap
791 if check_connection:
792 ev = ap.wait_event([ "AP-STA-CONNECTED" ], timeout=10)
793 if ev is None:
794 self.connected = None
795 raise Exception("No connection event received from %s" % ssid)
8fb84690 796 h.dump_monitor()
41a256ec
AN
797
798 def disconnect(self, check_disconnect=True):
799 """Disconnects from the AP the station is currently connected to"""
800 if self.connected is not None:
801 h = self.get_instance()
8fb84690 802 h.dump_monitor()
41a256ec
AN
803 h.request("DISCONNECT")
804 if check_disconnect:
805 hap = self.connected.get_instance()
806 ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
807 if ev is None:
808 raise Exception("No disconnection event received from %s" % self.connected.get_ssid())
8fb84690 809 h.dump_monitor()
41a256ec
AN
810 self.connected = None
811
812
813 def disconnect_from_external_ap(self, check_disconnect=True):
814 """Disconnects from the external AP the station is currently connected
815 to"""
816 if self.connected is not None:
817 h = self.get_instance()
8fb84690 818 h.dump_monitor()
41a256ec
AN
819 h.request("DISCONNECT")
820 if check_disconnect:
821 hap = self.connected
822 ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
823 if ev is None:
824 raise Exception("No disconnection event received from AP")
8fb84690 825 h.dump_monitor()
41a256ec 826 self.connected = None
8fb84690
JM
827
828 def dump_monitor(self):
829 """Dump control interface monitor events"""
830 if self.instance:
831 self.instance.dump_monitor()