Exemplo n.º 1
0
 def dump(self):
     x = ""
     if self.rid != None:
         x += ("rid:%s" % pb.int_to_bit(self.rid, self.R.C.rid_size))
     if self.dtag != None:
         if len(x) != 0: x += " "
         x += ("dtag:%s" % pb.int_to_bit(self.dtag, self.R.dtag_size))
     if self.win != None:
         if len(x) != 0: x += " "
         x += ("w:%d" % self.win)
     if self.fcn != None:
         if len(x) != 0: x += " "
         x += ("fcn:%s" % pb.int_to_bit(self.fcn, self.R.fcn_size))
     if self.mic != None:
         if len(x) != 0: x += " "
         x += ("mic:%s" % pb.int_to_bit(self.mic, self.R.C.mic_size))
         x += ("(0x%s)" % "".join(["%02x"%((self.mic>>i)&0xff)
                                  for i in [24,16,8,0]]))
     if self.cbit != None:
         if len(x) != 0: x += " "
         x += ("cbit:%d" % self.cbit)
     if self.bitmap != None:
         if len(x) != 0: x += " "
         x += ("bitmap:%s" % pb.int_to_bit(self.bitmap, self.R.bitmap_size))
     if self.payload != None:
         if len(x) != 0: x += " "
         x += ("payload:%s" % self.payload)
     #
     return x
Exemplo n.º 2
0
 def parse_ack(self, recvbuf, peer):
     if self.R.mode == SCHC_MODE.NO_ACK:
         raise AssertionError(
             "parse_ack() must not be called in NO-ACK mode.")
     #
     # XXX here, must check the peer expected.
     #
     if self.state.get() == STATE.SEND_ALL0:
         fgh = sfh.frag_sender_rx_all0_ack(recvbuf, self.R, self.dtag,
                                           self.win)
     elif self.state.get() == STATE.SEND_ALL1:
         fgh = sfh.frag_sender_rx_all1_ack(recvbuf, self.R, self.dtag,
                                           self.win)
     else:
         raise TypeError(
             "state must be either sent_all0 or sent_all1 when parse_ack() is called. but, state=%d"
             % self.state.get())
     if fgh.cbit == 1:
         self.logger(1, "cbit is on.")
         self.missing = 0
     else:
         # get the missing fragments.
         if fgh.bitmap == None:
             raise ValueError("no bitmap found")
         # set new bitmap for retransmission.
         self.missing = self.bitmap & ~fgh.bitmap
         # save the local bitmap for retransmission
         self.missing_prev = self.missing
         self.logger(1, "bitmap tx:",
                     pb.int_to_bit(self.bitmap, self.R.bitmap_size))
         self.logger(1, "bitmap rx:",
                     pb.int_to_bit(fgh.bitmap, self.R.bitmap_size))
         self.logger(1, "missing  :",
                     pb.int_to_bit(self.missing, self.R.bitmap_size))
     #
     if self.missing:
         if self.state.get() == STATE.SEND_ALL0:
             return self.state.set(STATE.RETRY_ALL0), fgh
         elif self.state.get() == STATE.SEND_ALL1:
             return self.state.set(STATE.RETRY_ALL1), fgh
     else:
         #
         # The receiver looks to have all fragments that the sender sent.
         # win_head can be moved to the next.
         # missing is initialized.
         self.win_head = self.pos
         self.__init_window()
         #
         # if this is the last window, then set it into DONE state.
         # Note that in ACK-ON-ERROR, it will be set it into DONE later.
         if self.state.get() == STATE.SEND_ALL0:
             return self.state.set(STATE.WIN_DONE), fgh
         elif self.state.get() == STATE.SEND_ALL1:
             return self.state.set(STATE.DONE), fgh
Exemplo n.º 3
0
 def all_fragments_received(self):
     self.logger(1, "checking all-0 fragments, local bitmap=",
                 pb.int_to_bit(self.bitmap, self.R.bitmap_size))
     if self.bitmap == self.R.bitmap_all_1:
         self.logger(1, "received all fragments.")
         return True
     else:
         self.logger(1, "not received all fragments.")
         return False
