NTP implementation C - c

Can someone find what I'm missing on my ntp implementation?
I'm programming an 32-bit microcontroller ARM Cortex M3.
I have three functions - wifiSend which calls the bsdUdpClient and bsdUdpServer. The bsdUdpClient sends data to the server and bsdUdpServer listens to the reserved NTP port and receive the data of the NTP server.
I got no error messages at all but the buffer received is empty.
static void wifiSend(xTimerHandle xTimer){
uint16_t AddrSize = sizeof(SlSockAddrIn_t);
if (STATUS_OK != bsdUdpClient(SERVER_PORT, AddrSize)){
printf("Failed to send udp packet\n\r");
assert(false);
}
if (STATUS_OK != bsdUdpServer(SERVER_PORT, AddrSize))
printf("Failed to receive udp packet\n\r");
}
static returnTypes_t bsdUdpClient(uint16_t port, uint16_t AddrSize){
int16_t Status = (int16_t) ZERO;
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0xE3; //0b11100011; // LI, Version, Mode
packetBuffer[1] = 0x00; // Stratum, or type of clock
packetBuffer[2] = 0x06; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
Addr.sin_family = SL_AF_INET;
Addr.sin_port = sl_Htons((uint16_t) port);
Addr.sin_addr.s_addr = sl_Htonl(SERVER_IP);
SockID = sl_Socket(SL_AF_INET, SL_SOCK_DGRAM, (uint32_t) ZERO);
if (SockID < (int16_t) ZERO)
return (SOCKET_ERROR);
Status = sl_SendTo(SockID, packetBuffer, NTP_PACKET_SIZE * sizeof(uint8_t), (uint32_t) ZERO, (SlSockAddr_t *) &Addr, AddrSize);
if (Status <= (int16_t) ZERO) {
Status = sl_Close(SockID);
if (Status < 0)
return (SEND_ERROR);
return (SEND_ERROR);
}
Status = sl_Close(SockID);
if (Status < 0)
return (SEND_ERROR);
return (STATUS_OK);
}
static returnTypes_t bsdUdpServer(uint16_t port, uint16_t AddrSize){
int16_t Status = (int16_t) ZERO;
LocalAddr.sin_family = SL_AF_INET;
LocalAddr.sin_port = sl_Htons(5001);
LocalAddr.sin_addr.s_addr = 0;
SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, (uint32_t) ZERO);
if (SockID < 0){
printf("error on sl_Socket\n\r");
return SOCKET_ERROR;
}
Status = sl_Bind(SockID, (SlSockAddr_t *) &LocalAddr, AddrSize);
if (Status < 0){
printf("problem on sl_Bind\n\r");
return SOCKET_ERROR;
}
Status = sl_RecvFrom(SockID, packetBuffer, NTP_PACKET_SIZE * sizeof(uint8_t), (uint32_t) ZERO, (SlSockAddr_t *) &Addr, &AddrSize);
if (Status < (int16_t) ZERO){
printf("error - no bytes received: %d\n\r", (int16_t)Status);
return SOCKET_ERROR;
}
Status = sl_Close(SockID);
if (Status < 0)
printf("problem on sl_Close\n\r");
uint8_t index3 = packetBuffer[40];
uint8_t index2 = packetBuffer[41];
uint8_t index1 = packetBuffer[42];
uint8_t index0 = packetBuffer[43];
uint16_t highWord = index3 << 16 | index2;
uint16_t lowWord = index1 << 16 | index0;
uint32_t secondsSince1900 = highWord << 16 | lowWord;
printf("Seconds since 1 Janeiro de 1900: %ld\n\r", secondsSince1900);
return (STATUS_OK);
}

Your client code sends a query, but then closes the socket and never listens for a reply.
Your server code waits for a query, but then never sends any response.
Neither of them appear to do anything particularly useful. You should complete the client code so that it listens for a reply before it closes the socket. Note that you should use a timeout so that you don't wait forever in the event that either the query or the response is lost.

