Exemple #1
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        u = pcs.Field("u", 1)
        type = pcs.Field("exp", 15)
        length = pcs.Field("length", 16)
        id = pcs.Field("id", 32)
        mparams = pcs.OptionListField("")
        oparams = pcs.OptionListField("")

        pcs.Packet.__init__(self, [ u, type, length, id, mparams, oparams ], \
                            bytes = bytes, **kv)
        self.description = "RFC 3036 LDP message header "

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            self.data = payload.payload(bytes[curr:remaining], \
                                        timestamp = timestamp)
        else:
            self.data = None
Exemple #2
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        """initialize a header very similar to that of IGMPv1/v2"""
        reserved00 = pcs.Field("reserved00", 8)
        capabilities = pcs.Field("capabilities", 8)
        minor = pcs.Field("minor", 8)
        major = pcs.Field("major", 8)
        options = pcs.OptionListField("options")
        pcs.Packet.__init__(self,
                            [reserved00, capabilities, minor, major, options],
                            bytes, **kv)

        self.description = "initialize a header very similar to that of IGMPv1/v2"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

# XXX optional bytes not processed yet.

        if bytes is not None:
            offset = self.sizeof()
            self.data = payload.payload(bytes[offset:len(bytes)])
        else:
            self.data = None
Exemple #3
0
    def __init__(self, name, **kv):
        self.packet = None
        self.name = name

        self.len = pcs.Field("len", 16)
        self.flags = pcs.Field("flags", 8)
        self.hops = pcs.Field("hops", 8)
        self.ifindex = pcs.Field("ifindex", 32)
        self.tlvs = pcs.OptionListField("tlvs")

        # XXX I actually have variable width when I am being encoded,
        # OptionList deals with this.
        self.width = self.len.width + self.flags.width + \
                     self.hops.width + self.ifindex.width + \
                     self.tlvs.width

        # If keyword initializers are present, deal with the syntactic sugar.
        # TODO: Figure out how to initialize the TLVs inside our TLV...
        if kv is not None:
            for kw in kv.iteritems():
                if kw[0] in self.__dict__:
                    if kw[0] == 'tlvs':
                        if not isinstance(kw[1], list):
                            if __debug__:
                                print "argument is not a list"
                            continue
                        #for src in kw[1]:
                        #    if not isinstance(src, int):
                        #        if __debug__:
                        #            print "source is not an IPv4 address"
                        #        continue
                        #    self.sources.append(pcs.Field("", 32, default=src))
                    else:
                        self.__dict__[kw[0]].value = kw[1]
Exemple #4
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        ntpts = pcs.Field("ntpts", 64)
        rtpts = pcs.Field("rtpts", 32)
        spkts = pcs.Field("spkts", 32)
        sbytes = pcs.Field("sbytes", 32)
        opt = pcs.OptionListField("opt")

        pcs.Packet.__init__(self, [ntpts, rtpts, spkts, sbytes, opt],
                            bytes=bytes,
                            **kv)
        self.description = "RFC 3550 Real Time Control Protocol sender message portion"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            # XXX TODO decapsulate all the report counts.
            # to do this, we need to see the parent RC.
            self.data = payload.payload(bytes[curr:remaining], \
                                        timestamp = timestamp)
        else:
            self.data = None
Exemple #5
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        """initialize an IGMPv3 query"""
        group = pcs.Field("group", 32)
        reserved00 = pcs.Field("reserved00", 4)
        sbit = pcs.Field("sbit", 1)
        qrv = pcs.Field("qrv", 3)
        qqic = pcs.Field("qqic", 8)
        nsrc = pcs.Field("nsrc", 16)
        srcs = pcs.OptionListField("sources")

        # If keyword initializers are present, deal with the syntactic sugar.
        # query's constructor accepts a list of IP addresses. These need
        # to be turned into Fields for encoding to work, as they are going
        # to be stashed into the "sources" OptionListField defined above.
        if kv is not None:
            for kw in kv.iteritems():
                if kw[0] == 'sources':
                    assert isinstance(kw[1], list)
                    for src in kw[1]:
                        assert isinstance(src, int)
                        srcs.append(pcs.Field("", 32, default=src))
            kv.pop('sources')

        pcs.Packet.__init__(self,
                            [group, reserved00, sbit, qrv, qqic, nsrc, srcs],
                            bytes=bytes,
                            **kv)

        self.description = "initialize an IGMPv3 query"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        # Decode source list if provided.
        if bytes is not None:
            sources_len = self.nsrc * 4
            query_len = self.sizeof() + sources_len

            if query_len > len(bytes):
                raise UnpackError, \
                      "IGMPv3 query is larger than input (%d > %d)" % \
                      (query_len, len(bytes))

            rem = sources_len
            curr = self.sizeof()
            while rem >= 4:
                src = struct.unpack('I', bytes[curr:curr + 4])[0]
                sources.append(pcs.Field("", 32, default=src))
                curr += 4
                rem -= 4
            if rem > 0:
                print "WARNING: %d trailing bytes in query." % rem

        # IGMPv3 queries SHOULD NOT contain ancillary data. If we
        # do find any, we'll append it to the data member.
            self.data = payload.payload(bytes[query_len:len(bytes)])
        else:
            self.data = None
