1
+ /*
2
+ * Copyright (c) 2024, COVESA
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are met:
6
+ *
7
+ * * Redistributions of source code must retain the above copyright notice,
8
+ * this list of conditions and the following disclaimer.
9
+ * * Redistributions in binary form must reproduce the above copyright
10
+ * notice, this list of conditions and the following disclaimer in the
11
+ * documentation and/or other materials provided with the distribution.
12
+ * * Neither the name of COVESA nor the names of its contributors may be
13
+ * used to endorse or promote products derived from this software without
14
+ * specific prior written permission.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ *
27
+ * SPDX-License-Identifier: BSD-3-Clause
28
+ */
29
+
30
+ #include <argp.h>
31
+ #include <stdlib.h>
32
+ #include <linux/if_ether.h>
33
+ #include <linux/if_packet.h>
34
+ #include <linux/if.h>
35
+ #include <stdint.h>
36
+ #include <string.h>
37
+ #include <unistd.h>
38
+ #include <inttypes.h>
39
+
40
+ #include "common/common.h"
41
+ #include "avtp/Udp.h"
42
+ #include "avtp/acf/Ntscf.h"
43
+ #include "avtp/acf/Tscf.h"
44
+ #include "avtp/acf/Common.h"
45
+ #include "avtp/acf/Gpc.h"
46
+ #include "avtp/CommonHeader.h"
47
+
48
+ #define MAX_PDU_SIZE 1500
49
+ #define MAX_MSG_SIZE 100
50
+
51
+ static char ifname [IFNAMSIZ ];
52
+ static uint8_t macaddr [ETH_ALEN ];
53
+ static uint8_t use_udp ;
54
+ static uint32_t udp_port = 17220 ;
55
+
56
+ static struct argp_option options [] = {
57
+ {"port" , 'p' , "UDP_PORT" , 0 , "UDP Port to listen on if UDP enabled" },
58
+ {"udp" , 'u' , 0 , 0 , "Use UDP" },
59
+ {"dst-mac-address" , 0 , 0 , OPTION_DOC , "Stream destination MAC address (If Ethernet)" },
60
+ {"ifname" , 0 , 0 , OPTION_DOC , "Network interface (If Ethernet)" },
61
+ { 0 }
62
+ };
63
+
64
+ static error_t parser (int key , char * arg , struct argp_state * state )
65
+ {
66
+ int res ;
67
+
68
+ switch (key ) {
69
+ case 'p' :
70
+ udp_port = atoi (arg );
71
+ break ;
72
+ case 'u' :
73
+ use_udp = 1 ;
74
+ break ;
75
+
76
+ case ARGP_KEY_NO_ARGS :
77
+ break ;
78
+
79
+ case ARGP_KEY_ARG :
80
+
81
+ if (state -> argc < 2 ){
82
+ argp_usage (state );
83
+ }
84
+
85
+ if (!use_udp ){
86
+
87
+ strncpy (ifname , arg , sizeof (ifname ) - 1 );
88
+
89
+ if (state -> next < state -> argc )
90
+ {
91
+ res = sscanf (state -> argv [state -> next ], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" ,
92
+ & macaddr [0 ], & macaddr [1 ], & macaddr [2 ],
93
+ & macaddr [3 ], & macaddr [4 ], & macaddr [5 ]);
94
+ if (res != 6 ) {
95
+ fprintf (stderr , "Invalid MAC address\n\n" );
96
+ argp_usage (state );
97
+ }
98
+ state -> next += 1 ;
99
+ }
100
+ }
101
+
102
+ break ;
103
+ }
104
+
105
+ return 0 ;
106
+ }
107
+
108
+ static struct argp argp = { options , parser , 0 , 0 };
109
+
110
+ int main (int argc , char * argv [])
111
+ {
112
+ int sk_fd , res ;
113
+ uint64_t msg_length , proc_bytes = 0 , msg_proc_bytes = 0 ;
114
+ uint64_t udp_seq_num , subtype , flag , acf_type , pdu_length ;
115
+ uint8_t pdu [MAX_PDU_SIZE ];
116
+ uint8_t * cf_pdu , * acf_pdu , * udp_pdu ;
117
+ uint64_t gpc_code ;
118
+ char * recd_msg ;
119
+
120
+ argp_parse (& argp , argc , argv , 0 , NULL , NULL );
121
+
122
+ if (use_udp ) {
123
+ sk_fd = create_listener_socket_udp (udp_port );
124
+ } else {
125
+ sk_fd = create_listener_socket (ifname , macaddr , ETH_P_TSN );
126
+ }
127
+
128
+ if (sk_fd < 0 )
129
+ return 1 ;
130
+
131
+ while (1 ) {
132
+ proc_bytes = 0 ;
133
+
134
+ res = recv (sk_fd , pdu , MAX_PDU_SIZE , 0 );
135
+ if (res < 0 || res > MAX_PDU_SIZE ) {
136
+ perror ("Failed to receive data" );
137
+ goto err ;
138
+ }
139
+
140
+ // If UDP is used the packets starts with an encapsulation number
141
+ if (use_udp ) {
142
+ udp_pdu = pdu ;
143
+ Avtp_Udp_GetField ((Avtp_Udp_t * )udp_pdu , AVTP_UDP_FIELD_ENCAPSULATION_SEQ_NO , & udp_seq_num );
144
+ cf_pdu = pdu + AVTP_UDP_HEADER_LEN ;
145
+ proc_bytes += AVTP_UDP_HEADER_LEN ;
146
+ } else {
147
+ cf_pdu = pdu ;
148
+ }
149
+
150
+ // Check if the packet is a control format packet (i.e. NTSCF or TSCF)
151
+ res = Avtp_CommonHeader_GetField ((Avtp_CommonHeader_t * )cf_pdu , AVTP_COMMON_HEADER_FIELD_SUBTYPE , & subtype );
152
+ if (res < 0 ) {
153
+ fprintf (stderr , "Failed to get subtype field: %d\n" , res );
154
+ goto err ;
155
+ }
156
+ if (subtype == AVTP_SUBTYPE_TSCF ){
157
+ proc_bytes += AVTP_TSCF_HEADER_LEN ;
158
+ Avtp_Tscf_GetField ((Avtp_Tscf_t * )cf_pdu , AVTP_TSCF_FIELD_STREAM_DATA_LENGTH , (uint64_t * ) & msg_length );
159
+ }else {
160
+ proc_bytes += AVTP_NTSCF_HEADER_LEN ;
161
+ Avtp_Ntscf_GetField ((Avtp_Ntscf_t * )cf_pdu , AVTP_NTSCF_FIELD_NTSCF_DATA_LENGTH , (uint64_t * ) & msg_length );
162
+ }
163
+
164
+ // Check if the control packet payload is a ACF GPC.
165
+ acf_pdu = & pdu [proc_bytes ];
166
+ Avtp_AcfCommon_GetField ((Avtp_AcfCommon_t * )acf_pdu , AVTP_ACF_FIELD_ACF_MSG_TYPE , & acf_type );
167
+ if (acf_type != AVTP_ACF_TYPE_GPC ) {
168
+ fprintf (stderr , "ACF type mismatch: expected %u, got %lu\n" ,
169
+ AVTP_ACF_TYPE_GPC , acf_type );
170
+ continue ;
171
+ }
172
+
173
+ // Parse the GPC Packet and print contents on the STDOUT
174
+ Avtp_Gpc_GetField ((Avtp_Gpc_t * )acf_pdu , AVTP_GPC_FIELD_GPC_MSG_ID , & gpc_code );
175
+ Avtp_Gpc_GetField ((Avtp_Gpc_t * )acf_pdu , AVTP_GPC_FIELD_ACF_MSG_LENGTH , & pdu_length );
176
+ if (pdu_length * 4 <= MAX_MSG_SIZE ) {
177
+ recd_msg = acf_pdu + AVTP_GPC_HEADER_LEN ;
178
+ printf ("%s : GPC Code %ld\n" , recd_msg , gpc_code );
179
+ }
180
+ }
181
+
182
+ return 0 ;
183
+
184
+ err :
185
+ close (sk_fd );
186
+ return 1 ;
187
+
188
+ }
0 commit comments