Thanks to #DavidSchwartz, I have now a working solution.
I also fixed a bug I had when I was trying to extract the number of seconds since 1st January of 1900 from the packet received.
I hope this can help someone.
TO BE IMPROVED: add a timeout to avoid a blocking state if there is no response from the server
#define NTP_PACKET_SIZE 48
uint8_t packetBuffer[ NTP_PACKET_SIZE];
static returnTypes_t bsdUdpClient(uint16_t AddrSize){
int16_t Status = (int16_t) ZERO;
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
packetBuffer[0] = 0xE3; //0b11100011; // LI, Version, Mode
packetBuffer[1] = 0x00; // Stratum, or type of clock
packetBuffer[2] = 0x06; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
SockID = sl_Socket(SL_AF_INET, SL_SOCK_DGRAM, (uint32_t) ZERO);
if (SockID < (int16_t) ZERO)
return (SOCKET_ERROR);
/*make the request to the server*/
Status = sl_SendTo(SockID, packetBuffer, NTP_PACKET_SIZE * sizeof(uint8_t), (uint32_t) ZERO, (SlSockAddr_t *) &Addr, AddrSize);
/*Check if 0 transmitted bytes sent or error condition*/
if (Status <= (int16_t) ZERO) {
sl_Close(SockID);
return (SEND_ERROR);
}
else
printf("request sent successfully\n\r");
/* receive the reply from the server*/
Status = sl_RecvFrom(SockID, packetBuffer, NTP_PACKET_SIZE * sizeof(uint8_t), (uint32_t) ZERO, (SlSockAddr_t *) &Addr, &AddrSize);
if (Status < (int16_t) ZERO){
printf("error - no bytes received: %d\n\r", (int16_t)Status);
return SOCKET_ERROR;
}
else
printf("reply received\n\r");
Status = sl_Close(SockID);
if (Status < 0)
printf("problem on sl_Close\n\r");
uint8_t index3 = packetBuffer[40];
uint8_t index2 = packetBuffer[41];
uint8_t index1 = packetBuffer[42];
uint8_t index0 = packetBuffer[43];
uint16_t highWord = index3 << 8 | index2;
uint16_t lowWord = index1 << 8 | index0;
uint32_t secondsSince1900 = highWord << 16 | lowWord;
printf("Seconds since 1 Janeiro de 1900: %lu\n\r", secondsSince1900);
return (STATUS_OK);
}

Related

Raspberry Pi Pico DMA to a I2C device

