#!/usr/bin/env python
#
# Test script to generate frames corresponding to the RSS
# test vectors in the Microsoft RSS specification.

from pcs.packets.localhost import *
from pcs.packets.ethernet import *
from pcs.packets.ipv4 import *
from pcs.packets.ipv6 import *
from pcs.packets.icmpv4 import *
from pcs.packets.icmpv6 import *
from pcs.packets.tcp import *
from pcs.packets.payload import *
from pcs import *

import pdb

def main():

    from optparse import OptionParser
    
    parser = OptionParser()

    parser.add_option("-e", "--ether_source",
                      dest="ether_source", default=None,
                      help="Ethernet source address.")

    parser.add_option("-g", "--ether_dest",
                      dest="ether_dest", default=None,
                      help="Ethernet destination address.")

    parser.add_option("-I", "--ether_iface",
                      dest="ether_iface", default=None,
                      help="The name of the source network interface.")

    (options, args) = parser.parse_args()
 
    pktlist = []

    ##
    ## IPv4 test vectors
    ##

    # test case 1
    #   dest                  src                 v4-only hash
    #   161.142.100.80        66.9.149.187        0x323e8fc2
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('66.9.149.187'),  \
              dst=inet_atol('161.142.100.80')) / \
         icmpv4(type=8) / icmpv4echo(id=12345) / payload(payload="foobar")
    pktlist.append(p1)

    # test case 1a
    #   dest/port             src/port            v4 TCP hash
    #   161.142.100.80/1766   66.9.149.187/2794   0x51ccc178
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('66.9.149.187'),  \
              dst=inet_atol('161.142.100.80')) / \
         tcp(sport=2794, dport=1766, window=1024, reset=1, ack=1, \
             sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 2
    #   dest                  src                 v4-only hash
    #   65.69.140.83          199.92.111.2        0xd718262a
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('199.92.111.2'),  \
              dst=inet_atol('65.69.140.83')) / \
         icmpv4(type=8) / icmpv4echo(id=12345) / payload(payload="foobar")
    pktlist.append(p1)

    # test case 2a
    #   dest/port             src/port            v4 TCP hash
    #   65.69.140.83/4739     199.92.111.2/14230  0xc626b0ea
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('199.92.111.2'),  \
              dst=inet_atol('65.69.140.83')) / \
         tcp(sport=14230, dport=4739, window=1024, reset=1, ack=1, \
             sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 3
    #   dest                  src                 v4-only hash
    #   12.22.207.184         24.19.198.95        0xd2d0a5de
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('24.19.198.95'),  \
              dst=inet_atol('12.22.207.184')) / \
         icmpv4(type=8) / icmpv4echo(id=12345) / payload(payload="foobar")
    pktlist.append(p1)

    # test case 3a
    #   dest/port             src/port            v4 TCP hash
    #   12.22.207.184/38024   24.19.198.95/12898  0x5c2b394a
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('24.19.198.95'),  \
              dst=inet_atol('12.22.207.184')) / \
         tcp(sport=12898, dport=38024, window=1024, reset=1, ack=1, \
             sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 4
    #   dest                  src                  v4-only hash
    #   209.142.163.6         38.27.205.30         0x82989176
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('38.27.205.30'),  \
              dst=inet_atol('209.142.163.6')) / \
         icmpv4(type=8) / icmpv4echo(id=12345) / payload(payload="foobar")
    pktlist.append(p1)

    # test case 4a
    #   dest/port             src/port             v4 TCP hash
    #   209.142.163.6/2217    38.27.205.30/48228   0xafc7327f
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('38.27.205.30'),  \
              dst=inet_atol('209.142.163.6')) / \
         tcp(sport=48228, dport=2217, window=1024, reset=1, ack=1, \
             sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 5
    #   dest                  src                   v4-only hash
    #   202.188.127.2         153.39.163.191        0x5d1809c5
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('153.39.163.191'),  \
              dst=inet_atol('202.188.127.2')) / \
         icmpv4(type=8) / icmpv4echo(id=12345) / payload(payload="foobar")
    pktlist.append(p1)

    # test case 5a
    #   dest/port             src/port              v4 TCP hash
    #   202.188.127.2/1303    153.39.163.191/44251  0x10e828a2
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
         ipv4(ttl=0, src=inet_atol('153.39.163.191'),  \
              dst=inet_atol('202.188.127.2')) / \
         tcp(sport=44251, dport=1303, window=1024, reset=1, ack=1, \
             sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)


    ##
    ##  IPv6 test vectors
    ##

    # test case 1
    #   dest                src                     v6-only hash
    #   3ffe:2501:200:3::1  3ffe:2501:200:1fff::7   0x2cc18cd5
    p1= ethernet(src=ether_atob(options.ether_source),  \
                 dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0,  next_header = 59, \
             src=inet_pton(AF_INET6, '3ffe:2501:200:1fff::7'),  \
             dst=inet_pton(AF_INET6, '3ffe:2501:200:3::1'))
    pktlist.append(p1)

    # test case 1a
    #   dest/port                src                         v6 TCP hash
    #   3ffe:2501:200:3::1/1766  3ffe:2501:200:1fff::7/2794  0x40207d3d
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0, length = 20, \
             src=inet_pton(AF_INET6, '3ffe:2501:200:1fff::7'),  \
             dst=inet_pton(AF_INET6, '3ffe:2501:200:3::1')) / \
        tcp(sport=2794, dport=1766, window=1024, reset=1, ack=1, \
            sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 2
    #   dest            src                              v6-only hash
    #   ff02::1         3ffe:501:8::260:97ff:fe40:efab   0x0f0c461c 
    p1= ethernet(src=ether_atob(options.ether_source),  \
                 dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0,  next_header = 59, \
             src=inet_pton(AF_INET6, '3ffe:501:8::260:97ff:fe40:efab'),  \
             dst=inet_pton(AF_INET6, 'ff02::1'))
    pktlist.append(p1)

    # test case 2a
    #   dest/port       src                                    v6 TCP hash
    #   ff02::1/4739    3ffe:501:8::260:97ff:fe40:efab/14230   0xdde51bbf
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0, length = 20, \
             src=inet_pton(AF_INET6, '3ffe:501:8::260:97ff:fe40:efab'),  \
             dst=inet_pton(AF_INET6, 'ff02::1')) / \
        tcp(sport=14230, dport=4739, window=1024, reset=1, ack=1, \
            sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    # test case 3
    #   dest                         src
    #   fe80::200:f8ff:fe21:67cf     3ffe:1900:4545:3:200:f8ff:fe21:67cf
    #   v6-only hash
    #   0x4b61e985
    p1= ethernet(src=ether_atob(options.ether_source),  \
                 dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0,  next_header = 59, \
             src=inet_pton(AF_INET6, '3ffe:1900:4545:3:200:f8ff:fe21:67cf'),  \
             dst=inet_pton(AF_INET6, 'fe80::200:f8ff:fe21:67cf'))
    pktlist.append(p1)

    # test case 3a
    #   dest/port
    #   fe80::200:f8ff:fe21:67cf/38024
    #   src/port
    #   3ffe:1900:4545:3:200:f8ff:fe21:67cf/44251
    #   v6 TCP hash
    #   0x02d1feef
    p1 = ethernet(src=ether_atob(options.ether_source),  \
                  dst=ether_atob(options.ether_dest)) /  \
        ipv6(hop=0, length = 20, \
             src=inet_pton(AF_INET6, '3ffe:1900:4545:3:200:f8ff:fe21:67cf'),  \
             dst=inet_pton(AF_INET6, 'fe80::200:f8ff:fe21:67cf')) / \
        tcp(sport=44251, dport=38024, window=1024, reset=1, ack=1, \
            sequence=1, ack_number=2, offset=5)
    pktlist.append(p1)

    #
    # Write the packets out the network interface
    #
    output = PcapConnector(options.ether_iface)

    for p in pktlist:
        p.calc_lengths()
        p.calc_checksums()
        p.encode()

        out = output.write(p.bytes, len(p.bytes))
        
main()
