| @@ -10,6 +10,12 @@ initiator does not receive a response to it's query, it will resend the | |||||
| request until it does. It is required that the responder be able to | request until it does. It is required that the responder be able to | ||||
| detect this, and resend the last response. | detect this, and resend the last response. | ||||
| The respondent will cache message responses after the session has been | |||||
| confirmed, but before that, it is unneccessary, as there is no harm to | |||||
| reprocess the messages. The more complicated part is dealing w/ a | |||||
| missed confirmed reply, as the state will need to be back tracked (saved) | |||||
| to decode the repeated confirm request. | |||||
| both sides: | both sides: | ||||
| meta-AD('com.funkthat.lora.irrigation.<type>.v0.0.1') | meta-AD('com.funkthat.lora.irrigation.<type>.v0.0.1') | ||||
| key(<defined by type>) | key(<defined by type>) | ||||
| @@ -5,6 +5,19 @@ static const size_t MAC_LEN = 8; | |||||
| static const size_t CHALLENGE_LEN = 16; | static const size_t CHALLENGE_LEN = 16; | ||||
| static const uint8_t domain[] = "com.funkthat.lora.irrigation.shared.v0.0.1"; | static const uint8_t domain[] = "com.funkthat.lora.irrigation.shared.v0.0.1"; | ||||
| static int comms_pktbuf_equal(struct pktbuf a, struct pktbuf b); | |||||
| /* returns 1 if equal, 0 if not equal */ | |||||
| static int | |||||
| comms_pktbuf_equal(struct pktbuf a, struct pktbuf b) | |||||
| { | |||||
| if (a.pktlen != b.pktlen) | |||||
| return 0; | |||||
| return memcmp(a.pkt, b.pkt, a.pktlen) == 0; | |||||
| } | |||||
| size_t | size_t | ||||
| _strobe_state_size() | _strobe_state_size() | ||||
| { | { | ||||
| @@ -48,6 +61,14 @@ comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout) | |||||
| struct pktbuf pbmsg, pbrep; | struct pktbuf pbmsg, pbrep; | ||||
| ssize_t cnt, ret, msglen; | ssize_t cnt, ret, msglen; | ||||
| /* if the current msg matches the previous */ | |||||
| if (comms_pktbuf_equal(pbin, cs->cs_prevmsg)) { | |||||
| /* send the previous response */ | |||||
| pbout->pktlen = cs->cs_prevmsgresp.pktlen; | |||||
| memcpy(pbout->pkt, cs->cs_prevmsgresp.pkt, pbout->pktlen); | |||||
| return; | |||||
| } | |||||
| strobe_attach_buffer(&cs->cs_state, pbin.pkt, pbin.pktlen); | strobe_attach_buffer(&cs->cs_state, pbin.pkt, pbin.pktlen); | ||||
| cnt = strobe_get(&cs->cs_state, APP_CIPHERTEXT, buf, pbin.pktlen - | cnt = strobe_get(&cs->cs_state, APP_CIPHERTEXT, buf, pbin.pktlen - | ||||
| @@ -108,8 +129,23 @@ comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout) | |||||
| ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN); | ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN); | ||||
| break; | break; | ||||
| } | |||||
| } | |||||
| } | } | ||||
| /* set the output buffer length */ | |||||
| pbout->pktlen = ret; | pbout->pktlen = ret; | ||||
| if (ret != 0) { | |||||
| /* we accepted a new message store it */ | |||||
| /* store the req */ | |||||
| cs->cs_prevmsg.pkt = cs->cs_prevmsgbuf; | |||||
| cs->cs_prevmsg.pktlen = pbin.pktlen; | |||||
| memcpy(cs->cs_prevmsg.pkt, pbin.pkt, pbin.pktlen); | |||||
| /* store the response */ | |||||
| cs->cs_prevmsgresp.pkt = cs->cs_prevmsgrespbuf; | |||||
| cs->cs_prevmsgresp.pktlen = pbout->pktlen; | |||||
| memcpy(cs->cs_prevmsgresp.pkt, pbout->pkt, pbout->pktlen); | |||||
| } | |||||
| } | } | ||||
| @@ -3,6 +3,8 @@ | |||||
| #include <strobe.h> | #include <strobe.h> | ||||
| #define COMMS_MAXMSG 64 | |||||
| struct pktbuf { | struct pktbuf { | ||||
| uint8_t *pkt; | uint8_t *pkt; | ||||
| uint16_t pktlen; | uint16_t pktlen; | ||||
| @@ -23,6 +25,12 @@ struct comms_state { | |||||
| strobe_s cs_start; /* special starting state cache */ | strobe_s cs_start; /* special starting state cache */ | ||||
| process_msgfunc_t cs_procmsg; | process_msgfunc_t cs_procmsg; | ||||
| struct pktbuf cs_prevmsg; | |||||
| struct pktbuf cs_prevmsgresp; | |||||
| uint8_t cs_prevmsgbuf[COMMS_MAXMSG]; | |||||
| uint8_t cs_prevmsgrespbuf[COMMS_MAXMSG]; | |||||
| }; | }; | ||||
| size_t _strobe_state_size(); | size_t _strobe_state_size(); | ||||
| @@ -311,6 +311,19 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): | |||||
| _self.assertEqual(expectlen, | _self.assertEqual(expectlen, | ||||
| outbuf.pktlen) | outbuf.pktlen) | ||||
| # save what was originally replied | |||||
| origmsg = outbuf._from() | |||||
| # pretend that the reply didn't make it | |||||
| r = make_pktbuf(gb) | |||||
| outbuf = make_pktbuf(outbytes) | |||||
| lora_comms.comms_process(commstate, r, | |||||
| outbuf) | |||||
| # make sure that the reply matches previous | |||||
| _self.assertEqual(origmsg, outbuf._from()) | |||||
| # pass the reply back | # pass the reply back | ||||
| await self.put(outbytes[:outbuf.pktlen]) | await self.put(outbytes[:outbuf.pktlen]) | ||||
| @@ -1,5 +1,5 @@ | |||||
| from ctypes import Structure, POINTER, CFUNCTYPE, pointer | from ctypes import Structure, POINTER, CFUNCTYPE, pointer | ||||
| from ctypes import c_uint8, c_uint16, c_ssize_t, c_size_t, c_uint64 | |||||
| from ctypes import c_uint8, c_uint16, c_ssize_t, c_size_t, c_uint64, c_int | |||||
| from ctypes import CDLL | from ctypes import CDLL | ||||
| class PktBuf(Structure): | class PktBuf(Structure): | ||||
| @@ -21,7 +21,6 @@ def make_pktbuf(s): | |||||
| if isinstance(s, bytearray): | if isinstance(s, bytearray): | ||||
| obj = s | obj = s | ||||
| pb.pkt = pointer(c_uint8.from_buffer(s)) | pb.pkt = pointer(c_uint8.from_buffer(s)) | ||||
| #print('mp:', repr(pb.pkt)) | |||||
| else: | else: | ||||
| obj = (c_uint8 * len(s))(*s) | obj = (c_uint8 * len(s))(*s) | ||||
| pb.pkt = obj | pb.pkt = obj | ||||
| @@ -44,8 +43,15 @@ class CommsState(Structure): | |||||
| _fields_ = [ | _fields_ = [ | ||||
| # The alignment of these may be off | # The alignment of these may be off | ||||
| ('cs_state', c_uint64 * _strobe_state_u64_cnt), | ('cs_state', c_uint64 * _strobe_state_u64_cnt), | ||||
| ('cs_comm_state', c_int), | |||||
| ('cs_start', c_uint64 * _strobe_state_u64_cnt), | ('cs_start', c_uint64 * _strobe_state_u64_cnt), | ||||
| ('cs_procmsg', process_msgfunc_t), | ('cs_procmsg', process_msgfunc_t), | ||||
| ('cs_prevmsg', PktBuf), | |||||
| ('cs_prevmsgresp', PktBuf), | |||||
| ('cs_prevmsgbuf', c_uint8 * 64), | |||||
| ('cs_prevmsgrespbuf', c_uint8 * 64), | |||||
| ] | ] | ||||
| for func, ret, args in [ | for func, ret, args in [ | ||||