• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "nfc_integration_fuzzer_impl.h"
2 
3 #include <android-base/logging.h>
4 #include <android-base/stringprintf.h>
5 #include <fuzzer/FuzzedDataProvider.h>
6 
7 #include "nfa_ce_api.h"
8 #include "nfa_ee_api.h"
9 #include "nfa_p2p_api.h"
10 #include "nfa_rw_api.h"
11 #include "nfa_sys.h"
12 #include "nfc_api.h"
13 #include "nfc_int.h"
14 #include "nfc_task_helpers.h"
15 #include "rw_int.h"
16 
17 extern uint32_t g_tick_count;
18 extern tRW_CB rw_cb;
19 
20 FuzzedDataProvider* g_fuzzed_data;
21 
22 static bool g_saw_event = false;
23 static tNFA_EE_DISCOVER_REQ g_ee_info;
24 
fuzz_cback(tRW_EVENT event,tRW_DATA * p_rw_data)25 void fuzz_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
26   (void)event;
27   (void)p_rw_data;
28 }
29 constexpr int32_t kMaxFramesSize =
30     USHRT_MAX - NFC_HDR_SIZE - NCI_MSG_OFFSET_SIZE - NCI_DATA_HDR_SIZE - 3;
31 
nfa_dm_callback(uint8_t event,tNFA_DM_CBACK_DATA *)32 static void nfa_dm_callback(uint8_t event, tNFA_DM_CBACK_DATA*) {
33   g_saw_event = true;
34   LOG(INFO) << android::base::StringPrintf("nfa_dm_callback got event %d",
35                                            event);
36 }
37 
nfa_conn_callback(uint8_t event,tNFA_CONN_EVT_DATA *)38 static void nfa_conn_callback(uint8_t event, tNFA_CONN_EVT_DATA*) {
39   LOG(INFO) << android::base::StringPrintf("nfa_conn_callback got event %d",
40                                            event);
41   g_saw_event = true;
42 }
43 
nfa_ee_callback(tNFA_EE_EVT event,tNFA_EE_CBACK_DATA * p_data)44 static void nfa_ee_callback(tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* p_data) {
45   switch (event) {
46     case NFA_EE_DISCOVER_REQ_EVT: {
47       memcpy(&g_ee_info, &p_data->discover_req, sizeof(g_ee_info));
48       break;
49     }
50   }
51 }
52 
53 // From packages/apps/Nfc/nci/jni/PeerToPeer.cpp
54 #define LLCP_DATA_LINK_TIMEOUT 2000
55 
56 void nfc_process_timer_evt(void);
nfa_p2p_callback(tNFA_P2P_EVT,tNFA_P2P_EVT_DATA *)57 void nfa_p2p_callback(tNFA_P2P_EVT, tNFA_P2P_EVT_DATA*) {}
58 
GetProtocol(const Protocol & protocol)59 static tNFC_PROTOCOL GetProtocol(const Protocol& protocol) {
60   switch (protocol.value()) {
61     case Protocol::FUZZER_PROTOCOL_UNKNOWN: {
62       return NFC_PROTOCOL_UNKNOWN;
63     }
64     case Protocol::FUZZER_PROTOCOL_T1T: {
65       return NFC_PROTOCOL_T1T;
66     }
67     case Protocol::FUZZER_PROTOCOL_T2T: {
68       return NFC_PROTOCOL_T2T;
69     }
70     case Protocol::FUZZER_PROTOCOL_T3T: {
71       return NFC_PROTOCOL_T3T;
72     }
73     case Protocol::FUZZER_PROTOCOL_T5T: {
74       return NFC_PROTOCOL_T5T;
75     }
76     case Protocol::FUZZER_PROTOCOL_ISO_DEP: {
77       return NFC_PROTOCOL_ISO_DEP;
78     }
79     case Protocol::FUZZER_PROTOCOL_NFC_DEP: {
80       return NFC_PROTOCOL_NFC_DEP;
81     }
82     case Protocol::FUZZER_PROTOCOL_MIFARE: {
83       return NFC_PROTOCOL_MIFARE;
84     }
85     case Protocol::FUZZER_PROTOCOL_ISO15693: {
86       return NFC_PROTOCOL_ISO15693;
87     }
88     case Protocol::FUZZER_PROTOCOL_B_PRIME: {
89       return NFC_PROTOCOL_B_PRIME;
90     }
91     case Protocol::FUZZER_PROTOCOL_KOVIO: {
92       return NFC_PROTOCOL_KOVIO;
93     }
94   }
95 }
96 
GetDiscovery(const DiscoveryType & type)97 static tNFC_DISCOVERY_TYPE GetDiscovery(const DiscoveryType& type) {
98   switch (type.value()) {
99     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_A: {
100       return NFC_DISCOVERY_TYPE_POLL_A;
101     }
102     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_B: {
103       return NFC_DISCOVERY_TYPE_POLL_B;
104     }
105     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_F: {
106       return NFC_DISCOVERY_TYPE_POLL_F;
107     }
108     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_V: {
109       return NFC_DISCOVERY_TYPE_POLL_V;
110     }
111     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_A_ACTIVE: {
112       return NFC_DISCOVERY_TYPE_POLL_A_ACTIVE;
113     }
114     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_F_ACTIVE: {
115       return NFC_DISCOVERY_TYPE_POLL_F_ACTIVE;
116     }
117     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_A: {
118       return NFC_DISCOVERY_TYPE_LISTEN_A;
119     }
120     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_B: {
121       return NFC_DISCOVERY_TYPE_LISTEN_B;
122     }
123     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_F: {
124       return NFC_DISCOVERY_TYPE_LISTEN_F;
125     }
126     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_A_ACTIVE: {
127       return NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE;
128     }
129     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_F_ACTIVE: {
130       return NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE;
131     }
132     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_ISO15693: {
133       return NFC_DISCOVERY_TYPE_LISTEN_ISO15693;
134     }
135     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_B_PRIME: {
136       return NFC_DISCOVERY_TYPE_POLL_B_PRIME;
137     }
138     case DiscoveryType::FUZZER_DISCOVERY_TYPE_POLL_KOVIO: {
139       return NFC_DISCOVERY_TYPE_POLL_KOVIO;
140     }
141     case DiscoveryType::FUZZER_DISCOVERY_TYPE_LISTEN_B_PRIME: {
142       return NFC_DISCOVERY_TYPE_LISTEN_B_PRIME;
143     }
144   }
145 }
146 
SerializeTechParameters(const tNFC_RF_TECH_PARAMS & params)147 std::vector<uint8_t> SerializeTechParameters(
148     const tNFC_RF_TECH_PARAMS& params) {
149   std::vector<uint8_t> vec;
150 
151   switch (params.mode) {
152     case NCI_DISCOVERY_TYPE_POLL_A: {
153       const tNFC_RF_PA_PARAMS* pa = &params.param.pa;
154       vec.push_back(pa->sens_res[0]);
155       vec.push_back(pa->sens_res[1]);
156       vec.push_back(pa->nfcid1_len);
157       vec.insert(vec.end(), pa->nfcid1, pa->nfcid1 + pa->nfcid1_len);
158 
159       // sel_rsp of 0 is the same as not having it, so we just always send it
160       vec.push_back(1);
161       vec.push_back(pa->sel_rsp);
162 
163       vec.push_back(pa->hr_len);
164       vec.insert(vec.end(), pa->hr, pa->hr + pa->hr_len);
165       break;
166     }
167     default: {
168       abort();
169     }
170   }
171 
172   return vec;
173 }
174 
175 // Serialize an NFC Activation event back to the spec wire format
SerializeNfcActivate(const tNFC_ACTIVATE_DEVT & activate,uint8_t buff_size,uint8_t num_buff,const std::string & rf_tech_param_buffer,const std::string & intf_param_buffer)176 std::vector<uint8_t> SerializeNfcActivate(
177     const tNFC_ACTIVATE_DEVT& activate, uint8_t buff_size, uint8_t num_buff,
178     const std::string& rf_tech_param_buffer,
179     const std::string& intf_param_buffer) {
180   std::vector<uint8_t> packet;
181   packet.push_back(activate.rf_disc_id);
182   packet.push_back(activate.intf_param.type);
183   packet.push_back(activate.protocol);
184   packet.push_back(activate.rf_tech_param.mode);
185   packet.push_back(buff_size);
186   packet.push_back(num_buff);
187 
188   std::vector<uint8_t> tech_parameters(
189       rf_tech_param_buffer.begin(),
190       rf_tech_param_buffer
191           .end());  // = SerializeTechParameters(activate.rf_tech_param);
192   if (tech_parameters.size() > 256) {
193     tech_parameters.resize(256);
194   }
195   packet.push_back(tech_parameters.size());
196   packet.insert(packet.end(), tech_parameters.begin(), tech_parameters.end());
197 
198   packet.push_back(activate.data_mode);
199   packet.push_back(activate.tx_bitrate);
200   packet.push_back(activate.rx_bitrate);
201 
202   std::vector<uint8_t> activation_parameters(intf_param_buffer.begin(),
203                                              intf_param_buffer.end());
204   if (activation_parameters.size() > 256) {
205     activation_parameters.resize(256);
206   }
207 
208   packet.push_back(activation_parameters.size());
209   packet.insert(packet.end(), activation_parameters.begin(),
210                 activation_parameters.end());
211   return packet;
212 }
213 
DoRfManageIntfActivated(const RfManageIntfActivated & activated)214 void DoRfManageIntfActivated(const RfManageIntfActivated& activated) {
215   // The event we want to generate
216   tNFC_ACTIVATE_DEVT activate_event = {};
217   activate_event.rf_disc_id = activated.rf_discovery_id();
218   activate_event.protocol = GetProtocol(activated.rf_protocol());
219   activate_event.data_mode = GetDiscovery(activated.data_mode());
220   activate_event.tx_bitrate = activated.tx_bitrate();
221   activate_event.rx_bitrate = activated.rx_bitrate();
222   uint8_t buff_size = activated.buff_size();
223   uint8_t num_buff = activated.num_buff();
224 
225   std::vector<uint8_t> packet = SerializeNfcActivate(
226       activate_event, buff_size, num_buff, activated.rf_tech_param_buffer(),
227       activated.intf_param_buffer());
228 
229   g_fake_hal->SimulatePacketArrival(NCI_MT_NTF, 0, NCI_GID_RF_MANAGE,
230                                     NCI_MSG_RF_INTF_ACTIVATED, packet.data(),
231                                     packet.size());
232 }
233 
DoRfManagementNtf(const RfManagementNtf & ntf)234 void DoRfManagementNtf(const RfManagementNtf& ntf) {
235   switch (ntf.opcode_case()) {
236     case RfManagementNtf::kIntfActivated: {
237       DoRfManageIntfActivated(ntf.intf_activated());
238       break;
239     }
240     case RfManagementNtf::OPCODE_NOT_SET: {
241       break;
242     }
243   }
244 }
245 
DoMtNtf(const MtNtf & ntf)246 void DoMtNtf(const MtNtf& ntf) {
247   switch (ntf.gid_case()) {
248     case MtNtf::kRfManage: {
249       DoRfManagementNtf(ntf.rf_manage());
250       break;
251     }
252     case MtNtf::GID_NOT_SET: {
253       break;
254     }
255   }
256 }
257 
DoStructuredPacket(const SimulateStructuredPacket & packet)258 void DoStructuredPacket(const SimulateStructuredPacket& packet) {
259   switch (packet.packet_case()) {
260     case SimulateStructuredPacket::kNtf: {
261       DoMtNtf(packet.ntf());
262       break;
263     }
264     case SimulateStructuredPacket::PACKET_NOT_SET: {
265       break;
266     }
267   }
268 }
269 
DoPacket(const SimulatePacketArrival & packet)270 void DoPacket(const SimulatePacketArrival& packet) {
271   uint8_t mt = packet.mt();
272   uint8_t pbf = packet.pbf();
273   uint8_t gid = packet.gid();
274   uint8_t opcode = static_cast<uint8_t>(packet.opcode());
275   bool need_flush = false;
276   if (mt == NCI_MT_DATA) {
277     // The gid field will be used as the connection ID. We should handle this
278     // a lot better but for now we let the existing gid enum get interpreted
279     // as a connection ID.
280     // gid = 0;
281     opcode = 0;
282   }
283 
284   g_fake_hal->SimulatePacketArrival(mt, pbf, gid, opcode,
285                                     (unsigned char*)packet.packet().data(),
286                                     packet.packet().size());
287   if (need_flush) {
288     DoAllTasks(false);
289   }
290 }
291 
DoOneCommand(std::vector<std::vector<uint8_t>> & bytes_container,const Command & command)292 void NfcIntegrationFuzzer::DoOneCommand(
293     std::vector<std::vector<uint8_t>>& bytes_container,
294     const Command& command) {
295   switch (command.command_case()) {
296     case Command::kSimulatePacketArrival: {
297       DoPacket(command.simulate_packet_arrival());
298       break;
299     }
300     case Command::kSimulateHalEvent: {
301       g_fake_hal->SimulateHALEvent(command.simulate_hal_event().hal_event(),
302                                    command.simulate_hal_event().hal_status());
303       break;
304     }
305     case Command::kSimulateStructuredPacket: {
306       DoStructuredPacket(command.simulate_structured_packet());
307       break;
308     }
309     case Command::kSendRawFrame: {
310       std::vector<uint8_t> frame(
311           command.send_raw_frame().data(),
312           command.send_raw_frame().data() + command.send_raw_frame().size());
313       uint16_t frameSize =
314           frame.size() <= kMaxFramesSize ? frame.size() : kMaxFramesSize;
315       NFA_SendRawFrame(frame.data(), frameSize,
316                        /*presence check start delay*/ 0);
317       break;
318     }
319     case Command::kDoNciMessages: {
320       nfc_process_nci_messages();
321       break;
322     }
323     case Command::kDoNfaTasks: {
324       nfc_process_nfa_messages();
325       break;
326     }
327     case Command::kSimulateTimerEvent: {
328       nfc_process_timer_evt();
329       break;
330     }
331     case Command::kSimulateQuickTimerEvent: {
332       nfc_process_quick_timer_evt();
333       break;
334     }
335     case Command::kSelect: {
336       NFA_Select(command.select().rf_select_id(),
337                  GetProtocol(command.select().protocol()),
338                  command.select().rf_interface());
339       break;
340     }
341     case Command::kConfigureUiccListenTech: {
342       if (g_ee_info.num_ee > 0) {
343         uint8_t handle = command.configure_uicc_listen_tech().ee_handle();
344         handle = g_ee_info.ee_disc_info[handle % g_ee_info.num_ee].ee_handle;
345         NFA_CeConfigureUiccListenTech(
346             handle, command.configure_uicc_listen_tech().tech_mask());
347         NFA_EeClearDefaultTechRouting(handle, 0xFF);
348         NFA_EeSetDefaultTechRouting(handle, 0xFF, 0, 0, 0, 0, 0);
349       }
350       break;
351     }
352     case Command::kRegisterT3T: {
353       uint8_t nfcid2[NCI_RF_F_UID_LEN] = {};
354       uint8_t t3tPmm[NCI_T3T_PMM_LEN] = {};
355       NFA_CeRegisterFelicaSystemCodeOnDH(0, nfcid2, t3tPmm, nfa_conn_callback);
356       const uint8_t SYS_CODE_PWR_STATE_HOST = 0x01;
357       NFA_EeAddSystemCodeRouting(0, NCI_DH_ID, SYS_CODE_PWR_STATE_HOST);
358       break;
359     }
360     case Command::kStartRfDiscovery: {
361       NFA_StartRfDiscovery();
362       break;
363     }
364     case Command::kStopRfDiscovery: {
365       NFA_StopRfDiscovery();
366       break;
367     }
368     case Command::kSetIsoListenTech: {
369       NFA_CeSetIsoDepListenTech(
370           fuzzed_data_.ConsumeIntegralInRange<uint8_t>(0, 0xFF));
371       NFA_CeRegisterAidOnDH(nullptr, 0, nfa_conn_callback);
372       break;
373     }
374     case Command::kRwFormatTag: {
375       NFA_RwFormatTag();
376       break;
377     }
378     case Command::kRwPresenceCheck: {
379       NFA_RwPresenceCheck(command.rw_presence_check().option());
380       break;
381     }
382     case Command::kRwSetTagReadOnly: {
383       NFA_RwSetTagReadOnly(command.rw_set_tag_read_only());
384       break;
385     }
386     case Command::kEeUpdateNow: {
387       NFA_EeUpdateNow();
388       break;
389     }
390     case Command::kEeAddAidRouting: {
391       uint8_t handle = command.ee_add_aid_routing().ee_handle();
392       if (g_ee_info.num_ee) {
393         handle = g_ee_info.ee_disc_info[handle % g_ee_info.num_ee].ee_handle;
394       }
395       std::vector<uint8_t> aid(command.ee_add_aid_routing().aid().data(),
396                                command.ee_add_aid_routing().aid().data() +
397                                    command.ee_add_aid_routing().aid().size());
398       tNFA_EE_PWR_STATE power_state =
399           command.ee_add_aid_routing().power_state();
400       uint8_t aidInfo = command.ee_add_aid_routing().aid_info();
401       NFA_EeAddAidRouting(handle, aid.size(), aid.data(), power_state, aidInfo);
402       break;
403     }
404     case Command::kReadNdef: {
405       NFA_RwReadNDef();
406       break;
407     }
408     case Command::kDetectNdef: {
409       NFA_RwDetectNDef();
410       break;
411     }
412     case Command::kWriteNdef: {
413       bytes_container.emplace_back(command.write_ndef().size() % 1024);
414       NFA_RwWriteNDef(bytes_container.back().data(),
415                       bytes_container.back().size());
416       break;
417     }
418     case Command::kP2PRegisterServer: {
419       NFA_P2pSetLLCPConfig(LLCP_MAX_MIU, LLCP_OPT_VALUE, LLCP_WAITING_TIME,
420                            LLCP_LTO_VALUE, 0, 0, LLCP_DELAY_RESP_TIME,
421                            LLCP_DATA_LINK_TIMEOUT,
422                            LLCP_DELAY_TIME_TO_SEND_FIRST_PDU);
423       NFA_P2pRegisterServer(
424           command.p2p_register_server().server_sap() & 0xFF, NFA_P2P_DLINK_TYPE,
425           (char*)command.p2p_register_server().service_name().c_str(),
426           nfa_p2p_callback);
427       break;
428     }
429     case Command::kP2PAcceptConn: {
430       NFA_P2pAcceptConn(command.p2p_accept_conn().handle() & 0xFF,
431                         command.p2p_accept_conn().miu() & 0xFFFF,
432                         command.p2p_accept_conn().rw() & 0xFF);
433       break;
434     }
435     case Command::kP2PRegisterClient: {
436       NFA_P2pRegisterClient(NFA_P2P_DLINK_TYPE, nfa_p2p_callback);
437       break;
438     }
439     case Command::kP2PDeregister: {
440       NFA_P2pDeregister(command.p2p_deregister());
441       break;
442     }
443     case Command::kP2PConnectBySap: {
444       NFA_P2pConnectBySap(command.p2p_connect_by_sap().handle(),
445                           command.p2p_connect_by_sap().dsap(),
446                           command.p2p_connect_by_sap().miu(),
447                           command.p2p_connect_by_sap().rw());
448       break;
449     }
450     case Command::kP2PConnectByName: {
451       NFA_P2pConnectByName(
452           command.p2p_connect_by_name().client_handle(),
453           (char*)command.p2p_connect_by_name().service_name().c_str(),
454           command.p2p_connect_by_name().miu(),
455           command.p2p_connect_by_name().rw());
456       break;
457     }
458     case Command::kP2PSendUi: {
459       std::vector<uint8_t> buffer(command.p2p_send_ui().data().data(),
460                                   command.p2p_send_ui().data().data() +
461                                       command.p2p_send_ui().data().size());
462       NFA_P2pSendUI(command.p2p_send_ui().handle(),
463                     command.p2p_send_ui().dsap(), buffer.size(), buffer.data());
464       break;
465     }
466     case Command::kP2PDisconnect: {
467       NFA_P2pDisconnect(command.p2p_disconnect().handle(),
468                         command.p2p_disconnect().flush());
469       break;
470     }
471     case Command::kPauseP2P: {
472       NFA_PauseP2p();
473       break;
474     }
475     case Command::kResumeP2P: {
476       NFA_ResumeP2p();
477       break;
478     }
479     case Command::kP2PReadData: {
480       std::vector<uint8_t> buffer((size_t)command.p2p_read_data().length() %
481                                   1024);
482       bool is_more_data = false;
483       unsigned int actual_size = 0;
484       NFA_P2pReadData(command.p2p_read_data().handle(), buffer.size(),
485                       &actual_size, buffer.data(), &is_more_data);
486       break;
487     }
488     case Command::kP2PSendData: {
489       std::vector<uint8_t> buffer(command.p2p_send_data().data().data(),
490                                   command.p2p_send_data().data().data() +
491                                       command.p2p_send_data().data().size());
492       NFA_P2pSendData(command.p2p_send_data().handle(), buffer.size(),
493                       buffer.data());
494       break;
495     }
496     case Command::COMMAND_NOT_SET: {
497       break;
498     }
499   }
500 }
501 
NfcIntegrationFuzzer(const Session * session)502 NfcIntegrationFuzzer::NfcIntegrationFuzzer(const Session* session)
503     : session_(session),
504       fuzzed_data_(
505           reinterpret_cast<const uint8_t*>(session->data_provider().data()),
506           session->data_provider().size()) {
507   g_fuzzed_data = &fuzzed_data_;
508 }
509 
Setup()510 bool NfcIntegrationFuzzer::Setup() {
511   g_tick_count = 0;
512   memset(&g_ee_info, 0, sizeof(g_ee_info));
513   NFA_Init(&fuzzed_hal_entry);
514 
515   rw_cb.p_cback = &fuzz_cback;
516   NFA_Enable(nfa_dm_callback, nfa_conn_callback);
517   DoAllTasks(false);
518 
519   NFA_EeRegister(nfa_ee_callback);
520   NFA_EeSetDefaultProtoRouting(NFC_DH_ID, NFA_PROTOCOL_MASK_ISO_DEP, 0, 0, 0, 0,
521                                0);
522 
523   DoPacket(session_->setup_packet());
524   g_saw_event = false;
525   DoAllTasks(false);
526   if (!g_saw_event) {
527     return false;
528   }
529 
530   NFA_EnableListening();
531   NFA_EnablePolling(NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B |
532                     NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_V |
533                     NFA_TECHNOLOGY_MASK_B_PRIME | NFA_TECHNOLOGY_MASK_A_ACTIVE |
534                     NFA_TECHNOLOGY_MASK_F_ACTIVE | NFA_TECHNOLOGY_MASK_KOVIO);
535 
536   NFA_EnableDtamode(static_cast<tNFA_eDtaModes>(session_->dta_mode()));
537   NFA_StartRfDiscovery();
538 
539   DoAllTasks(false);
540   return true;
541 }
542 
RunCommands()543 void NfcIntegrationFuzzer::RunCommands() {
544   for (const Command& command : session_->commands()) {
545     DoOneCommand(bytes_container_, command);
546   }
547 }
548 
TearDown()549 void NfcIntegrationFuzzer::TearDown() {
550   // Do any remaining tasks including pending timers
551   DoAllTasks(true);
552 
553   // Issue a disable command then clear pending tasks
554   // and timers again
555   NFA_Disable(false);
556   DoAllTasks(true);
557 }
558