Performs defragmentation of a list of IPv6 packets. Packets are reordered.
    Crap is dropped. What lacks is completed by 'X' characters.

def defragment6(packets):
    """
    Performs defragmentation of a list of IPv6 packets. Packets are reordered.
    Crap is dropped. What lacks is completed by 'X' characters.
    """

    # Remove non fragments
    lst = [x for x in packets if IPv6ExtHdrFragment in x]
    if not lst:
        return []

    id = lst[0][IPv6ExtHdrFragment].id

    llen = len(lst)
    lst = [x for x in lst if x[IPv6ExtHdrFragment].id == id]
    if len(lst) != llen:
        warning("defragment6: some fragmented packets have been removed from list")  # noqa: E501
    llen = len(lst)

    # reorder fragments
    res = []
    while lst:
        min_pos = 0
        min_offset = lst[0][IPv6ExtHdrFragment].offset
        for p in lst:
            cur_offset = p[IPv6ExtHdrFragment].offset
            if cur_offset < min_offset:
                min_pos = 0
                min_offset = cur_offset
        res.append(lst[min_pos])
        del(lst[min_pos])

    # regenerate the fragmentable part
    fragmentable = b""
    for p in res:
        q = p[IPv6ExtHdrFragment]
        offset = 8 * q.offset
        if offset != len(fragmentable):
            warning("Expected an offset of %d. Found %d. Padding with XXXX" % (len(fragmentable), offset))  # noqa: E501
        fragmentable += b"X" * (offset - len(fragmentable))
        fragmentable += raw(q.payload)

    # Regenerate the unfragmentable part.
    q = res[0]
    nh = q[IPv6ExtHdrFragment].nh
    q[IPv6ExtHdrFragment].underlayer.nh = nh
    q[IPv6ExtHdrFragment].underlayer.plen = len(fragmentable)
    del q[IPv6ExtHdrFragment].underlayer.payload
    q /= conf.raw_layer(load=fragmentable)
    del(q.plen)

    return IPv6(raw(q))