Network Activity Monitoring on iPhone - ios

I've been working for 5 days trying to learn and implement Network monitor on the iPhone.
I looked into netstat code from apple, and i lost like 25% of my hair.
I found links for JB Devices but i need it to execute on a non JB device. (Irrespective of whether Apple accepts it on the App store or not).
I found some useful links :
how to get tcp udp opening port list on iPhone (I couldn't parse the data returned in this question :( )
Data Usage on iPhone
sysctlbyname buf return type (I'm not a networking guy..could not understand this one, may be you guys can help :) )
TCP/UPD port list
I can say i got some thing from the first link. Can you guys help me to Parse the data ?
Is there any other method to achieve this??

Ok, you have all that you need over the table.
You can check the question Is there any private api to monitor network traffic on iPhone?
And here you can find the source code of inet. That code have all you need to parse the data returned of how to get tcp udp opening port list on iPhone
size_t len = 0;
if (sysctlbyname("net.inet.tcp.pcblist_n", 0, &len, 0, 0) < 0) {
perror("sysctlbyname");
} else {
char *buf = malloc(len);
sysctlbyname("net.inet.tcp.pcblist_n", buf, &len, 0, 0);
NSData *data = [NSData dataWithBytesNoCopy:buf length:len];
NSLog(#"data = %#", data);
}
Ok, yes the source code of inet is a little complicate. But, you know that netstat print the net status. So, you only need to see when inet execute printf, at this point you will have the data parsed.
If you try to compile the source of inet for iOS, you will find a lot of problems: some header files are not present in ios sdk. Ok, no problem copy the headers.
For the simulator you only need copy the header of netstat.h. And add some struct declaration that are private:
struct xtcpcb_n {
u_int32_t xt_len;
u_int32_t xt_kind; /* XSO_TCPCB */
u_int64_t t_segq;
int t_dupacks; /* consecutive dup acks recd */
int t_timer[TCPT_NTIMERS_EXT]; /* tcp timers */
int t_state; /* state of this connection */
u_int t_flags;
int t_force; /* 1 if forcing out a byte */
tcp_seq snd_una; /* send unacknowledged */
tcp_seq snd_max; /* highest sequence number sent;
* used to recognize retransmits
*/
tcp_seq snd_nxt; /* send next */
tcp_seq snd_up; /* send urgent pointer */
tcp_seq snd_wl1; /* window update seg seq number */
tcp_seq snd_wl2; /* window update seg ack number */
tcp_seq iss; /* initial send sequence number */
tcp_seq irs; /* initial receive sequence number */
tcp_seq rcv_nxt; /* receive next */
tcp_seq rcv_adv; /* advertised window */
u_int32_t rcv_wnd; /* receive window */
tcp_seq rcv_up; /* receive urgent pointer */
u_int32_t snd_wnd; /* send window */
u_int32_t snd_cwnd; /* congestion-controlled window */
u_int32_t snd_ssthresh; /* snd_cwnd size threshold for
* for slow start exponential to
* linear switch
*/
u_int t_maxopd; /* mss plus options */
u_int32_t t_rcvtime; /* time at which a packet was received */
u_int32_t t_starttime; /* time connection was established */
int t_rtttime; /* round trip time */
tcp_seq t_rtseq; /* sequence number being timed */
int t_rxtcur; /* current retransmit value (ticks) */
u_int t_maxseg; /* maximum segment size */
int t_srtt; /* smoothed round-trip time */
int t_rttvar; /* variance in round-trip time */
int t_rxtshift; /* log(2) of rexmt exp. backoff */
u_int t_rttmin; /* minimum rtt allowed */
u_int32_t t_rttupdated; /* number of times rtt sampled */
u_int32_t max_sndwnd; /* largest window peer has offered */
int t_softerror; /* possible error not yet reported */
/* out-of-band data */
char t_oobflags; /* have some */
char t_iobc; /* input character */
/* RFC 1323 variables */
u_char snd_scale; /* window scaling for send window */
u_char rcv_scale; /* window scaling for recv window */
u_char request_r_scale; /* pending window scaling */
u_char requested_s_scale;
u_int32_t ts_recent; /* timestamp echo data */
u_int32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
/* RFC 1644 variables */
tcp_cc cc_send; /* send connection count */
tcp_cc cc_recv; /* receive connection count */
tcp_seq snd_recover; /* for use in fast recovery */
/* experimental */
u_int32_t snd_cwnd_prev; /* cwnd prior to retransmit */
u_int32_t snd_ssthresh_prev; /* ssthresh prior to retransmit */
u_int32_t t_badrxtwin; /* window for retransmit recovery */
};
struct xinpcb_n {
u_int32_t xi_len; /* length of this structure */
u_int32_t xi_kind; /* XSO_INPCB */
u_int64_t xi_inpp;
u_short inp_fport; /* foreign port */
u_short inp_lport; /* local port */
u_int64_t inp_ppcb; /* pointer to per-protocol pcb */
inp_gen_t inp_gencnt; /* generation count of this instance */
int inp_flags; /* generic IP/datagram flags */
u_int32_t inp_flow;
u_char inp_vflag;
u_char inp_ip_ttl; /* time to live */
u_char inp_ip_p; /* protocol */
union { /* foreign host table entry */
struct in_addr_4in6 inp46_foreign;
struct in6_addr inp6_foreign;
} inp_dependfaddr;
union { /* local host table entry */
struct in_addr_4in6 inp46_local;
struct in6_addr inp6_local;
} inp_dependladdr;
struct {
u_char inp4_ip_tos; /* type of service */
} inp_depend4;
struct {
u_int8_t inp6_hlim;
int inp6_cksum;
u_short inp6_ifindex;
short inp6_hops;
} inp_depend6;
u_int32_t inp_flowhash;
};
#define SO_TC_STATS_MAX 4
struct data_stats {
u_int64_t rxpackets;
u_int64_t rxbytes;
u_int64_t txpackets;
u_int64_t txbytes;
};
struct xgen_n {
u_int32_t xgn_len; /* length of this structure */
u_int32_t xgn_kind; /* number of PCBs at this time */
};
#define XSO_SOCKET 0x001
#define XSO_RCVBUF 0x002
#define XSO_SNDBUF 0x004
#define XSO_STATS 0x008
#define XSO_INPCB 0x010
#define XSO_TCPCB 0x020
struct xsocket_n {
u_int32_t xso_len; /* length of this structure */
u_int32_t xso_kind; /* XSO_SOCKET */
u_int64_t xso_so; /* makes a convenient handle */
short so_type;
u_int32_t so_options;
short so_linger;
short so_state;
u_int64_t so_pcb; /* another convenient handle */
int xso_protocol;
int xso_family;
short so_qlen;
short so_incqlen;
short so_qlimit;
short so_timeo;
u_short so_error;
pid_t so_pgid;
u_int32_t so_oobmark;
uid_t so_uid; /* XXX */
};
struct xsockbuf_n {
u_int32_t xsb_len; /* length of this structure */
u_int32_t xsb_kind; /* XSO_RCVBUF or XSO_SNDBUF */
u_int32_t sb_cc;
u_int32_t sb_hiwat;
u_int32_t sb_mbcnt;
u_int32_t sb_mbmax;
int32_t sb_lowat;
short sb_flags;
short sb_timeo;
};
struct xsockstat_n {
u_int32_t xst_len; /* length of this structure */
u_int32_t xst_kind; /* XSO_STATS */
struct data_stats xst_tc_stats[SO_TC_STATS_MAX];
};
But for the Device you need to copy some other headers of the kernel, I don't know why the headers aren't in the device sdk (maybe if you use them Apple will not approve your app, I don't know, but that doesn't matter).
You can copy the missing headers from the simulator SDK to your project. Or you can change the header path to the simulator SDK. (I copied the headers).
If you copy the headers you will need change some include declaration.
You don't need all the inet.c code. You only need these functions:
protopr
inetprint
inetname
Then inside those functions you will see the printf with the data parsed, you can add that in a dictionary.
Here is my code. You can see a class named: DHInet with two method that return a NSArray with a list of NSDictionary with the information of the connections.
I hope you find it useful, and if anyone wants to give me a hand in improving the code, so be it, I need to clean the code, because it has a lot of ifdef that are not necessary.

Related

I can't receive from ESP8266

I am using ESP8266 with STM32F103. The ESP receives the AT-command correctly and executes it, and I can receive the echo characters, but when it comes to the ESP response I can't receive anything.
Here is a pic to demonstrate the issue:
https://drive.google.com/file/d/19Of8ENNDDB0YAV5H5HuamcWF_OwV8JSj/view?usp=sharing
For instance: I send ATE0 to stop the echo, the ESP executes the command and there is no echo anymore, but I can't receive "OK" or "WIFI CONNECTED" or any other response.
I have tried putty and it worked without any problems in sending or receiving, so the ESP is fine.
I am using 115200 Baud rate, and this is my code:
main:
void main(void)
{
/* Init RCC */
RCC_voidInitSysClock();
/* Enable Clock For GPIOA & UART1 */
RCC_voidEnableClock(RCC_APB2,GPIOA_BUS);
RCC_voidEnableClock(RCC_APB2,14);
/* Set TX and Rx Directions */
MGPIO_voidSetPinDirection(GPIOA, PIN9 ,OUTPUT_SPEED_2MHZ_AFPP); /* TX */
MGPIO_voidSetPinDirection(GPIOA, PIN10 ,INPUT_FLOATING); /* RX */
/* Set Direction For Pin 0 To power Led */
MGPIO_voidSetPinDirection(GPIOA, PIN0 ,OUTPUT_SPEED_10MHZ_PP);
/* Enable UART1 Interrupt */
MNVIC_voidEnableInterrupt(USART1_ID);
/* Init UART1 */
MUART_voidInit();
/* Init ESP */
HESP_voidInit();
/* Connect To WIFI Network */
HESP_voidConnecttoWifi("Androidap","111112222");
//HESP_voidConnectToServerTCP("162.253.155.226","80");
//HESP_u8ReceiveResponse("Abdullaharm.freevar.com/status.txt","47");
while(1)
{
}
}
Implementation of ESP_init and connect to WIFI functions:
void HESP_voidInit(void)
{
//MUART_voidTransmitSynch("AT\r\n");
/* Stop Echo */
MUART_voidTransmitSynch("ATE0\r\n");
/* Set Station Mode */
MUART_voidTransmitSynch("AT+CWMODE=1\r\n");
MSYSTICK_voidSetBusyWait(1000);//microseconds
}
void HESP_voidConnecttoWifi(uint8* Copy_u8SSID , uint8* Copy_u8Pass)
{
/* Connect to WIFI network */
MUART_voidTransmitSynch("AT+CWJAP_CUR=\"");
MUART_voidTransmitSynch(Copy_u8SSID);
MUART_voidTransmitSynch("\",\"");
MUART_voidTransmitSynch(Copy_u8Pass);
MUART_voidTransmitSynch("\"\r\n");
}
Implementaion of UART_TransmitSynch:
void MUART_voidTransmitSynch(uint8 arr[])
{
uint8 i=0;
while(arr[i] != '\0')
{
UART1 -> DR = arr[i];
/* wait till transmission is complete */
while (!(UART1->SR & (1<<6)));
i++;
MSYSTICK_voidSetBusyWait(2000); //microseconds
}
}
I am using interrupt to receive from the ESP and this is the code inside ISR:
void USART1_IRQHandler(void)
{
if(GET_BIT(UART1 -> SR , 5))
{
static uint8 Data_Counter=0;
if(UART1 -> DR !='\0')
{
Data_Received_int[Data_Counter]=UART1 -> DR;
Data_Counter++;
}
else
{
Data_Counter=0;
}
CLR_BIT(UART1 -> SR , 5);
}
//UART_CallBackPtr();
}

Initializing LwIP causes RTOS to stop working

Good day
The goal:
I am trying to configure FreeRTOS and LwIP so that I can set up MQTT.
I am using a STM32-NucleoF429ZI development board
What I have done:
I am using CubeMX to generate project files and I am using Visual Studio and VisualGDB for compiling and debugging.
I have set up FreeRTOS for the dev board using CMSIS_V2 and Heap_4.
I have set up LwIP with: Static IP and MEM_SIZE of 1024*10
I have kept all standard pinout (i.e. I have note cleared pinouts) of nucleo board
Ive set up an "Ethernet" thread and I am blinking and LED on the ethernet thread and the default thread.
Other than that no other setting has been changed. I did not set the MPU because as far as I can tell, this MCU does not have it.
The problem:
If I comment out the line MX_LWIP_Init();, (which cubeMX puts into the default thread), then the board runs fine and both LED's on both threads blink forever as far as I have tested. However, as soon as I leave MX_LWIP_Init();, FreeRTOS gets stuck as shown in the picture.
This occurs anywhere from 30 seconds to many minutes after powering the board
Please excuse the picture, but it shows where exactly the program is when I pause it. If I resume the debugger and pause it again, it always pauses in the same place.
I have tried moving MX_LWIP_Init(); into main.c with the other init functions and also into the ethernet thread where it should belong. All produce the same error at some point.
I can ping the board once I add MX_LWIP_Init();
freertos.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* #attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "config.h"
#include "EthernetLwIP_thread.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
extern void MX_LWIP_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* #brief FreeRTOS initialization
* #param None
* #retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
if (EthernetModule_Init() == Result_Successful)
{
logger("template module successfully initialized!!!");
}
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* #brief Function implementing the defaultTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* init code for LWIP */
//MX_LWIP_Init();
/* USER CODE BEGIN StartDefaultTask */
// Task timing
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
const TickType_t xDelay_Ticks = 1000; // Current RTOS clock config has 1 tick equal 1ms. Thus 20 ticks sets a frequency of 50Hz
/* Infinite loop */
while (1)
{
vTaskDelayUntil(&xLastWakeTime, xDelay_Ticks); // waits until a certain number of ticks have passed before it starts this task again in a timely manner
HAL_GPIO_TogglePin(LED_BLUE_PORT, LED_BLUE_PIN);
//HAL_GPIO_TogglePin(LED_RED_PORT, LED_RED_PIN);
//HAL_GPIO_TogglePin(LED_GREEN_PORT, LED_GREEN_PIN);
}
/* USER CODE END StartDefaultTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
Ethernet src file
/* Ethernet_thread.c */
// Includes: ----------------------------------------------------------
#include "EthernetLwIP_thread.h"
#include "config.h"
// Instantiations: ----------------------------------------------------
// Thread declaration: ------------------------------------------------
osThreadId_t EthernetModule_ThreadId;
const osThreadAttr_t EthernetModule_Attributes = {
.name = "EthernetModule",
.priority = (osPriority_t) osPriorityHigh,
.stack_size = 1024 * 4 // This needs to be optimized at a later stage
};
void EthernetModule_Thread(void *argument);
// Functions: --------------------------------------------------------
// Initializing functions: ---------------------------------------------------------------------
MResult EthernetModule_HardwareInit()
{
return Result_Successful;
}
MResult EthernetModule_Init() {
MX_LWIP_Init();
if (EthernetModule_HardwareInit() == Result_Error)
return Result_Error;
EthernetModule_ThreadId = osThreadNew(EthernetModule_Thread, NULL, &EthernetModule_Attributes);
if (EthernetModule_ThreadId == NULL)
return Result_Error;
return Result_Successful;
}
// Thread: ---------------------------------------------------------------------------------------
void EthernetModule_Thread(void *argument)
{
// Task timing
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
const TickType_t xDelay_Ticks = 500;
while (1)
{
vTaskDelayUntil(&xLastWakeTime, xDelay_Ticks);
HAL_GPIO_TogglePin(LED_GREEN_PORT, LED_GREEN_PIN);
}
}
I am not sure the cause of this problem, but I have changed from FreeRTOS CMSIS_V2 to CMSIS_V1 and it resolved the issue. I dont know if there is a configuration in CMSIS_V2 that was wrong, or if there is an actual bug, but CMSIS_V1 and LwIP works great now.

GRUB memory map gives me weird values

I am trying to use grub in order to get the memory map, instead of going through the bios route. The problem is that grub seems to be giving me very weird values for some reason. Can anyone help with this?
Relevant code:
This is how I parse the mmap
void mm_init(mmap_entry_t *mmap_addr, uint32_t length)
{
mmap = mmap_addr;
/* Loop through mmap */
printk("-- Scanning memory map --");
for (size_t i = 0; mmap < (mmap_addr + length); i++) {
/* RAM is available! */
if (mmap->type == 1) {
uint64_t starting_addr = (((uint64_t) mmap->base_addr_high) << 32) | ((uint64_t) mmap->base_addr_low);
uint64_t length = (((uint64_t) mmap->length_high) << 32) | ((uint64_t) mmap->length_low);
printk("Found segment starting from 0x%x, with a length of %i", starting_addr, length);
}
/* Next entry */
mmap = (mmap_entry_t *) ((uint32_t) mmap + mmap->size + sizeof(mmap->size));
}
}
This is my mmap_entry_t struct (not the one in multiboot.h):
struct mmap_entry {
uint32_t size;
uint32_t base_addr_low, base_addr_high;
uint32_t length_low, length_high;
uint8_t type;
} __attribute__((packed));
typedef struct mmap_entry mmap_entry_t;
And this is how I call mm_init()
/* Kernel main function */
void kmain(multiboot_info_t *info)
{
/* Check if grub can give us a memory map */
/* TODO: Detect manually */
if (!(info->flags & (1<<6))) {
panic("couldn't get memory map!");
}
/* Init mm */
mm_init((mmap_entry_t *) info->mmap_addr, info->mmap_length);
for(;;);
}
This is the output I get on qemu:
-- Scanning memory map --
Found segment starting from 0x0, with a length of 0
Found segment starting from 0x100000, with a length of 0
And yes, I am pushing eax and ebx before calling kmain. Any ideas on what is going wrong here?
It turns out that the bit masking stuff was the problem. If we drop that, we can still have 32-bit addresses and the memory map works just fine.

I have a problem reading ADC with DMA on STM32 F767zi. When I look into the buffer, all I see are zeros, and I do not know why?

The size of my buffer is 4096 and I want to fill the buffer with the adc values that are read.
#define ADC_BUF_LEN 4096
uint16_t adc_buf[ADC_BUF_LEN];
I am using this function to start the reading process of the ADC using DMA
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc_buf, ADC_BUF_LEN);
Here are my configurations for the ADC
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV6;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
This my DMA configuration
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
These are my interrupt functions. I set a toggle breakpoint on the first interrupt and when I debug, the LED does not turn on which suggests that the DMA isn't working?
/* USER CODE BEGIN 4 */
//Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
//HAL_ADC_GetValue(&hadc2);
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}
//Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}
I set the prescaled to be divided by 6 if this information helps.
Please give me some advice!
Thank you in advance.

why use cpu_to_le32 for the DMA address but not for length? (in an example code in a book)

I was reading the book Essential Linux Device Driver (by Sreekrishnan Venkateswaran) and in Chapter 10 Listing 10.5. Setting Up DMA Descriptors and Buffers, I see
/* Device-specific data structure for the Ethernet Function */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the receive descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the receive descriptor */
void *dma_buffer_tx; /* Kernel virtual address of the transmit descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit descriptor */
/* ... */
spin_lock_t device_lock; /* Serialize */
} *mydev_data;
/* On-card registers related to DMA */
#define DMA_RX_REGISTER_OFFSET 0x0 /* Offset of the register holding the bus address of the RX descriptor */
#define DMA_TX_REGISTER_OFFSET 0x4 /* Offset of the register holding the bus address of the TX descriptor */
#define CONTROL_REGISTER 0x8 /* Offset of the control register */
/* Control Register Defines */
#define INITIATE_XMIT 0x1
/* Descriptor control word definitions */
#define FREE_FLAG 0x1 /* Free Descriptor */
#define INTERRUPT_FLAG 0x2 /* Assert interrupt after DMA */
/* Invoked from Listing 10.3 */
static void dma_descriptor_setup(struct pci_dev *pdev)
{
/* Allocate receive DMA descriptors and buffers */
mydev_data->dma_buffer_rx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_rx);
/* Fill the two receive descriptors as shown in Figure 10.2 */
/* RX descriptor 1 */
mydev_data->dma_buffer_rx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 24)); /* Buffer address */
mydev_data->dma_buffer_rx[1] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[2] = FREE_FLAG; /* Descriptor is free */
/* RX descriptor 2 */
mydev_data->dma_buffer_rx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 1560)); /* Buffer address */
mydev_data->dma_buffer_rx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[5] = FREE_FLAG; /* Descriptor is free */
wmb(); /* Write Memory Barrier */
/* Write the address of the receive descriptor to the appropriate register in the card. The I/O base address, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_rx), ioaddr + DMA_RX_REGISTER_OFFSET);
/* Allocate transmit DMA descriptors and buffers */
mydev_data->dma_buffer_tx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_tx);
/* Fill the two transmit descriptors as shown in Figure 10.2 */
/* TX descriptor 1 */
mydev_data->dma_buffer_tx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 24)); /* Buffer address */ <---- line A
mydev_data->dma_buffer_tx[1] = 1536; /* Buffer length */ <---- line B
/* Valid descriptor. Generate an interrupt after completing the DMA */
mydev_data->dma_buffer_tx[2] = (FREE_FLAG | INTERRUPT_FLAG);
/* TX descriptor 2 */
mydev_data->dma_buffer_tx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 1560)); /* Buffer address */
mydev_data->dma_buffer_tx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_tx[5] = (FREE_FLAG | INTERRUPT_FLAG);
wmb(); /* Write Memory Barrier */
/* Write the address of the transmit descriptor to the appropriate register in the card. The I/O base, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_tx), ioaddr + DMA_TX_REGISTER_OFFSET);
}
/* Invoked from Listing 10.3 */
static void dma_descriptor_release(struct pci_dev *pdev)
{
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_tx);
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_rx);
}
In the code, the driver prepares a buffer for the DMA descriptors and DMA buffers using pci_alloc_consistent() and sets them up and passes the buffer address (bus address) to the hardware making sure it's in little endian format using cpu_to_le32(). So I understood the H/W sees the buffer descriptor. But in the descriptor, why did it use cpu_to_le32() for the descriptor address (line A above) and not for the following buffer length (line B above)? Does the H/W see only the buffer address and not the size? Or is it an error in the book? By the way, this is for a fictitious PCI ethernet chip driver.
In practice such approach indeed looks like a mistake. But theoretically it's possible that one field (address) is always little endian no matter what, while another (length) is in native mode. Nowadays, with help of FPGA, I guess one even may try to implement this theoretical case.
So, in the given context, especially taking into consideration your remark that this is for a fictitious PCI ethernet chip, it is a bit hard to say what was author's intention here.

Resources