1#!/usr/bin/env python3
2#
3# Copyright (c) 2021 Intel Corporation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#    http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import getopt
18import socket
19import sys
20import os.path
21from datetime import datetime
22from scapy.all import *
23from scapy.layers.can import CAN
24
25interface = None
26verbose = True
27port = 4242
28pcap = None
29type = "Ether"
30cooked = False
31cooked_sllv1 = False
32cooked_sllv2 = False
33
34argv = sys.argv[1:]
35
36def usage():
37    print("Listen captured network data from Zephyr and save it " +
38        "optionally to pcap file.\n")
39    print(f"{sys.argv[0]} \\" +
40          "\n\t-i | --interface <network interface>" +
41          "\n\t\tListen this inferface for the data" +
42          "\n\t[-p | --port <UDP port>]" +
43          f"\n\t\tUDP port (default is {port}) where the capture data is received" +
44          "\n\t[-q | --quiet]" +
45          "\n\t\tDo not print packet information" +
46          "\n\t[-t | --type <L2 type of the data>]" +
47          f"\n\t\tScapy L2 type name of the UDP payload, default is {type}" +
48          "\n\t[-w | --write <pcap file name>]" +
49          "\n\t\tWrite the received data to file in PCAP format" +
50          "\n\t[-c | --cooked-sllv1]" +
51          "\n\t\tThe payload is Linux cooked mode v1 data" +
52          "\n\t[-C | --cooked-sllv2]" +
53          "\n\t\tThe payload is Linux cooked mode v2 data")
54
55try:
56    opts, args = getopt.getopt(argv,
57                               'cChi:p:qt:w:',
58                               ['cooked-sllv1', 'cooked-sllv2', 'help',
59                                'interface=', 'port=',
60                                'quiet', 'type=', 'write='])
61except getopt.GetoptError as err:
62    print(err)
63    usage()
64    sys.exit(2)
65
66for o, a in opts:
67    if o in ("-q", "--quiet"):
68        verbose = False
69    elif o in ("-h", "--help"):
70        usage()
71        sys.exit()
72    elif o in ("-i", "--interface"):
73        interface = a
74    elif o in ("-p", "--port"):
75        port = int(a)
76    elif o in ("-t", "--type"):
77        type = a
78    elif o in ("-w", "--write"):
79        pcap = a
80    elif o in ("-c", "--cooked-sllv1"):
81        cooked_sllv1 = True
82        cooked = True
83    elif o in ("-C", "--cooked-sllv2"):
84        cooked_sllv2 = True
85        cooked = True
86    else:
87        assert False, "unhandled option " + o
88
89if interface == None:
90    print("Network interface not set.\n")
91    usage()
92    sys.exit()
93
94if pcap != None and os.path.exists(pcap):
95    os.remove(pcap)
96
97sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
98sock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE,
99                interface.encode())
100sock.bind(('', port))
101
102def process_packet(data):
103    packet = eval(type)(data)
104
105    if cooked:
106        if cooked_sllv1:
107            packet = CookedLinux(_pkt = Packet.build(packet))
108        else:
109            packet = CookedLinuxV2(_pkt = Packet.build(packet))
110
111        packet.show()
112
113    if verbose:
114        now = datetime.utcnow()
115        hdr = now.strftime("%Y%m%dZ%H:%M:%S") + "." + str(now.microsecond)
116        print('[%s] %s' % (hdr, packet.summary()))
117    if pcap != None:
118        wrpcap(pcap, packet, append=True)
119
120while True:
121    data, address = sock.recvfrom(4096)
122    process_packet(data)
123