Exemple #6
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        """initialize an IGMPv3 report header"""
        reserved00 = pcs.Field("reserved00", 16)
        nrecords = pcs.Field("nrecords", 16)
        records = pcs.OptionListField("records")

        pcs.Packet.__init__(self, [reserved00, nrecords, records], bytes, **kv)
        self.description = "initialize an IGMPv3 report header"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        # Decode additional bytes into group records, if provided.
        # Group records are variable length structures.
        # Some IGMPv3 implementations re-use the same buffers which
        # may contain junk, so don't try to parse the entire packet
        # as a set of group record fields.
        if bytes is not None:
            curr = self.sizeof()
            byteBR = 8
            found = 0
            expected = self._fieldnames['nrecords'].value
            while len(self.records) < expected and curr < len(bytes):
                rec = GroupRecordField("")
                oldcurr = curr
                [dummy, curr, byteBR] = rec.decode(bytes, curr, byteBR)
                self.records.append(rec)
            #print len(self.records), "records parsed"
            self.data = payload.payload(bytes[curr:len(bytes)])
        else:
            self.data = None
Exemple #7
0
    def __init__(self, name, **kv):
        self.packet = None
        self.name = name

        self.type = pcs.Field("type", 8)
        self.auxdatalen = pcs.Field("auxdatalen", 8)
        self.nsources = pcs.Field("nsources", 16)
        self.group = pcs.Field("group", 32)
        self.sources = pcs.OptionListField("sources")
        self.auxdata = pcs.OptionListField("auxdata")

        # XXX I actually have variable width when I am being encoded,
        # OptionList deals with this.
        self.width = self.type.width + self.auxdatalen.width + \
       self.nsources.width + self.group.width + \
       self.sources.width + self.auxdata.width

        # If keyword initializers are present, deal with the syntactic sugar.
        if kv is not None:
            for kw in kv.iteritems():
                if kw[0] in self.__dict__:
                    if kw[0] == 'auxdata':
                        if not isinstance(kw[1], str):
                            if __debug__:
                                print "argument is not a string"
                            continue
                        self.auxdata.append([pcs.StringField("",             \
                                                             len(kv[1]) * 8, \
                                                             default=kv[1])])
                    elif kw[0] == 'sources':
                        if not isinstance(kw[1], list):
                            if __debug__:
                                print "argument is not a list"
                            continue
                        for src in kw[1]:
                            if not isinstance(src, int):
                                if __debug__:
                                    print "source is not an IPv4 address"
                                continue
                            self.sources.append(pcs.Field("", 32, default=src))
                    else:
                        self.__dict__[kw[0]].value = kw[1]
