Rawsock library  v0.3.4
Library to make the use of raw sockets easier, under Linux. Currently supporting IPv4, UDP and a custom latency measurement protocol (LaMP - supported both in raw and non-raw sockets).
rawsock_lamp.c
1 // Rawsock library, licensed under GPLv2
2 // Version 0.3.4
3 #include "rawsock.h"
4 #include "rawsock_lamp.h"
6 #include <sys/time.h>
7 #include <string.h>
8 
34 void lampHeadPopulate(struct lamphdr *lampHeader, unsigned char ctrl, unsigned short id, unsigned short seq) {
35  lampHeader->reserved=PROTO_LAMP;
36  lampHeader->ctrl=(uint8_t) ctrl;
37  lampHeader->id=htons(id);
38  lampHeader->seq=htons(seq);
39  lampHeader->len=0;
40 
41  lampHeader->sec=0;
42  lampHeader->usec=0;
43 }
44 
61 void lampHeadSetConnType(struct lamphdr *initLampHeader, uint16_t mode_index) {
62  // If packet type is not INIT, ignore any operation on the LaMP header
63  if(initLampHeader->ctrl==CTRL_CONN_INIT && IS_INIT_INDEX_VALID(mode_index)) {
64  initLampHeader->len=htons(mode_index);
65  }
66 }
67 
83 void lampHeadSetFollowupCtrlType(struct lamphdr *followupLampHeader, uint16_t followup_type) {
84  // If packet type is not FOLLOWUP_CTRL, ignore any operation on the LaMP header
85  if(followupLampHeader->ctrl==CTRL_FOLLOWUP_CTRL && IS_FOLLOWUP_CTRL_TYPE_VALID(followup_type)) {
86  followupLampHeader->len=htons(followup_type);
87  }
88 }
89 
109 void lampHeadSetTimestamp(struct lamphdr *lampHeader, struct timeval *tStampPtr) {
110  struct timeval currtime;
111 
112  if(lampHeader->ctrl!=CTRL_PINGLIKE_REQ_TLESS && lampHeader->ctrl!=CTRL_PINGLIKE_REPLY_TLESS && lampHeader->ctrl!=CTRL_PINGLIKE_ENDREQ_TLESS && lampHeader->ctrl!=CTRL_PINGLIKE_ENDREPLY_TLESS) {
113  if(tStampPtr==NULL) {
114  gettimeofday(&currtime,NULL); // Set timestamp as very last operation, only if it is not a TLESS packet
115 
116  lampHeader->sec=hton64((uint64_t) currtime.tv_sec);
117  lampHeader->usec=hton64((uint64_t) currtime.tv_usec);
118  } else {
119  lampHeader->sec=hton64((uint64_t) tStampPtr->tv_sec);
120  lampHeader->usec=hton64((uint64_t) tStampPtr->tv_usec);
121  }
122  }
123 }
124 
137 void lampHeadIncreaseSeq(struct lamphdr *inpacket_headerptr) {
138  uint16_t seq=htons(inpacket_headerptr->seq); // Get current sequence number in the proper bit order
139  // Take into account ciclicity in the sequence numbers
140  if(inpacket_headerptr->seq==UINT16_MAX) {
141  seq=0;
142  } else {
143  seq++;
144  }
145  inpacket_headerptr->seq=ntohs(seq);
146 }
147 
160 void lampSetUnidirStop(struct lamphdr *lampHeader) {
161  lampHeader->ctrl=CTRL_UNIDIR_STOP;
162 }
163 
176 void lampSetPinglikeEndreq(struct lamphdr *lampHeader) {
177  lampHeader->ctrl=CTRL_PINGLIKE_ENDREQ;
178 }
179 
192 void lampSetPinglikeEndreqTless(struct lamphdr *lampHeader) {
193  lampHeader->ctrl=CTRL_PINGLIKE_ENDREQ_TLESS;
194 }
195 
214 void lampSetPinglikeEndreqAll(struct lamphdr *lampHeader) {
215  if(lampHeader->ctrl==CTRL_PINGLIKE_REQ) {
216  lampHeader->ctrl=CTRL_PINGLIKE_ENDREQ;
217  } else if(lampHeader->ctrl==CTRL_PINGLIKE_REQ_TLESS) {
218  lampHeader->ctrl=CTRL_PINGLIKE_ENDREQ_TLESS;
219  }
220 }
221 
246 void lampEncapsulate(byte_t *packet, struct lamphdr *lampHeader, byte_t *data, size_t payloadsize) {
247  lampHeader->len=htons(payloadsize);
248 
249  memcpy(packet,lampHeader,sizeof(struct lamphdr));
250  memcpy(packet+sizeof(struct lamphdr),data,payloadsize);
251 }
252 
276 int rawLampSend(int descriptor, struct sockaddr_ll addrll, struct lamphdr *inpacket_headerptr, byte_t *ethernetpacket, size_t finalpacketsize, endflag_t end_flag, protocol_t llprot) {
277  struct timeval currtime;
278  struct udphdr *inpacket_headerptr_udp;
279  struct iphdr *inpacket_headerptr_ipv4;
280  size_t packetsize;
281 
282  if(IS_UNIDIR(inpacket_headerptr->ctrl) && end_flag==FLG_STOP) {
283  inpacket_headerptr->ctrl=CTRL_UNIDIR_STOP;
284  } else if(IS_PINGLIKE(inpacket_headerptr->ctrl) && end_flag==FLG_STOP) {
285  if(inpacket_headerptr->ctrl==CTRL_PINGLIKE_REQ) {
286  inpacket_headerptr->ctrl=CTRL_PINGLIKE_ENDREQ;
287  } else if(inpacket_headerptr->ctrl==CTRL_PINGLIKE_REQ_TLESS) {
288  inpacket_headerptr->ctrl=CTRL_PINGLIKE_ENDREQ_TLESS;
289  }
290  }
291 
292  if(IS_UNIDIR(inpacket_headerptr->ctrl) || inpacket_headerptr->ctrl==CTRL_PINGLIKE_REQ || inpacket_headerptr->ctrl==CTRL_PINGLIKE_ENDREQ) {
293  gettimeofday(&currtime,NULL); // Set timestamp as very last operation, only if it is not a ping-like reply
294 
295  inpacket_headerptr->sec=hton64((uint64_t) currtime.tv_sec);
296  inpacket_headerptr->usec=hton64((uint64_t) currtime.tv_usec);
297  }
298 
299  // Compute again the checksum depending on the lower layer protocol (UDP is supported as of now)
300  switch(llprot) {
301  case UDP:
302  // Try to obtain the UDP header pointer by subtracting a certain offset to the LaMP inpacket_headerptr
303  inpacket_headerptr_udp=(struct udphdr *) ((byte_t *)inpacket_headerptr-sizeof(struct udphdr));
304  // Try to obtain the IPv4 header pointer by subtracting a certain offset to the LaMP inpacket_headerptr
305  inpacket_headerptr_ipv4=(struct iphdr *) ((byte_t *)inpacket_headerptr_udp-sizeof(struct iphdr));
306 
307  inpacket_headerptr_udp->check=0;
308  if(IS_INIT(inpacket_headerptr->ctrl) || IS_FOLLOWUP_CTRL(inpacket_headerptr->ctrl)) {
309  packetsize=sizeof(struct udphdr)+LAMP_HDR_SIZE();
310  } else {
311  packetsize=sizeof(struct udphdr)+LAMP_HDR_PAYLOAD_SIZE(ntohs(inpacket_headerptr->len));
312  }
313 
314  inpacket_headerptr_udp->check=minirighi_udp_checksum(inpacket_headerptr_udp,packetsize,inpacket_headerptr_ipv4->saddr,inpacket_headerptr_ipv4->daddr);
315  break;
316  default: // case UNSET_P -> do nothing
317  break;
318  }
319 
320  return (sendto(descriptor,ethernetpacket,finalpacketsize,0,(struct sockaddr *)&addrll,sizeof(struct sockaddr_ll))!=finalpacketsize);
321 }
322 
339 void lampHeadGetData(byte_t *lampPacket, lamptype_t *type, unsigned short *id, unsigned short *seq, unsigned short *len, struct timeval *timestamp, byte_t *payload) {
340  struct lamphdr *lampHeader=(struct lamphdr *) lampPacket;
341  byte_t *payloadptr=(lampPacket+LAMP_HDR_SIZE());
342 
343  if(type) *type=(lampHeader->ctrl) & 0x0F;
344  if(id) *id=ntohs(lampHeader->id);
345  if(seq) *seq=ntohs(lampHeader->seq);
346  if(len) *len=ntohs(lampHeader->len);
347  if(timestamp) {
348  timestamp->tv_sec=(time_t) ntoh64(lampHeader->sec);
349  timestamp->tv_usec=(suseconds_t) ntoh64(lampHeader->usec);
350  }
351 
352  if(payload && lampHeader->len!=0x00) {
353  memcpy(payload,payloadptr,lampHeader->len);
354  }
355 }
356 
383 byte_t *lampGetPacketPointers(byte_t *pktbuf,struct lamphdr **lampHeader) {
384  byte_t *payload;
385 
386  *lampHeader=(struct lamphdr*) pktbuf;
387  payload=pktbuf+sizeof(struct lamphdr);
388 
389  return payload;
390 }
#define IS_UNIDIR(ctrl)
Definition: rawsock_lamp.h:72
void lampHeadPopulate(struct lamphdr *lampHeader, unsigned char ctrl, unsigned short id, unsigned short seq)
Populate a LaMP header.
Definition: rawsock_lamp.c:34
#define CTRL_PINGLIKE_REQ_TLESS
Definition: rawsock_lamp.h:36
#define CTRL_FOLLOWUP_CTRL
Definition: rawsock_lamp.h:40
uint8_t reserved
Definition: rawsock_lamp.h:148
#define PROTO_LAMP
Definition: rawsock_lamp.h:24
uint16_t len
Definition: rawsock_lamp.h:152
#define CTRL_PINGLIKE_ENDREPLY_TLESS
Definition: rawsock_lamp.h:39
void lampSetUnidirStop(struct lamphdr *lampHeader)
Set the control field of a LaMP header to "Unidirectional stop".
Definition: rawsock_lamp.c:160
#define IS_INIT_INDEX_VALID(idx)
Definition: rawsock_lamp.h:67
void lampEncapsulate(byte_t *packet, struct lamphdr *lampHeader, byte_t *data, size_t payloadsize)
Combine LaMP payload and header.
Definition: rawsock_lamp.c:246
void lampHeadSetConnType(struct lamphdr *initLampHeader, uint16_t mode_index)
Set the INIT type field ("length or packet type") inside a LaMP header.
Definition: rawsock_lamp.c:61
uint64_t ntoh64(uint64_t netu64)
Convert a 64-bit unsigned value between network and host byte order.
Definition: rawsock.c:532
uint64_t sec
Definition: rawsock_lamp.h:153
uint8_t ctrl
Definition: rawsock_lamp.h:149
#define IS_FOLLOWUP_CTRL_TYPE_VALID(idx)
Definition: rawsock_lamp.h:71
#define IS_FOLLOWUP_CTRL(ctrl)
Definition: rawsock_lamp.h:69
int rawLampSend(int descriptor, struct sockaddr_ll addrll, struct lamphdr *inpacket_headerptr, byte_t *ethernetpacket, size_t finalpacketsize, endflag_t end_flag, protocol_t llprot)
Send LaMP packet over a raw socket, automatically setting some fields such as the timestamp (when nee...
Definition: rawsock_lamp.c:276
uint64_t hton64(uint64_t hostu64)
Convert a 64-bit unsigned value between host and network byte order.
Definition: rawsock.c:513
void lampSetPinglikeEndreq(struct lamphdr *lampHeader)
Set the control field of a LaMP header to "Ping-like (bidirectional) end request".
Definition: rawsock_lamp.c:176
#define CTRL_CONN_INIT
Definition: rawsock_lamp.h:35
protocol_t
Protocol type enumerator.
Definition: rawsock.h:125
void lampHeadSetTimestamp(struct lamphdr *lampHeader, struct timeval *tStampPtr)
Set the timestamp inside a LaMP Header.
Definition: rawsock_lamp.c:109
void lampHeadGetData(byte_t *lampPacket, lamptype_t *type, unsigned short *id, unsigned short *seq, unsigned short *len, struct timeval *timestamp, byte_t *payload)
Extract relevant data from a LaMP packet.
Definition: rawsock_lamp.c:339
void lampHeadIncreaseSeq(struct lamphdr *inpacket_headerptr)
Increase the sequence number inside a LaMP header.
Definition: rawsock_lamp.c:137
Definition: rawsock.h:127
void lampSetPinglikeEndreqTless(struct lamphdr *lampHeader)
Set the control field of a LaMP header to "Ping-like (bidirectional) end request (timestampless)".
Definition: rawsock_lamp.c:192
uint8_t byte_t
Definition: rawsock.h:102
Main LaMP packet header structure.
Definition: rawsock_lamp.h:147
#define IS_INIT(ctrl)
Definition: rawsock_lamp.h:68
#define CTRL_PINGLIKE_REQ
Definition: rawsock_lamp.h:27
#define IS_PINGLIKE(ctrl)
Definition: rawsock_lamp.h:73
#define CTRL_UNIDIR_STOP
Definition: rawsock_lamp.h:32
uint16_t seq
Definition: rawsock_lamp.h:151
uint64_t usec
Definition: rawsock_lamp.h:154
uint16_t minirighi_udp_checksum(const void *buff, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
Calculate the UDP checksum (calculated with the whole packet)
#define CTRL_PINGLIKE_REPLY_TLESS
Definition: rawsock_lamp.h:37
uint16_t id
Definition: rawsock_lamp.h:150
lamptype_t
LaMP type enumerator.
Definition: rawsock_lamp.h:99
void lampHeadSetFollowupCtrlType(struct lamphdr *followupLampHeader, uint16_t followup_type)
Set the FOLLOWUP_CTRL type field ("length or packet type") inside a LaMP header.
Definition: rawsock_lamp.c:83
#define CTRL_PINGLIKE_ENDREQ
Definition: rawsock_lamp.h:29
#define CTRL_PINGLIKE_ENDREQ_TLESS
Definition: rawsock_lamp.h:38
byte_t * lampGetPacketPointers(byte_t *pktbuf, struct lamphdr **lampHeader)
Get pointers to header and payload in a LaMP packet.
Definition: rawsock_lamp.c:383
#define LAMP_HDR_SIZE()
Definition: rawsock_lamp.h:81
void lampSetPinglikeEndreqAll(struct lamphdr *lampHeader)
Set the control field of a LaMP header to "Ping-like (bidirectional) end request".
Definition: rawsock_lamp.c:214
endflag_t
End flag type.
Definition: rawsock_lamp.h:132