I'm using the C/C++ SDK of the Pi Pico and trying to use the DMA to read I2C data in the background. However, there is no example script in Pico-Examples that shows how to use the DMA to read from I2C. There is one for SPI, called spi-dma. But It doesn't directly correlate to I2C because I have to give the device address too along with the register address for I2C.
Can anyone help me understand what to change in the following lines for it to work with an I2C device?
const uint dma_rx = dma_claim_unused_channel(true);
static uint8_t rxbuf[1024];
dma_channel_config c = dma_channel_get_default_config(dma_rx);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, spi_get_dreq(spi_default, false));
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
dma_channel_configure(dma_rx, &c,
rxbuf, // write address
&spi_get_hw(spi_default)->dr, // read address
TEST_SIZE, // element count (each element is of size transfer_data_size)
false); // don't start yet
dma_start_channel_mask(1u << dma_rx);
dma_channel_wait_for_finish_blocking(dma_rx);
dma_channel_unclaim(dma_rx);
I Know a few changes to be made like
channel_config_set_dreq(&c, i2c_get_dreq(i2c_default, false));
dma_channel_configure(dma_rx, &c,
rxbuf, // write address
i2c_get_hw(i2c_default), // read address
TEST_SIZE, // element count (each element is of size transfer_data_size)
true); // don't start yet
But what more after this?
Don't like the SPI protocol, when you read from an I2C device, you also need to send some register address to the device.
There are some helper functions to illustrate the process.
long long rx_ind = 0;
uint16_t rx_buf[300];
static int gi2c_read_blocking_internal(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop,
check_timeout_fn timeout_check, timeout_state_t *ts) {
invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
invalid_params_if(I2C, i2c_reserved_addr(addr));
invalid_params_if(I2C, len == 0);
invalid_params_if(I2C, ((int)len) < 0);
int kk = rx_ind;
i2c->hw->enable = 0;
i2c->hw->tar = addr;
i2c->hw->enable = 1;
bool abort = false;
bool timeout = false;
uint32_t abort_reason;
int byte_ctr;
int ilen = (int)len;
for (byte_ctr = 0; byte_ctr < ilen; ++byte_ctr) {
bool first = byte_ctr == 0;
bool last = byte_ctr == ilen - 1;
while (!i2c_get_write_available(i2c))
tight_loop_contents();
rx_buf[rx_ind++] =
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
I2C_IC_DATA_CMD_CMD_BITS;
i2c->hw->data_cmd =
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read
do {
abort_reason = i2c->hw->tx_abrt_source;
abort = (bool) i2c->hw->clr_tx_abrt;
if (timeout_check) {
timeout = timeout_check(ts);
abort |= timeout;
}
} while (!abort && !i2c_get_read_available(i2c));
if (abort)
break;
*dst++ = (uint8_t) i2c->hw->data_cmd;
rx_buf[rx_ind++] = *(dst-1);
}
int rval;
if (abort) {
if (timeout)
rval = PICO_ERROR_TIMEOUT;
else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
// No reported errors - seems to happen if there is nothing connected to the bus.
// Address byte not acknowledged
rval = PICO_ERROR_GENERIC;
} else {
// panic("Unknown abort from I2C instance #%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
rval = PICO_ERROR_GENERIC;
}
} else {
rval = byte_ctr;
}
i2c->restart_on_next = nostop;
do{
printf("rx %#08x\n", rx_buf[kk++]);
} while (rx_ind > kk);
return rval;
}
long long tx_ind = 0;
uint16_t tx_buf[300];
static int gi2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
check_timeout_fn timeout_check, struct timeout_state *ts) {
invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
invalid_params_if(I2C, i2c_reserved_addr(addr));
// Synopsys hw accepts start/stop flags alongside data items in the same
// FIFO word, so no 0 byte transfers.
invalid_params_if(I2C, len == 0);
invalid_params_if(I2C, ((int)len) < 0);
int kk = tx_ind;
i2c->hw->enable = 0;
i2c->hw->tar = addr;
i2c->hw->enable = 1;
bool abort = false;
bool timeout = false;
uint32_t abort_reason = 0;
int byte_ctr;
int ilen = (int)len;
for (byte_ctr = 0; byte_ctr < ilen; ++byte_ctr) {
bool first = byte_ctr == 0;
bool last = byte_ctr == ilen - 1;
tx_buf[tx_ind++] =
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
*src;
i2c->hw->data_cmd =
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
*src++;
// Wait until the transmission of the address/data from the internal
// shift register has completed. For this to function correctly, the
// TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag
// was set in i2c_init.
do {
if (timeout_check) {
timeout = timeout_check(ts);
abort |= timeout;
}
tight_loop_contents();
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS));
// If there was a timeout, don't attempt to do anything else.
if (!timeout) {
abort_reason = i2c->hw->tx_abrt_source;
if (abort_reason) {
// Note clearing the abort flag also clears the reason, and
// this instance of flag is clear-on-read! Note also the
// IC_CLR_TX_ABRT register always reads as 0.
i2c->hw->clr_tx_abrt;
abort = true;
}
if (abort || (last && !nostop)) {
// If the transaction was aborted or if it completed
// successfully wait until the STOP condition has occured.
// TODO Could there be an abort while waiting for the STOP
// condition here? If so, additional code would be needed here
// to take care of the abort.
do {
if (timeout_check) {
timeout = timeout_check(ts);
abort |= timeout;
}
tight_loop_contents();
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS));
// If there was a timeout, don't attempt to do anything else.
if (!timeout) {
i2c->hw->clr_stop_det;
}
}
}
// Note the hardware issues a STOP automatically on an abort condition.
// Note also the hardware clears RX FIFO as well as TX on abort,
// because we set hwparam IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
if (abort)
break;
}
int rval;
// A lot of things could have just happened due to the ingenious and
// creative design of I2C. Try to figure things out.
if (abort) {
if (timeout)
rval = PICO_ERROR_TIMEOUT;
else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
// No reported errors - seems to happen if there is nothing connected to the bus.
// Address byte not acknowledged
rval = PICO_ERROR_GENERIC;
} else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) {
// Address acknowledged, some data not acknowledged
rval = byte_ctr;
} else {
//panic("Unknown abort from I2C instance #%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
rval = PICO_ERROR_GENERIC;
}
} else {
rval = byte_ctr;
}
// nostop means we are now at the end of a *message* but not the end of a *transfer*
i2c->restart_on_next = nostop;
do{
printf("tx %#08x\n", tx_buf[kk++]);
} while (tx_ind > kk);
return rval;
}
int gi2c_write_blocking(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop) {
return gi2c_write_blocking_internal(i2c, addr, src, len, nostop, NULL, NULL);
}
int gi2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop) {
return gi2c_read_blocking_internal(i2c, addr, dst, len, nostop, NULL, NULL);
}
// Write 1 byte to the specified register
int reg_write( i2c_inst_t *i2c,
const uint addr,
const uint8_t reg,
uint8_t *buf,
const uint8_t nbytes) {
int num_bytes_read = 0;
uint8_t msg[nbytes + 1];
// Check to make sure caller is sending 1 or more bytes
if (nbytes < 1) {
return 0;
}
// Append register address to front of data packet
msg[0] = reg;
for (int i = 0; i < nbytes; i++) {
msg[i + 1] = buf[i];
}
printf("write func.\n");
// Write data to register(s) over I2C
gi2c_write_blocking(i2c, addr, msg, (nbytes + 1), false);
return num_bytes_read;
}
// Read byte(s) from specified register. If nbytes > 1, read from consecutive
// registers.
int reg_read( i2c_inst_t *i2c,
const uint addr,
const uint8_t reg,
uint8_t *buf,
const uint8_t nbytes) {
int num_bytes_read = 0;
// Check to make sure caller is asking for 1 or more bytes
if (nbytes < 1) {
return 0;
}
printf("write func.\n");
// Read data from register(s) over I2C
gi2c_write_blocking(i2c, addr, &reg, 1, true);
printf("read func.\n");
num_bytes_read = gi2c_read_blocking(i2c, addr, buf, nbytes, false);
return num_bytes_read;
}
In gi2c_read_blocking_internal function, you can see first you need to write the i2c->hw->data_cmd to control the stop, restart... states in I2C protocol, and then you can read from i2c->hw->data_cmd to get information from I2C device.
In reg_read function, first send the register address by call gi2c_write_blocking, and then you can read the register by call gi2c_read_blocking
After look up the whole process, you need two dma channel trigger simultaneously to simulate the reading from I2C device process(one for write i2c->hw->data_cmd and one for read i2c->hw->data_cmd).