Exemple #8
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        v = pcs.Field("v", 2)  # version
        p = pcs.Field("p", 1)  # padded
        x = pcs.Field("x", 1)  # extended
        cc = pcs.Field("cc", 4)  # csrc count
        m = pcs.Field("m", 1)  # m-bit
        pt = pcs.Field("pt", 7, discriminator=True)  # payload type
        seq = pcs.Field("seq", 16)  # sequence
        ts = pcs.Field("ts", 32)  # timestamp
        ssrc = pcs.Field("ssrc", 32)  # source
        opt = pcs.OptionListField("opt")  # optional fields

        pcs.Packet.__init__(self, [v, p, x, cc, m, pt, seq, ts, ssrc, opt], \
                            bytes = bytes, **kv)
        self.description = "RFC 3550 Real Time Protocol"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            # Parse CSRC.
            nc = self.cc
            while nc > 0 and remaining >= 4:
                value = struct.unpack("!I", bytes[curr:curr + 4])
                csrc = pcs.Field("csrc", 32, default=value)
                self.opt._options.append(csrc)
                curr += 4
                remaining -= 4
            # Parse Header Extension.
            if self.x == 1 and remaining >= 4:
                extlen = struct.unpack("!H", bytes[curr + 2:curr + 4])
                extlen <<= 2
                extlen = min(extlen, remaining)
                # Copy the entire chunk so we keep the type field.
                ext = pcs.StringField("ext", extlen * 8, \
                                      default=bytes[curr:extlen+4])
                self.opt._options.append(ext)
                curr += extlen
                remaining -= extlen
            # Heed padding byte.
            npad = 0
            if self.p == 1:
                npad = bytes[-1]
            self.data = payload.payload(bytes[curr:remaining-npad], \
                                        timestamp = timestamp)
        else:
            self.data = None
Exemple #9
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        """initialize an ethernet packet"""
        version = pcs.Field("version", 8)  # currently 0.
        pad = pcs.Field("pad", 8)
        len = pcs.Field("len", 16)  # inclusive.
        present = pcs.Field("present", 32)  # Bit mask.
        tlvs = pcs.OptionListField("tlvs")

        pcs.Packet.__init__(self, [version, pad, len, present, tlvs], \
                            bytes = bytes, **kv)
        self.description = "initialize an ethernet packet"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = min(len(bytes), self.len) - offset
            # Force little-endian conversion.
            # TODO: Process the EXT bit.
            he_prez = struct.unpack('<i', bytes[4:4])
            for i in xrange(IEEE80211_RADIOTAP_TSFT, \
                            IEEE80211_RADIOTAP_XCHANNEL+1):
                if (he_prez & (1 << i)) != 0:
                    if i in _vmap:
                        vt = _vmap[i]
                        vname = vt[0]
                        vbytes = vt[1] >> 3
                        vfmt = vt[2]
                        vfunc = vt[3]
                        if remaining >= vbytes:
                            value = struct.unpack(vfmt, bytes[curr:vlen])
                            fields = vfunc(vname, value)
                            for f in fields:
                                tlvs._options.append(f)
                            curr += vlen
                            remaining -= vlen
                        else:
                            break
            # XXX TODO: always decode next header as a full 802.11 header.
            self.data = payload.payload(bytes[curr:remaining], \
                                        timestamp = timestamp)
        else:
            self.data = None
Exemple #10
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        dsap = pcs.Field("dsap", 8)
        ssap = pcs.Field("ssap", 8)
        control = pcs.Field("control", 8)  # snd_x2 in an I-frame.
        opt = pcs.OptionListField("opt")

        pcs.Packet.__init__(self, [dsap, ssap, opt], bytes=bytes, **kv)
        self.description = "IEEE 802.2 LLC"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            # TODO: Decode other fields.
            # For now, just do the minimum to parse 802.11 and 802.1d frames.
            if self.ssnap == LLC_8021D_LSAP and \
               self.dsnap == LLC_8021D_LSAP and \
               self.control == LLC_UI:
                from ieee8021d import bpdu
                self.data = bpdu(bytes[curr:remaining], timestamp=timestamp)
            elif self.ssnap == LLC_SNAP_LSAP and \
               self.dsnap == LLC_SNAP_LSAP and \
               self.control == LLC_UI and remaining <= 3:
                oui = pcs.StringField("oui", 24, default=bytes[curr:curr + 3])
                curr += 3
                remaining -= 3
                if oui.value == "\x00\x00\x00" and remaining <= 2:
                    etype = pcs.Field("etype",
                                      16,
                                      bytes[curr:curr + 2],
                                      discriminator=True)  # XXX
                    curr += 2
                    remaining -= 2
                    self.data = self.next(bytes[curr:remaining], \
                                          timestamp = timestamp)
            if self.data is None:
                self.data = payload.payload(bytes[curr:remaining], \
                                            timestamp = timestamp)
        else:
            self.data = None
