OT_WEAK ot_u16 otapi_close_request() { /// Set the footer if the session is valid if (session_notempty()) { m2np_footer( /* session_top() */ ); return 1; } return 0; }
OT_WEAK void dll_beacon_applet(m2session* active) { /// Beaconing is a Request-TX operation, and the value for Tc is the amount of /// time to spend in CSMA before quitting the beacon. ot_queue beacon_queue; ot_u8 b_params; ot_u8 cmd_ext; ot_u8 cmd_code; b_params = active->extra; active->extra = 0; /// Start building the beacon packet: /// <LI> Calling m2np_header() will write most of the front of the frame </LI> /// <LI> Add the command byte and optional command-extension byte </LI> m2np_header(active, M2RT_BROADCAST, M2FI_FRDIALOG); cmd_ext = (b_params & 0x06); // Normal extension bits cmd_ext |= (dll.netconf.btemp[2] == 0) << 6; // Announcement No-File bit cmd_code = 0x20 | (b_params & 1) | ((cmd_ext!=0) << 7); q_writebyte(&txq, cmd_code); if (cmd_code) { q_writebyte(&txq, cmd_ext); } /// Setup the comm parameters, if the channel is available: /// <LI> dll.comm values tx_eirp, cs_rssi, and cca_rssi must be set by the /// radio module during the CSMA-CA process -- don't set them here. /// The DASH7 spec requires it to happen in this order. </LI> /// <LI> Set CSMA-CA parameters, which are used by the radio module </LI> /// <LI> Set number of redundant TX's we would like to transmit </LI> /// <LI> Set rx_timeout for Default-Tg or 0, if beacon has no response </LI> dll_set_defaults(active); dll.comm.tc = TI2CLK(M2_PARAM_BEACON_TCA); dll.comm.rx_timeout = (b_params & 0x02) ? \ 0 : rm2_default_tgd(active->channel); dll.comm.csmaca_params |= (b_params & 0x04) | M2_CSMACA_NA2P | M2_CSMACA_MACCA; dll.comm.redundants = dll.netconf.b_attempts; q_writebyte(&txq, (ot_u8)dll.comm.rx_timeout); /// Add the announcement file data if the specified return data != 0 bytes. /// If the beacon data is missing or otherwise not accessible by the GUEST /// user, dump the session (thus killing the beacon) and go back to idle. if (dll.netconf.btemp[2] != 0) { q_init(&beacon_queue, &dll.netconf.btemp[2], 4); if (m2qp_isf_call((b_params & 1), &beacon_queue, AUTH_GUEST) < 0) { session_pop(); dll_idle(); return; } } /// Final step to any packet generation: add footer m2np_footer(); }
void m2dp_footer() { /// M2DP is similar enough to M2NP that the same footer function may be used. m2np_footer(); }
ot_int network_route_ff(m2session* session) { ot_int route_val; /// Strip CRC (-2 bytes) rxq.front[0] -= 2; /// Acquire Flags and Protocol from the Frame Info Field rxq.getcursor = &rxq.front[3]; session->protocol = (*rxq.getcursor & M2FI_FRTYPEMASK); session->flags = *rxq.getcursor & 0xC0; m2np.header.fr_info = *rxq.getcursor++; /// Treat Non-Mode-2 Protocols /// @note Non-Mode-2 protocols not supported at this time if (m2np.header.fr_info & M2FI_NM2) { return -1; } /// Data Link Layer Security if (m2np.header.fr_info & M2FI_DLLS) { # if (OT_FEATURE(DLL_SECURITY)) ///@todo experimental AES_load_static_key(ISF_ID(user_authentication_key), (ot_u32*)txq.front); AES_keyschedule_dec((ot_u32*)txq.front, (ot_u32*)(txq.front+16)); AES_decrypt(rxq.getcursor, rxq.getcursor, (ot_u32*)(txq.front+16)); # else return -1; # endif } /// Address Control Header (Present in M2NP) /// Session Connection and Dialog Filtering: /// - if unassociated, connect now /// - if already connected, make sure the dialog IDs are equal if (m2np.header.fr_info & M2FI_ENADDR) { if (session->netstate & M2_NETSTATE_CONNECTED) { if (session->dialog_id != q_readbyte(&rxq)) { return -1; } } else { session->netstate |= M2_NETSTATE_CONNECTED; session->subnet = rxq.front[2]; session->dialog_id = q_readbyte(&rxq); } /// Grab global flags from Address Control m2np.header.addr_ctl = q_readbyte(&rxq); session->flags |= m2np.header.addr_ctl & 0x3F; /// Grab Source Address from this packet (dialog address), which is /// converted to the target address in the response. m2np.rt.dlog.length = (m2np.header.addr_ctl & M2_FLAG_VID) ? 2 : 8; m2np.rt.dlog.value = q_markbyte(&rxq, m2np.rt.dlog.length); /// Network Layer Security /// @note Network Layer Security not supported at this time if (m2np.header.addr_ctl & M2_FLAG_NLS) { # if (OT_FEATURE(NL_SECURITY)) # else return -1; # endif } /// If unicasting, the next data is the target address, which will have /// the same length as the source address, and it needs to match this /// device's device ID (VID or UID) if ((m2np.header.addr_ctl & 0xC0) == 0) { session->netstate |= M2_NETFLAG_FIRSTRX; if ( !m2np_idcmp(m2np.rt.dlog.length, q_markbyte(&rxq, m2np.rt.dlog.length)) ) { return -1; } } } /// Vector to the appropriate Network Layer Protocol Parser /// Most network protocols don't do anything except broadcast. M2NP is the /// exception, and it manages various types of routing at the network layer. route_val = -1; switch (session->protocol & M2FI_FRTYPEMASK) { case M2FI_FRDIALOG: case M2FI_FRNACK: { // Reset routing template m2np.rt.hop_code = 0; m2np.rt.hop_ext = 0; m2np.rt.orig.value = NULL; m2np.rt.dest.value = NULL; /// Unicast and Anycast Requests have a routing template /// (Not currently supported, so just move the cursor ahead) if ((m2np.header.addr_ctl & 0x40) == 0) { m2np.rt.hop_code = q_readbyte(&rxq); m2np.rt.orig.length = ((m2np.rt.hop_code & M2HC_VID) != 0) ? 2 : 8; m2np.rt.dest.length = m2np.rt.orig.length; if ((m2np.rt.hop_code & M2HC_EXT) != 0) { m2np.rt.hop_ext = q_readbyte(&rxq); } if ((m2np.rt.hop_code & M2HC_ORIG) != 0) { m2np.rt.orig.value = q_markbyte(&rxq, m2np.rt.orig.length); } if ((m2np.rt.hop_code & M2HC_DEST) != 0) { m2np.rt.dest.value = q_markbyte(&rxq, m2np.rt.dest.length); } } } // Note case fall-through case M2FI_STREAM: { /// M2DP gets parsed just like M2NP, but it uses the Network data /// stored from the last M2NP frame route_val = m2qp_parse_frame(session); break; } case M2FI_RFU: break; } /// Attach footer to response, if necessary if (route_val >= 0) { m2np_footer(session); } # if (OT_FEATURE(M2NP_CALLBACKS) == ENABLED) && \ !defined(EXTF_network_sig_route) m2np.signal.route(route_val, session->protocol); # elif defined(EXTF_network_sig_route) network_sig_route(route_val, session->protocol); # endif return route_val; }