예제 #1
0
 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
예제 #2
0
 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
예제 #3
0
 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
예제 #4
0
 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
예제 #5
0
 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)
예제 #6
0
 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
예제 #7
0
 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
예제 #8
0
 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
예제 #9
0
 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)
예제 #10
0
    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