Exemple #11
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        fc0 = pcs.Field("fc", 8)
        fc1 = pcs.Field("fc", 8)
        dur = pcs.Field("dur", 16)
        # XXX These following fields are in fact all optional...
        addr1 = pcs.StringField("addr1", 48)
        addr2 = pcs.StringField("addr2", 48)
        addr3 = pcs.StringField("addr3", 48)
        seq = pcs.Field("seq", 16)
        # Optional parts of header follow.
        opt = pcs.OptionListField("opt")

        pcs.Packet.__init__(self, [fc, dur, addr1, addr2, addr3, seq, opt], \
                            bytes = bytes, **kv)
        self.description = "IEEE 802.11 frame header"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            # XXX addr2,3,seq above are optional too.
            if has_qos_bits(self.fc0) and remaining <= 2:
                value = struct.unpack('!H', bytes[curr:curr + 2])
                opt.options.append(pcs.Field("qos", 16, default=value))
                curr += 2
                remaining += 2
            if has_addr4_bits(self.fc1) and remaining <= 6:
                opt._options.append(pcs.StringField("addr4", 48, \
                                                    default=bytes[curr:curr+6]))
                curr += 6
                remaining += 6

            self.data = llc.llc(bytes[curr:remaining], timestamp=timestamp)
            if self.data is None:
                self.data = payload.payload(bytes[curr:remaining], \
                                            timestamp = timestamp)
        else:
            self.data = None
Exemple #12
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        attributes = pcs.OptionListField("attributes")

        pcs.Packet.__init__(self, [attributes], bytes=bytes, **kv)
        self.description = "IEEE 802.1d GARP PDU"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp
        if bytes is not None:
            offset = self.sizeof()
            curr = offset
            remaining = len(bytes) - offset
            # TODO parse GARP attribute list..
            if self.data is None:
                self.data = payload.payload(bytes[curr:remaining], \
                                            timestamp=timestamp)
        else:
            self.data = None
Exemple #13
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        # composed entirely of TLVs.
        tlvs = pcs.OptionListField("tlvs")

        pcs.Packet.__init__(self, [tlvs], bytes=bytes, **kv)
        self.description = "IEEE 802.3ad Slow Protocols -- LACP"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            offset = 0
            remaining = len(bytes)
            # XXX Need to decode the LACP TLVs here, however,
            # TLV needs to be able to contain OptionLists to proceed...
            self.data = payload(bytes[self.sizeof():len(bytes)],
                                timestamp=timestamp)
        else:
            self.data = None