Exemplo n.º 4
0
 def make_frag(self, dtag, win=None, fcn=None, mic=None, bitmap=None,
               cbit=None, abort=False, payload=None):
     '''
     payload: bit string of the SCHC fragment payload.
     '''
     #
     ba = bytearray()
     pos = 0
     #
     # basic fields.
     if self.R.rid != None and self.R.C.rid_size:
         pb.bit_set(ba, 0, pb.int_to_bit(self.R.rid, self.R.C.rid_size),
                    extend=True)
         pos += self.R.C.rid_size
     if dtag != None and self.R.dtag_size:
         pb.bit_set(ba, pos, pb.int_to_bit(dtag, self.R.dtag_size),
                    extend=True)
         pos += self.R.dtag_size
     #
     # extension fields.
     if win != None and self.R.win_size:
         pb.bit_set(ba, pos, pb.int_to_bit(win, self.R.win_size),
                    extend=True)
         pos += self.R.win_size
     if fcn != None and self.R.fcn_size:
         pb.bit_set(ba, pos, pb.int_to_bit(fcn, self.R.fcn_size),
                    extend=True)
         pos += self.R.fcn_size
     if mic != None and self.R.C.mic_size:
         pb.bit_set(ba, pos, pb.int_to_bit(mic, self.R.C.mic_size),
                    extend=True)
         pos += self.R.C.mic_size
     if cbit != None and self.R.cbit_size:
         pb.bit_set(ba, pos, pb.int_to_bit(cbit, self.R.cbit_size),
                    extend=True)
         pos += self.R.cbit_size
     if bitmap != None and self.R.bitmap_size:
         pb.bit_set(ba, pos, pb.int_to_bit(bitmap, self.R.bitmap_size),
                    extend=True)
         pos += self.R.bitmap_size
     if abort == True:
         pb.bit_set(ba, pos, pb.int_to_bit(0xff, 8),
                    extend=True)
         pos += 8
     #
     if payload != None:
         # assumed that bit_set() has extended to a byte boundary.
         pb.bit_set(ba, pos, payload, extend=True)
     #
     # the abort field is implicit, is not needed to set into the parameter.
     self.set_param(self.R.rid, dtag, win, fcn, mic, bitmap, cbit, payload)
     self.packet = ba
