def parse_cbit(self, pos): ''' parse cbit in the frame. assuming that cbit_size is not zero. ''' self.cbit = pb.bit_get(self.packet, pos, self.R.cbit_size, ret_type=int) return self.R.cbit_size
def parse_mic(self, pos): ''' parse mic in the frame. assuming that mic_size is not zero. ''' self.mic = pb.bit_get(self.packet, pos, self.R.C.mic_size, ret_type=int) return self.R.C.mic_size
def parse_fcn(self, pos): ''' parse fcn in the frame. assuming that fcn_size is not zero. ''' self.fcn = pb.bit_get(self.packet, pos, self.R.fcn_size, ret_type=int) return self.R.fcn_size
def parse_bitmap(self, pos): ''' parse bitmap in the frame. assuming that bitmap_size is not zero. ''' self.bitmap = pb.bit_get(self.packet, pos, self.R.bitmap_size, ret_type=int) return self.R.bitmap_size
def finalize(self, R): self.R = R pos = self.__pos pos += self.parse_dtag(pos) pos += self.parse_win(pos) pos += self.parse_fcn(pos) if self.fcn == self.R.fcn_all_1: pos += self.parse_mic(pos) payload_bit_len = len(self.packet)*8 - pos self.payload = pb.bit_get(self.packet, pos, payload_bit_len)
def parse_win(self, pos, exp_win=None): ''' parse win in the frame. exp_win: if non-None, check the win whether it is expected. if win_size is zero, self.win is not set. ''' if self.R.win_size: win = pb.bit_get(self.packet, pos, self.R.win_size, ret_type=int) if exp_win != None and win != exp_win: raise ValueError("the value of win unexpected. win=%d expected=%d" % (win, exp_win)) self.win = win return self.R.win_size
def parse_dtag(self, pos, exp_dtag=None): ''' parse dtag in the frame. exp_dtag: if non-None, check the dtag whether it is expected. ''' if self.R.dtag_size: dtag = pb.bit_get(self.packet, pos, self.R.dtag_size, ret_type=int) if exp_dtag != None and dtag != exp_dtag: raise ValueError("dtag unexpected.") else: dtag = self.R.C.default_dtag # self.dtag = dtag return self.R.dtag_size
def parse_rid(self, C, exp_rid=None): ''' parse rid in the frame. exp_rid: if non-None, check the rid whether it's expected. ''' if C.rid_size: rid = pb.bit_get(self.packet, 0, C.rid_size, ret_type=int) if exp_rid != None and rid != exp_rid: raise ValueError("rid unexpected.") else: rid = C.default_rid # self.rid = rid return C.rid_size
def finalize(self, R): self.R = R pos = self.__pos pos += self.parse_dtag(pos) pos += self.parse_win(pos) pos += self.parse_fcn(pos) if self.fcn == self.R.fcn_all_1: pos += self.parse_mic(pos) payload_bit_len = len(self.packet) * 8 - pos if payload_bit_len < 8: # just ignore the padding. return p = pb.bit_get(self.packet, pos, (payload_bit_len & (~7))) self.payload = pb.bit_to(p, payload_bit_len >> 3)
def next_fragment(self, l2_size): ''' l2_size: the size of the L2 payload in bytes. Note that l2_size in this method is converted the unit in bits. XXX Note that it doesn't care the l2_size in retransmitting. if the size is changed in that case, the packet will not be changed as it was. needs to be improved. ''' l2_size = l2_size * 8 # NOTE: converted into the unit of bits. # max_payload_size = l2_size - self.header_size if max_payload_size <= 0: raise AssertionError( "L2 size is smaller than the header. hdr={} L2={}".format( self.header_size, l2_size)) # the max_payload_size must be bigger than or equal to the MIC size. # at least, it's ensure that the payload size is enough to put the MIC. if max_payload_size < self.mic_size: raise AssertionError( "L2 size is smaller than the mic size. mic={} L2={}".format( self.mic_size, l2_size)) # if self.R.mode == SCHC_MODE.NO_ACK and self.state.get( ) == STATE.SEND_ALL1: # no more fragments to be sent return self.state.set(STATE.DONE), None # if self.state.get() == STATE.SEND_ALL0: # it comes here when the timeout happens while waiting for the # ack response from the receiver even though either all-0 was sent. if self.R.mode == SCHC_MODE.ACK_ALWAYS: self.missing = self.missing_prev self.state.set(STATE.RETRY_ALL0) else: # here, for ACK-ON-ERROR self.state.set(STATE.WIN_DONE) pass elif self.state.get() == STATE.SEND_ALL1: # here, the case the sender sent all-1, but no response from the # receiver. self.missing = self.missing_prev self.state.set(STATE.RETRY_ALL1) # if self.state.get() in [STATE.RETRY_ALL0, STATE.RETRY_ALL1]: # if all the missing fragments has been sent, resend the empty ALL. if self.missing == 0: # set the state into the previous one. self.state.back() if self.state.get() == STATE.SEND_ALL0: fgh = sfh.frag_sender_tx(self.R, self.dtag, win=self.win, fcn=self.R.fcn_all_0) elif self.state.get() == STATE.SEND_ALL1: fgh = sfh.frag_sender_tx(self.R, self.dtag, win=self.win, fcn=self.R.fcn_all_1, mic=self.mic) else: AssertionError("invalid state in retransmission %s" % self.state.get()) # return self.state.get(), fgh # if there are any missing fragments, # the sender only needs to send missed fragments. # doesn't need to send all-0/all1. if self.R.mode == SCHC_MODE.NO_ACK: raise AssertionError( "no-ack mode must not come here in next_fragment().") # e.g. N=3, Max FCN = 7 # all-0 # bit: 1 2 3 4 5 6 7 # fcn: 6 5 4 3 2 1 0 # all-1 # bit: 1 2 3 4 5 6 7 # fcn: 6 5 7 p, self.missing = pb.bit_find(self.missing, self.R.bitmap_size) self.logger(1, "retransmitting.", "fgh_list=", self.fgh_list.keys(), "p=", p, "missing=", pb.int_to_bit(self.missing, self.R.bitmap_size)) if p == None or p > self.R.max_fcn: raise AssertionError( "in missing check, p must be from 1 to %d" % self.R.max_fcn) if p == self.R.max_fcn: if self.state.get() == STATE.RETRY_ALL0: fgh = self.fgh_list[self.R.fcn_all_0] else: # i.e. SCHC_FRAG_RETRY_ALL1 fgh = self.fgh_list[self.R.fcn_all_1] else: fgh = self.fgh_list[self.R.max_fcn - p] # in others, return CONT, # however don't need to change the internal state. # i.e RETRY_ALL0 or RETRY_ALL1. return STATE.CONT, fgh # # defragment for transmitting. # if self.R.mode == SCHC_MODE.NO_ACK: margin = max_payload_size - self.rest_payload_size if margin < 0: pyld_size = max_payload_size self.fcn = 0 state = STATE.CONT else: # check whether there is enough size to put the MIC. if margin < self.mic_size: pyld_size = self.rest_payload_size self.fcn = 0 state = STATE.CONT else: # this is the last fragment. # margin is equal to or bigger than mic_size. pyld_size = self.rest_payload_size self.fcn = 1 self.mic = True state = STATE.SEND_ALL1 # payload = pb.bit_get(self.srcbuf, self.pos, pyld_size) if self.mic is None: self.append_tx_list(payload) else: self.append_tx_list(payload, self.mic_size) self.logger(1, "calculating mic") for i in self.tx_payload_list: self.logger(2, "fragment =", i) self.mic = self.R.C.mic_func.get_mic( pb.bit_to("".join(self.tx_payload_list), ljust=True)) # fgh = sfh.frag_sender_tx(self.R, self.dtag, fcn=self.fcn, mic=self.mic, payload=payload) self.state.set(state) self.n_frags_sent += 1 self.pos += pyld_size self.rest_payload_size -= pyld_size if self.rest_payload_size < 0: raise AssertionError("rest_payload_size becomes less than 0") return self.state.get(), fgh # # from here, ACK_ALWAYS or ACK_ON_ERROR # if self.state.get() == STATE.WIN_DONE: # try to support more than 1 bit wide window # though the bit size is 1 in the draft 7. self.win += 1 self.win &= ((2**self.R.win_size) - 1) self.fcn = self.R.max_fcn else: if self.fcn == None: self.fcn = self.R.max_fcn else: self.fcn -= 1 # in above, just set fcn. # then will check below if the packet is the last one. # if so, set fcn into all-1 at that time.. # XXX needs to revisit and improve the logic. margin = max_payload_size - self.rest_payload_size if margin < 0: self.bitmap |= 1 << self.fcn pyld_size = max_payload_size payload = pb.bit_get(self.srcbuf, self.pos, pyld_size) self.append_tx_list(payload) fgh = sfh.frag_sender_tx(self.R, self.dtag, win=self.win, fcn=self.fcn, payload=payload) if self.fcn == self.R.fcn_all_0: self.state.set(STATE.SEND_ALL0) else: self.state.set(STATE.CONT) elif margin < self.mic_size: self.bitmap |= 1 << self.fcn pyld_size = self.rest_payload_size payload = pb.bit_get(self.srcbuf, self.pos, pyld_size) self.append_tx_list(payload) fgh = sfh.frag_sender_tx(self.R, self.dtag, win=self.win, fcn=self.fcn, payload=payload) if self.fcn == self.R.fcn_all_0: self.state.set(STATE.SEND_ALL0) else: self.state.set(STATE.CONT) else: # this is the last window. self.bitmap |= 1 pyld_size = self.rest_payload_size self.fcn = self.R.fcn_all_1 payload = pb.bit_get(self.srcbuf, self.pos, pyld_size) self.append_tx_list(payload, self.mic_size) # self.logger(1, "calculating mic") for i in self.tx_payload_list: self.logger(2, "fragment =", i) self.mic = self.R.C.mic_func.get_mic( pb.bit_to("".join(self.tx_payload_list), ljust=True)) # fgh = sfh.frag_sender_tx(self.R, self.dtag, win=self.win, fcn=self.fcn, mic=self.mic, payload=payload) self.state.set(STATE.SEND_ALL1) # # save the local bitmap for retransmission # this is for the case when the receiver will not respond. self.missing_prev = self.bitmap # store the packet for the future retransmission. self.fgh_list[self.fcn] = fgh self.rest_payload_size -= pyld_size self.pos += pyld_size return self.state.get(), fgh