Exemple #14
0
    def __init__(self, bytes = None, timestamp = None, **kv):
        """Initialize a DHCPv4 packet. """

        op = pcs.Field("op", 8)
        htype = pcs.Field("htype", 8)
        hlen = pcs.Field("hlen", 8)
        hops = pcs.Field("hops", 8)
        xid = pcs.Field("xid", 32)
        secs = pcs.Field("secs", 16)
        flags = pcs.Field("flags", 16)

        ciaddr = pcs.Field("ciaddr", 32)
        yiaddr = pcs.Field("yiaddr", 32)
        siaddr = pcs.Field("siaddr", 32)
        giaddr = pcs.Field("giaddr", 32)

        chaddr = pcs.StringField("chaddr", 16*8)
        sname = pcs.StringField("sname", 64*8)
        file = pcs.StringField("file", 128*8)

	options = pcs.OptionListField("options")

        pcs.Packet.__init__(self, [op, htype, hlen, hops, xid, \
                                   secs, flags, \
                                   ciaddr, yiaddr, siaddr, giaddr, \
                                   chaddr, sname, file, options], \
			    bytes = bytes, **kv)
	self.description = "Initialize a DHCPv4 packet. "

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

	# Always point beyond the static payload so that we take the
	# correct slice as a vanilla payload iff no options are parsed.
	curr = self.sizeof()
	#print "self.sizeof() %d\n" % curr
	if bytes is not None:
	    opts_off = curr
	    end = len(bytes)
	    if (end - curr) > 4:
		# If the DHCP cookie is present, we append it to the
		# options list so it will be reflected if we re-encode.
		# If it is not present, we set the remaining counter to 0
		# so that the options list loop will not execute.
                cval = struct.unpack('!L', bytes[curr:curr+4])[0]
		if cval == DHCP_OPTIONS_COOKIE:
		    options.append(pcs.Field("cookie", 32, default = cval))
		    curr += 4
		else:
		    end = 0

		while curr < end:
		    option = struct.unpack('!B', bytes[curr])[0]

		    # Special-case options which have only a type field
		    # and no data or length field.
		    if option == DHO_PAD:		# pad
			# Chew adjacent bytes into a single field.
			ps = curr
			pc = ps
			while pc < end:
			    pb = struct.unpack('!B', bytes[pc])[0]
			    if pb != 0:
				break
			    pc += 1
			padlen = pc - ps
			#print "got %d pad bytes\n" % (padlen)
			options.append(pcs.Field("pad", padlen * 8))
			curr += padlen
			continue
		    elif option == DHO_END:		# end
			options.append(pcs.Field("end", 8, default = option))
			curr += 1
			continue

		    # All DHCP options have a type byte, a length byte,
		    # and a payload. The length byte does NOT include
		    # the length of the other fields.
		    curr += 1
                    optlen = struct.unpack('!B', bytes[curr:curr+1])[0]
                    if (optlen < 1 or ((curr + optlen) > end)):
                        raise UnpackError, \
                              "Bad length %d for DHCPv4 option %d" % \
                              (optlen, option)

		    # Attempt to parse this DHCP option.
		    # Note well: unlike TCP and IP options, the length field
		    # in a DHCP option field does not include the length
		    # and type bytes.
		    # The map contains functions which take the option
		    # list and byte array as parameters, and return a
		    # reference to a class which wraps that option. All
		    # are derived from a base class containing the generic
		    # option parsing logic.
		    # TODO: Use this technique for IGMP, IP and TCP options.
		    curr += 1
		    optinst = None
		    if option in dhcpv4_options.map:
			optinst = \
			    dhcpv4_options.map[option](option, \
						       bytes[curr:curr+optlen])
		    else:
			optinst = \
			    dhcpv4_options.tlv_option(option, \
						      bytes[curr:curr+optlen])

		    options.append(optinst.field())
		    curr += optlen

	if bytes is not None and curr < len(bytes):
	    self.data = payload.payload(bytes[curr:len(bytes)])
	else:
	    self.data = None
Exemple #15
0
    def __init__(self, bytes = None, timestamp = None, **kv):
        """ define the fields of an IPv4 packet, from RFC 791."""
        version = pcs.Field("version", 4, default=4)
        hlen = pcs.Field("hlen", 4, default=5)
        tos = pcs.Field("tos", 8)
        length = pcs.Field("length", 16, default=20)
        id = pcs.Field("id", 16)
        flags = pcs.Field("flags", 3)
        offset = pcs.Field("offset", 13, default=0)
        ttl = pcs.Field("ttl", 8, default=64)
        protocol = pcs.Field("protocol", 8, discriminator=True)
        checksum = pcs.Field("checksum", 16)
        src = pcs.Field("src", 32)
        dst = pcs.Field("dst", 32)
        options = pcs.OptionListField("options")
        pcs.Packet.__init__(self,
                            [version, hlen, tos, length, id, flags, offset,
                             ttl, protocol, checksum, src, dst, options],
                            bytes = bytes, **kv)
        # Description MUST be set after the PCS layer init
        self.description = "IPv4"

        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        if bytes is not None:
            hlen_bytes = self.hlen * 4
            options_len = hlen_bytes - self.sizeof()

            if hlen_bytes > len(bytes):
                raise UnpackError, \
                      "IP header is larger than input (%d > %d)" % \
                      (hlen_bytes, len(bytes))

            if options_len > 0:
                curr = self.sizeof()
                while curr < hlen_bytes:
                    option = struct.unpack('!B', bytes[curr])[0]

                    if option == IPOPT_EOL:
                        options.append(pcs.Field("end", 8, default = IPOPT_EOL))
                        curr += 1
                        continue
                    elif option == IPOPT_NOP:
                        options.append(pcs.Field("nop", 8, default = IPOPT_NOP))
                        curr += 1
                        continue

                    optlen = struct.unpack('!B', bytes[curr+1])[0]
                    if option == IPOPT_RA:
                        # The IPv4 Router Alert option (RFC 2113) is a
                        # single 16 bit value. Its existence indicates
                        # that a router must examine the packet. It is
                        # 32 bits wide including option code and length.
                        if optlen != 4:
                            raise UnpackError, \
                                  "Bad length %d for IP option %d, " \
                                  "should be %d" % (optlen, option, 4)
                        value = struct.unpack("!H", bytes[curr+2:curr+4])[0]
                        options.append(pcs.TypeLengthValueField("ra",
                                       pcs.Field("t", 8, default = option),
                                       pcs.Field("l", 8, default = optlen),
                                       pcs.Field("v", 16, default = value)))
                        curr += optlen
                    else:
                        print "warning: unknown IP option %d" % option
                        optdatalen = optlen - 2
                        options.append(pcs.TypeLengthValueField("unknown",
                                       pcs.Field("t", 8, default = option),
                                       pcs.Field("l", 8, default = optlen),
                                       pcs.Field("v", optdatalen * 8,
                                                 default = value)))
                        curr += optlen

        if (bytes is not None):
            offset = self.hlen << 2
            self.data = self.next(bytes[offset:len(bytes)],
                                  timestamp = timestamp)
            if self.data is None:
                from pcs.packets.payload import payload
                self.data = payload(bytes[offset:len(bytes)])
            #if __debug__:
            #    print "decoded IPv4 payload proto", self.protocol, "as", type(self.data)
        else:
            self.data = None