Exemplo n.º 5
0
 def __add_win_mode(self, fgh):
     '''
     except NO_ACK mode
     '''
     f = self.fragment_list.setdefault(fgh.fcn, {})
     # empty ALL0 or ALL1 only be acceptable with duplicate FCN.
     if len(f):
         if (fgh.payload == None and
             (self.win_state.get() == STATE.CONT_ALL0 and
              fgh.fcn == self.R.fcn_all_0)):
             return self.win_state.set(STATE.CHECK_ALL0)
         elif (fgh.payload == None and
               (self.win_state.get() == STATE.CONT_ALL1 and
              fgh.fcn == self.R.fcn_all_1)):
             return self.win_state.set(STATE.CHECK_ALL1)
         else:
             self.logger(1, "ERROR: got a FCN which was received before.",
                         self.win_state.get(), self.win, fgh.fcn)
             return STATE.FAIL
     # add new fragment for the assembling
     self.fragment_list[fgh.fcn] = fgh.payload
     #
     if fgh.fcn == self.R.fcn_all_1:
         self.bitmap |= 1
     else:
         self.bitmap |= 1<<fgh.fcn
     self.logger(1, "bitmap=", pb.int_to_bit(self.bitmap,
                                             self.R.bitmap_size))
     #
     # assuming that, in each window except the last one,
     # the bitmap must be filled up by the fragments that sender sends.
     if self.win_state.get() in [STATE.INIT, STATE.CONT]:
         if fgh.fcn == self.R.fcn_all_0:
             # immediately after receiving the all-0
             return self.win_state.set(STATE.CHECK_ALL0)
         elif fgh.fcn == self.R.fcn_all_1:
             # immediately after receiving the all-1
             return self.win_state.set(STATE.CHECK_ALL1)
         elif self.win_state.get() == STATE.INIT:
             # fnc is neigher all-0 nor all-1, if it's first fragment.
             return self.win_state.set(STATE.CONT)
         else:
             # otherwise,
             return STATE.CONT
     elif self.win_state.get() in [STATE.ALL0_NG, STATE.CONT_ALL0]:
         # same as the CONT_ALL1 state.
         if fgh.fcn == self.R.fcn_all_0:
             return self.win_state.set(STATE.CHECK_ALL0)
         elif self.win_state.get() == STATE.ALL0_NG:
             return self.win_state.set(STATE.CONT_ALL0)
         else:
             return STATE.CONT_ALL0
     elif self.win_state.get() == STATE.ALL0_OK:
         # same as the CONT_ALL1 state.
         if fgh.fcn == self.R.fcn_all_0:
             return self.win_state.get()
     elif self.win_state.get() in [STATE.ALL1_NG, STATE.CONT_ALL1]:
         # It doesn't need to check the payload size (i.e. ALL-1 empty).
         # If ALL-1 message is received at CONT_ALL1 state,
         # it just changes the state into CHECK_ALL1 anyway
         # doesn't change the state before it gets any ALL-1 message.
         if fgh.fcn == self.R.fcn_all_1:
             return self.win_state.set(STATE.CHECK_ALL1)
         elif self.win_state.get() == STATE.ALL1_NG:
             return self.win_state.set(STATE.CONT_ALL1)
         else:
             return STATE.CONT_ALL1
     elif self.win_state.get() == STATE.SEND_ACK1:
         # same as the CONT_ALL1 state.
         if fgh.fcn == self.R.fcn_all_1:
             return self.win_state.get()
     else:
         # in other case.
         raise ValueError("invalid state=%s" % self.win_state.pprint())
Exemplo n.º 6
0
    def next_fragment(self, l2_size):
        '''
        l2_size: the caller can specify the size of the payload anytime.

        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.
        '''
        # compute the max/min payload size.
        max_pyld_size, min_pyld_size = self.get_payload_base_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.
        #
        rest_size = len(self.srcbuf) - self.pos
        if self.R.mode == SCHC_MODE.NO_ACK:
            if rest_size > min_pyld_size:
                if rest_size >= max_pyld_size:
                    pyld_size = max_pyld_size
                else:
                    pyld_size = rest_size
                self.fcn = 0
                mic = None
                state = STATE.CONT
            else:
                # this is the last fragment.
                pyld_size = rest_size
                self.fcn = 1
                mic = self.mic
                state = STATE.SEND_ALL1
            #
            fgh = sfh.frag_sender_tx(self.R,
                                     self.dtag,
                                     fcn=self.fcn,
                                     mic=mic,
                                     payload=self.srcbuf[self.pos:self.pos +
                                                         pyld_size])
            self.state.set(state)
            self.n_frags_sent += 1
            self.pos += pyld_size
            return self.state.get(), fgh
        else:
            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..
            if rest_size > min_pyld_size:
                self.bitmap |= 1 << self.fcn
                if rest_size >= max_pyld_size:
                    pyld_size = max_pyld_size
                else:
                    pyld_size = rest_size
                fgh = sfh.frag_sender_tx(
                    self.R,
                    self.dtag,
                    win=self.win,
                    fcn=self.fcn,
                    payload=self.srcbuf[self.pos:self.pos + pyld_size])
                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 = rest_size
                self.fcn = self.R.fcn_all_1
                fgh = sfh.frag_sender_tx(
                    self.R,
                    self.dtag,
                    win=self.win,
                    fcn=self.fcn,
                    mic=self.mic,
                    payload=self.srcbuf[self.pos:self.pos + pyld_size])
                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.pos += pyld_size
            return self.state.get(), fgh
Exemplo n.º 7
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