Alsa plays audio get from CAN FD

I am trying to use Alsa library to reproduce the audio I get from my CAN FD communication, into my headphones. I don't quite understand how to properly configure Alsa's parameters, in order to be able to listen to the sound I get from the CAN FD.
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 16000; /* stream rate */
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 40000; /* ring buffer length in us */
static unsigned int period_time = 120000; /* period time in us */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
int size;
while (1) {
do {
nbytes = read(s, &frame, sizeof(struct canfd_frame));
} while (nbytes == 0);
for (x = 0; x < 64; x = x + 2) {
buffer[a] = ((uint32_t) frame.data[x] << 8)
| ((uint32_t) (frame.data[x + 1]));
a++;
}
//err=snd_pcm_writei(handle,buffer,32);
//printf("Datos = %d\n", err);
memcpy(total1 + i * 32, buffer, 32 * sizeof(uint32_t));
i++;
a = 0;
if (i == 500) {
buffer_length=16000;
ptr = total1;
while(buffer_length > 0){
err = snd_pcm_writei(handle, ptr, 16000);
printf("Datos = %d\n", err);
snd_pcm_avail_delay(handle, &availp, &delayp);
//printf("available frames =%ld delay = %ld z = %d\n", availp, delayp, z);
if (err == -EAGAIN)
continue;
if(err < 0){
err=snd_pcm_recover(handle, err, 1);
}
else{
ptr += err * channels;
buffer_length -= err;
z++;
}
if(err<0){
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
}
i = 0;
}
This is a part of my code, I don't thinks posting the whole code is worth. I don't understand which values should I give to buffer_time, period_time and how to be able to listen to what a I get through the CAN FD in real time. I am using snd_pcm_writei, inserting a buffer I fill with some samples I get from the CAN FD. I don't know which size should I give to the buffer and to the "frames" variable, another one that I don't quite understand, eventhough I have read some about it.
Any idea how should I configure my system? (buffer_time, period_time, buffer_size, frame,...)
I have tried using different buffer and frame sizes, but I don't think I understand how it works properly. How can I calculate the size of the frame and buffer of the snd_pcm_writei(), in order to listen in Real Time to the audio?
Should I use two differente threads? One to create the buffer with the CAN FD information and the other one to handle the buffer and the audio output?
Thanks in advance,
Ander.
I have finally managed to hear my self through the headphones. I have changed my configuration posted on my previous in order to sincronize it with the data I get from the CAN FD. I will post part of my code down here in case somebody needs an example. The most important part having to handle buffers like these is to handle the time to fill and the time to communicate it. Handling the time and configuring the Alsa parameters accordingly makes easier to handle the buffers.
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 22000; /* stream rate */
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 1000; /* ring buffer length in us */
static unsigned int period_time = 10000; /* period time in us */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
int size;
static snd_pcm_sframes_t buffer_size;
static snd_pcm_sframes_t period_size;
static snd_output_t *output = NULL;
snd_pcm_sframes_t delayp;
snd_pcm_sframes_t availp;
snd_pcm_uframes_t frames;
static void write_loop(snd_pcm_t *handle) {
uint32_t *buffer = malloc(16000 * sizeof(uint32_t));
uint32_t *total1 = malloc(16000 * sizeof(uint32_t)); // array to hold the result
while (1) {
do {
nbytes = read(s, &frame, sizeof(struct canfd_frame));
} while (nbytes == 0);
for (x = 0; x < 64;x = x + 2) {
buffer[a] = ((uint32_t) frame.data[x] << 8)
| ((uint32_t) (frame.data[x + 1]));
//buffer[a]=frame.data[x];
a++;
}
i++;
if (i == 250) {
memcpy(total1, buffer, 16000 * sizeof(uint32_t));
//printf("Address = %lu \n",(unsigned long)total1);
flag = 1;
buffer_length = 16000;
i = 0;
a = 0;
}
if (flag == 1) {
while(buffer_length > 0) {
snd_pcm_prepare(handle);
err = snd_pcm_writei(handle, total1, buffer_length);
//printf("Datos = %d\n", err);
snd_pcm_avail_delay(handle, &availp, &delayp);
//printf("available frames =%ld delay = %ld\n",availp,delayp);
if (err == -EAGAIN)
continue;
if (err < 0) {
err = snd_pcm_recover(handle, err, 1);
} else {
ptr += err * channels;
buffer_length -= err;
z++;
}
if (err < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
}
flag = 0;
}
}
}

Bogus TCP Header Length When Examining Packets in Tshark

I was trying to send a TCP SYN packet to a server on my machine on port 8000. Then, I wanted to check if the server responded with a SYN ACK. If this was the case, then I would send back a RST packet to abort the connection. However, when I sniff the SYN packet that I send out it tells me the TCP header has a bogus length of 0, which isn't the case. The sniffer I used was tshark, by the way. Here's my code:
In the main function, I run this:
FLAGS f = SYN;
tcp_scan("127.0.0.1",8000,f,0);
This function assembles the IP header:
struct iphdr* assemble_ip(char* dest,unsigned int proto) {
/* Assemble IP Layer */
struct iphdr* iph;
iph = malloc(sizeof(struct iphdr)); // allocate memory
if (iph == NULL) { // if the ip header is NULL
err();
return NULL;
}
srand((unsigned int)time(NULL)); // seed random number generator
/* Hardcoded values */
iph->version = 4; // the version
iph->tos = 0; // type of services
iph->ihl = 5; // internet header length
iph->id = htons(rand() % 65536); // random id
iph->ttl = rand() % 257; // ttl
iph->frag_off = 0; // fragment offset
if (iph->ttl < 64) iph->ttl += 64; // if TTL is not sufficient
iph->tot_len = htons(iph->ihl*4); // the internet header length
/* User defined values */
iph->saddr = inet_addr(client); // source address
iph->daddr = inet_addr(dest); // destination address
iph->protocol = proto; // protocol
iph->check = 0; // set to zero for later calculation
return iph;
}
This function assembles the TCP header:
struct tcphdr* assemble_tcp(unsigned int sport,unsigned int dport,FLAGS f) {
/* Assemble TCP layer */
struct tcphdr* tcph;
tcph = malloc(sizeof(struct tcphdr)); // allocate tcp header
if (tcph == NULL) { // if tcp is NULL
err();
return NULL;
}
bzero(tcph,sizeof(struct tcphdr));
srand((unsigned int)time(NULL)); // seed random number generator
/* Hardcoded values */
tcph->seq = htonl(rand() % 65001); // generate random sequence number
tcph->ack_seq = 0; // ack sequence should be 0
tcph->doff = 5; // set data offset
tcph->window = htons(rand() % 65536); // set window size
/* Increase values by random value above 64 */
if (ntohs(tcph->seq) < 64) tcph->seq += (rand() % 101 + 64);
if (ntohs(tcph->window) < 64) tcph->window += (rand() % 101 + 64);
/* User-defined values */
tcph->source = htons(sport); // source port
tcph->dest = htons(dport); // destination port
tcph = set_flags(tcph,f); // set the TCP flags
/* Set urgent ptr if URG flag is set*/
if (tcph->urg == 1) tcph->urg_ptr = 1;
else tcph->urg_ptr = 0;
tcph->check = 0; // set the checksum to 0 for other calculations
return tcph;
}
Also, I do compute the checksum of the headers. For my purposes, when calculating the checksum, the IP header is always 20 bytes long, since I'm not sending any data or options. That means that there are 10 16-bit words in the header. The TCP header is also going to be 20 bytes long since I didn't add any options or data. Here's the code:
unsigned short ip_checksum(struct iphdr* iph) {
/* Acquire IP checksum */
/*
Checksum for Internet Protocol:
One's complement of the one's complement sum of the 16 bit words in the header.
So we get the first 16 bits of the header then add it to the sum, and then
we get the next 16 bits, and add it, and so on.
...0100101010110101 -> "..." represents more bits
1111111111111111 -> this is 131071 in base 10
0000100101010110101 -> notice how the "..." bits are now 0's
*/
/* One's complement sum */
unsigned long long* ptr;
unsigned long long hdr;
unsigned short sum = 0;
unsigned long mask = 131071;
ptr = (unsigned long long*)iph; // cast structure
hdr = *ptr; // get hdr
for (int i = 0; i < 10; i++) { // 20 bytes -> 160 bits / 16 bits = 10 words
sum += (hdr & mask); // add to sum
hdr >>= 16; // shift the next 16 bits
}
sum = ~sum; // inverse
return sum;
}
TCP Checksum:
unsigned short tcp_checksum(struct tcphdr* tcph,struct iphdr* iph) {
/* Calculate TCP checksum */
struct pseudo_hdr* pseudo_hdr;
u_char* buffer;
u_char* segment;
u_char* pseudo_segment;
unsigned short sum = 0;
unsigned long mask = 131071;
unsigned long long* ptr;
unsigned long long hdr;
pseudo_hdr = malloc(sizeof(struct pseudo_hdr)); // allocate memory
buffer = malloc(32); // allocate for 32 bytes of information
if (pseudo_hdr == NULL || buffer == NULL) { // if memory wasn't allocated properly
err();
if (pseudo_hdr != NULL) free(pseudo_hdr);
if (buffer != NULL) free(buffer);
return 0;
}
pseudo_hdr->saddr = (unsigned long)iph->saddr; // we add the cast because the fields if of type u_int_32
pseudo_hdr->daddr = (unsigned long)iph->daddr; // same reason for adding the cast as above
memset(&pseudo_hdr->reserved,0,8); // set these 8 bits to 0
pseudo_hdr->proto = IPPROTO_TCP; // this will always be 6
pseudo_hdr->len = htons(tcph->doff*4); // length of tcp header
/* Place both headers into a buffer */
segment = (u_char*)tcph;
pseudo_segment = (u_char*)pseudo_hdr;
/* Concactenate */
strncat((char*)buffer,(char*)pseudo_segment,12); // first the pseudo header
strncat((char*)buffer,(char*)segment,20); // then the TCP segment
/* Calculate checksum just like IP checksum */
ptr = (unsigned long long*)buffer; // convert buffer
hdr = *ptr; // dereference for clarity in following clode
for (int i = 0; i < 16; i++) { // 32 bytes -> 256 bits / 16 bits = 16 words
sum += (hdr & mask); // apply mask to header and add to sum
hdr >>= 16; // shift the next 16 bits
}
sum = ~sum; // bitwise NOT operation
return sum;
};
Here's all of the functions I stated above put together:
int tcp_scan(char* ipaddr,unsigned int port,FLAGS f,unsigned int justsend) {
/* Do a TCP port scan */
u_char* buffer;
u_char recvbuf[65535];
u_char* ipbuf;
u_char* tcpbuf;
int s;
size_t bufsize;
size_t size;
struct sockaddr_in sa;
struct sockaddr_in recvstruct;
struct msghdr msg;
struct iovec iv[1];
struct iphdr* iph;
struct tcphdr* tcph;
FLAGS rst = RST;
srand((unsigned int)time(NULL)); // seed random number generator
bufsize = sizeof(struct tcphdr) + sizeof(struct iphdr); // store size in variable
buffer = malloc(bufsize); // allocate memory to buffer
iph = assemble_ip(ipaddr,IPPROTO_TCP); // set the ip address to provided and protocol as TCP
tcph = assemble_tcp(rand() % 65536,port,f); // set flag, source port as rand, and dest port as supplied port num
if (iph == NULL || tcph == NULL || buffer == NULL) { // if error occurs
err();
/* Deallocate memory to variables that still have it */
if (iph != NULL) free(iph);
if (tcph != NULL) free(tcph);
if (buffer != NULL) free(buffer);
return -1;
}
/* Now compute checksum */
iph->check = htons(ip_checksum(iph));
tcph->check = htons(tcp_checksum(tcph,iph));
/* Store headers in buffer */
ipbuf = (u_char*)iph;
tcpbuf = (u_char*)tcph;
/* Concactenate to buffer */
strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted
strncat((char*)buffer,(char*)ipbuf,20); // do same thing but with ip header
/* Create a socket */
s = create_socket(); // create a raw socket
if (s == -1) return -1; // if the socket wasn't able to be created
/* Clear memory */
bzero(&sa,sizeof(struct sockaddr_in));
bzero(&recvstruct,sizeof(struct sockaddr_in));
bzero(&msg,sizeof(struct msghdr));
bzero(&iv,sizeof(struct iovec));
/* For analyze_packet() */
sa.sin_family = AF_INET; // address family
sa.sin_addr.s_addr = inet_addr(ipaddr); // convert ip address
sa.sin_port = htons(port); // port number
/* For sendmsg() */
iv[0].iov_base = buffer;
iv[0].iov_len = bufsize;
msg.msg_name = &sa; // caller allocated buffer
msg.msg_namelen = sizeof(struct sockaddr_in); // specify size of buffer
msg.msg_iov = iv; // iov structure array
msg.msg_iovlen = 1; // the length of the array
msg.msg_control = NULL; // for ancillary data
msg.msg_controllen = 0; // sizeof ancillary data
if (sendmsg(s,&msg,0) == -1) {
err();
return -1;
}
printf("Sent\n");
if (justsend) return 0; // exit cleanly
bzero(&recvstruct,sizeof(struct sockaddr_in)); // clear structure
size = sizeof(struct sockaddr_in); // acquire size of recv structure
for(int i = 0; i < 100; i++) { // loop until we've received 100 packets
printf("Receiving\n");
bzero(recvbuf,65535); // clear memory
if (recvfrom(s,recvbuf,sizeof(recvbuf),0,(struct sockaddr*)&recvstruct,(socklen_t*)&size) == -1) { // recv
err();
return -1;
}
if (analyze_packet(recvbuf,sa,recvstruct) == 0) { // if packet is what we wanted
printf("\ttcp %d is open\n",port); // print out that port is opened
tcp_scan(ipaddr,port,rst,-1); // abort connection with RST flag
break;
}
}
return 0;
}
Alright, now that you've seen those, here's the 'tshark' command I used to sniff the packets:
sudo tshark -o tcp.check_checksum:TRUE # I also wanted to check the checksum value to make sure it was OK
Now here's the command to run the program:
sudo ./netmap enp0s3 # enp0s3 is the interface I'm sending packets on
After running both of these in separate terminals, tshark provides this output:
1 0.000000 10.0.2.15 -> 127.0.0.1 TCP 74 31280->8000 [<None>] Seq=1 Win=0, bogus TCP header length (0, must be 20)
Please note that the declarations for struct iphdr and struct tcphdr are located in the system header files <netinet/ip.h> and <netinet/tcp.h>, respectively.
I'm really lost as to how to solve this issue. In fact, I'm not certain what is causing the issue, in the first place. According to my knowledge there's no way to specify the length of the TCP header. Any help would be appreciated.
I think your problem is here
strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted
strncat((char*)buffer,(char*)ipbuf,20);
The headers aren't strings so you may only be copying part of each header. Try something like this;
memcpy((char*)buffer, (char*)tcpbuf, 20);
memcpy((char*)buffer+20, (char*)ipbuf, 20);

Serial port ReadFile reads 0 bytes and returns true

I'm trying to read in data from a serial port in Windows 7 using the Windows API. When I try to read in data, the WaitCommEvent() fires just fine and the ReadFile() call returns 1 as the status, but no data is read in. In the the ReadFile documentation it says that:
When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero.
However, I'm sure there are no EOT characters in the data being sent over the serial port.
I currently have two USB cables plugged into my computer and connected to each other. I know that they can send and receive data as I have tested them with Putty.
Why won't ReadFile() read in any data?
My code is below.
Header:
typedef struct uart_handle
{
uint8_t port_num;
char port_name[10];
uint32_t baud_rate;
uint8_t byte_size;
uint8_t stop;
uint8_t parity;
int32_t error;
HANDLE handle;
} uart_handle;
Main file:
uart_handle* serial_comm_init(uint8_t port_num, uint32_t baud_rate, uint8_t byte_size, uint8_t stop, uint8_t parity)
{
uart_handle* uart;
DCB uart_params = { 0 };
COMMTIMEOUTS timeouts = { 0 };
int status;
uart = (uart_handle*) malloc(1 * sizeof(uart_handle));
status = 0;
// Set port name
if (port_num > 9)
{
sprintf(uart->port_name, "\\\\.\\COM%d", port_num);
}
else
{
sprintf(uart->port_name, "COM%d", port_num);
}
// Set baud rate
uart->baud_rate = baud_rate;
// Set byte size
uart->byte_size = byte_size;
// Set stop bit
uart->stop = stop;
// Set parity
uart->parity = parity;
// Set up comm state
uart_params.DCBlength = sizeof(uart_params);
status = GetCommState(uart->handle, &uart_params);
uart_params.BaudRate = uart->baud_rate;
uart_params.ByteSize = uart->byte_size;
uart_params.StopBits = uart->stop;
uart_params.Parity = uart->parity;
SetCommState(uart->handle, &uart_params);
// Setup actual file handle
uart->handle = CreateFile(uart->port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (uart->handle == INVALID_HANDLE_VALUE) {
printf("Error opening serial port %s.\n", uart->port_name);
free(uart);
return NULL;
}
else {
printf("Serial port %s opened successfully.\n", uart->port_name);
}
// Set timeouts
status = GetCommTimeouts(uart->handle, &timeouts);
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
status = SetCommTimeouts(uart->handle, &timeouts);
if (status == 0) {
printf("Error setting comm timeouts: %d", GetLastError());
}
return uart;
}
int32_t serial_comm_read(void* handle, uint8_t* msg, uint32_t msg_size, uint32_t timeout_ms, uint32_t flag)
{
uart_handle* uart;
uint32_t num_bytes_read;
uint32_t event_mask;
int32_t status;
uart = (uart_handle*) handle;
num_bytes_read = 0;
event_mask = 0;
status = 0;
memset(msg, 0, msg_size);
// Register Event
status = SetCommMask(uart->handle, EV_RXCHAR);
// Wait for event
status = WaitCommEvent(uart->handle, &event_mask, NULL);
printf("Recieved characters.\n");
do {
status = ReadFile(uart->handle, msg, msg_size, &num_bytes_read, NULL);
printf("Status: %d\n", status);
printf("Num bytes read: %d\n", num_bytes_read);
printf("Message: %s\n", msg);
} while (num_bytes_read > 0);
printf("Read finished.\n");
return 0;
}
Output:
Serial port COM9 opened successfully.
Recieved characters.
Status: 1
Num bytes read: 0
Message:
Read finished.
The code shown calls GetCommState() on an uninitialised handle:
status = GetCommState(uart->handle, &uart_params);
provoking UB doing so. Its returned status is not tested.
Due to this uart_params probably contains BS no useful data.
Do yourself a favour: Always and ever check the return value on all relevant function calls (and let the code act accordingly)! Consider as "relevant" all those functions returning or changing data used afterwards.

read()/ioctl disturbs GPIO signal?

I connect a Linux embedded board(based on imx233) and a MSP430 MCU. They are connected via 4 pin SPI, but I use a GPIO for the chip select purpose on the Linux board. What I do is to use poll to detect falling edge of the GPIO(nr 52) then perform SPI reading either ioctl or read()
int main(void)
{
/********************************LINUX SCHEDULING**********************************/
sp.sched_priority = sched_get_priority_max(SCHED_FIFO); //scheduling
sched_setscheduler(0, SCHED_FIFO, &sp); //scheduling
/********************************LINUX SCHEDULING_END******************************/
struct pollfd fdset[2]; //declare the poll to be used in interrupt catching
int nfds = 2;
int gpio_fd, timeout, rc;
char *buf[MAX_BUF]; //max=64byte
int len;
initialize(); //gpio's are set to SPI_SLAVE
// spi_init();
gpio_fd = gpio_fd_open(CHIP_SELECT_PIN); //the CS(SS) pin is opened
timeout = POLL_TIMEOUT; //timeout 3 sec is set
// uint8_t voidFirstDetection = 1;
while (1) {
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = NULL;
fdset[0].events = POLLIN;
fdset[1].fd = gpio_fd;
fdset[1].events = POLLPRI;
/*** POLL starts to detect chipselects****/
rc = poll(fdset, nfds, timeout);
if (rc < 0) {
printf("\npoll() failed!\n");
return -1;
}
if (rc == 0) {
printf(".");
}
if (fdset[1].revents & POLLPRI ) { //HERE I need to run SPI_read
len = read(fdset[1].fd, buf, MAX_BUF);
/* if(voidFirstDetection){
voidFirstDetection = 0;
}else{*/
printf("\npoll() GPIO %d interrupt occurred\n", CHIP_SELECT_PIN);
int fd = open(device, O_RDWR);
if (fd < 0){
// snprintf(systemlogmsg, sizeof(systemlogmsg), "[1181]: errno:%s Cannot open /dev/spidev ", strerror(errno));
// error_logging(systemlogmsg, LOGLEVEL_ERROR);
printf("error spi recive\n");
}
//spi_transfer(fd);
do_read(fd);
close(fd);
// }
}
}
gpio_fd_close(gpio_fd);
return 0;
}
Above code works fine that it generates an interrupt only at the falling edge of the signal. I use the either of the below code when the interrupt is detected to read the /dev/spidev1-0
static void do_read(int fd)
{
unsigned char buf[1], *bp;
int status;
int len = 1;
/* read at least 2 bytes, no more than 32 */
memset(buf, 0, sizeof buf);
status = read(fd, buf, len);
if (status < 0) {
perror("read");
return;
}
if (status != len) {
fprintf(stderr, "short read\n");
return;
}
printf("read(%2d, %2d): %02x %02x,", len, status,
buf[0], buf[1]);
status -= 2;
bp = buf + 2;
while (status-- > 0)
printf(" %02x", *bp++);
printf("\n");
}
static void spi_transfer(int fd)
{
int ret;
uint8_t tx[2];
uint8_t rx[3] = {0 };
struct spi_ioc_transfer tr = {
.tx_buf = 0,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1){
printf("can't send spi message");
exit(1);
}
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
Whenever the either ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); line on spi_transfer() or status = read(fd, buf, len); on do_read() is executed, I see an infinite loop that detects an interrupt on the GPIO52 (chipselect). I try the observe the GPIO via oscilloscope but I could not see any signal change (it might be a spike that my oscilloscope cannot detect), however, when I connect the chipselect to the Vcc, it does not get the infinite loop. As I am on the early stage, I set one of GPIO of the MCU as an output and a constant logic high. I use GPIO52 (Chip select) as an input because my aim is to transfer data from MCU to the linux board.
I guess, the read() and ioctl somehow effects the GPIO to sink more current than the GPIO can provide. If it is the problem, what can I do that ioctl or read() would not disturb GPIO. Or do you think something else could be a problem?
I was lucky that I found the problem quick. I tied the grounds of both boards and now it works fine. I will keep the post as someone else might have the same problem. But I am still curious how ioctl or read disturbs the GPIO signal level

Resources