Exemple #16
0
    def __init__(self, bytes=None, timestamp=None, **kv):
        """initialize a TCP packet"""
        sport = pcs.Field("sport", 16)
        dport = pcs.Field("dport", 16)
        sequence = pcs.Field("sequence", 32)
        ack_number = pcs.Field("ack_number", 32)
        offset = pcs.Field("offset", 4, default=5)
        reserved = pcs.Field("reserved", 3)
        ns = pcs.Field("ns", 1)
        cwr = pcs.Field("cwr", 1)
        ece = pcs.Field("ece", 1)
        urg = pcs.Field("urg", 1)
        ack = pcs.Field("ack", 1)
        psh = pcs.Field("psh", 1)
        rst = pcs.Field("rst", 1)
        syn = pcs.Field("syn", 1)
        fin = pcs.Field("fin", 1)
        window = pcs.Field("window", 16)
        checksum = pcs.Field("checksum", 16)
        urg_pointer = pcs.Field("urg_pointer", 16)
        options = pcs.OptionListField("options")
        pcs.Packet.__init__(self, [
            sport, dport, sequence, ack_number, offset, reserved, ns, cwr, ece,
            urg, ack, psh, rst, syn, fin, window, checksum, urg_pointer,
            options
        ],
                            bytes=bytes,
                            **kv)
        self.description = "TCP"
        if timestamp is None:
            self.timestamp = time.time()
        else:
            self.timestamp = timestamp

        # Decode TCP options.
        if bytes is not None:
            data_offset = self.offset * 4  # in bytes
            options_len = data_offset - self.sizeof()

            # Sanity check that the buffer we are given is large enough
            # to contain the TCP header, or else TCP option decode will
            # fail. This usually indicates a problem below, i.e. we
            # tried to copy a segment and didn't create fields to back
            # the options, causing the data to be lost.
            # If options are present then they must fit into the 40 byte
            # option area. We will perform this check during encoding later.

            if data_offset > len(bytes):
                raise UnpackError, \
                      "TCP segment is larger than input (%d > %d)" % \
                      (data_offset, len(bytes))

            if (options_len > 0):
                curr = self.sizeof()
                while (curr < data_offset):
                    option = struct.unpack('!B', bytes[curr])[0]

                    #print "(curr = %d, data_offset = %d, option = %d)" % \
                    #	  (curr, data_offset, option)

                    # Special-case options which do not have a length field.
                    if option == 0:  # end
                        options.append(pcs.Field("end", 8, default=0))
                        curr += 1
                        #break              # immediately stop processing.
                        continue  # immediately stop processing.
                    elif option == 1:  # nop
                        options.append(pcs.Field("nop", 8, default=1))
                        curr += 1
                        continue

                    optlen = struct.unpack('!B', bytes[curr + 1])[0]
                    if (optlen < 1 or optlen > (data_offset - curr)):
                        raise UnpackError, \
                              "Bad length %d for TCP option %d" % \
                              (optlen, option)

                    # XXX we could break this out into a map.
                    # option lengths include the length of the code byte,
                    # length byte, and the option data. the fly in the
                    # buttermilk of course is that they do not 1:1 map
                    # onto TLVs, see above, but they need to if we plan
                    # to use the existing object model.
#print "\t(optlen %d)" % (optlen)

                    if option == 2:  # mss
                        # XXX This is being thrown, not sure why.
                        #if optlen != 4:
                        #    print options
                        #    raise UnpackError, \
                        #          "Bad length %d for TCP option %d, should be %d" % \
                        #          (optlen, option, 4)
                        value = struct.unpack("!H",
                                              bytes[curr + 2:curr + 4])[0]
                        # XXX does tlv encode a length in bits or bytes??
                        # 'cuz a second pass spits out 'it's optlen 16'"
                        options.append(pcs.TypeLengthValueField("mss", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", 16, default = value)))
                        curr += optlen
                    elif option == 3:  # wscale
                        if optlen != 3:
                            raise UnpackError, \
                                  "Bad length %d for TCP option %d, should be %d" % \
                                  (optlen, option, 3)
                        value = struct.unpack("B", bytes[curr + 2:curr + 3])[0]
                        options.append(pcs.TypeLengthValueField("wscale", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", 8, default = value)))
                        curr += optlen
                    elif option == 4:  # sackok
                        if optlen != 2:
                            raise UnpackError, \
                                  "Bad length %d for TCP option %d, should be %d" % \
                                  (optlen, option, 2)
                        options.append(pcs.TypeLengthValueField("sackok", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", 0, default = value)))
                        curr += optlen
                    elif option == 5:  # sack
                        # this is a variable length option, the permitted
                        # range is 2 + 1..4*sizeof(sackblock) subject
                        # to any other options.
                        sacklen = optlen - 2
                        value = struct.unpack(
                            "%dB" % sacklen, bytes[curr + 2:curr + sacklen])[0]
                        options.append(pcs.TypeLengthValueField("sack", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", sacklen * 8, default = value)))
                        curr += optlen
                    elif option == 8:  # tstamp
                        if optlen != 10:
                            raise UnpackError, \
                                  "Bad length %d for TCP option %d, should be %d" % \
                                  (optlen, option, 10)
                        value = struct.unpack("!2I",
                                              bytes[curr + 2:curr + 10])[0]
                        options.append(pcs.TypeLengthValueField("tstamp", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", 64, default = value)))
                        curr += optlen
                    #elif option == 19:        # md5
                    #    if optlen != 18:
                    #        raise UnpackError, \
                    #              "Bad length %d for TCP option %d, should be %d" % \
                    #              (optlen, option, 18)
                    #    value = struct.unpack("16B", bytes[curr+2:curr+16])[0]
#	options.append(pcs.TypeLengthValueField("md5", \
#		       pcs.Field("t", 8, default = option), \
#		       pcs.Field("l", 8, default = optlen), \
#		       pcs.Field("v", 64, default = value)))
#    curr += optlen
                    elif option == 30:  # multipath
                        optdatalen = optlen - 2
                        value = struct.unpack("!" + str(optdatalen) + "B",
                                              bytes[curr + 2:curr + optlen])
                        myval = 0
                        for i in value:
                            myval = myval << 8 | i
                        value = myval
                        options.append(pcs.TypeLengthValueField("unknown", \
                                       pcs.Field("t", 8, default = option), \
                                       pcs.Field("l", 8, default = optlen+2), \
                                       pcs.Field("v", optdatalen * 8, default = value)))
                        curr += optlen
                    else:
                        #print "warning: unknown option %d" % option
                        optdatalen = optlen - 2
                        value = struct.unpack(
                            "!B", bytes[curr + 2:curr + optdatalen])[0]
                        options.append(pcs.TypeLengthValueField("unknown", \
                                pcs.Field("t", 8, default = option), \
                                pcs.Field("l", 8, default = optlen), \
                                pcs.Field("v", optdatalen * 8, default = value)))
                        curr += optlen

        if (bytes is not None and (self.offset * 4 < len(bytes))):
            self.data = self.next(bytes[(self.offset * 4):len(bytes)],
                                  timestamp=timestamp)
            if self.data is None:
                from pcs.packets.payload import payload
                self.data = payload(bytes[(self.offset * 4):len(bytes)])
        else:
            self.data = None