Why does the Linux kernel have `struct sock` and `struct socket`? - sockets

This questions was asked before on the Internet, but I couldn't find a good answer.
The Linux kernel networking stack features two structures:
struct socket, generally stored in a variable sock
struct sock, generally stored in a variable sk
The two structures are essentially linked, but seem to have slightly different lifetimes. One can find an sk via sock->sk, or find a sock via sk->sk_socket.
Why are there two structures to store information about sockets? Assuming I need to add a new field, when would I add it to struct socket and when to struct sock?
UPDATE: Please note that I refer to struct socket in include/linux/net.h inside the Linux source code, which is meant for kernel code only, and not /usr/include/sys/socket.h which is meant for userland.

struct socket seems to be a higher level interface that is used for system calls (that is why it also has pointer to struct file which represents file descriptor here).
struct sock is a in-kernel implemenation for AF_INET sockets (there is also struct unix_sock for AF_UNIX sockets which is derivative of this) which can be used both by kernel and by userspace (via struct sock).
Both were added to Linux 1.0 back in 1993, I doubt you'll find a doc specifying initial design decision.

“The two structures are essentially linked” - not sure what you meant.
I guess you could find answer if look at source files for these structures:
socket -> linux-src/include/linux/net.h
sock -> linux-src/include/net/sock.h
socket
* NET An implementation of the SOCKET network access protocol.
* This is the master header file for the Linux NET layer,
* or, in plain English: the networking handling part of the
* kernel.
sock
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
These structures are different and has different representation of socket abstraction.
Here answer about different sockets.
Unix vs BSD vs TCP vs Internet sockets?
Where to define additional field depends on your intention. Please describe your task.
Please look at sources.
linux-src/include/linux/net.h
/*
* NET An implementation of the SOCKET network access protocol.
* This is the master header file for the Linux NET layer,
* or, in plain English: the networking handling part of the
* kernel.
*
* Version: #(#)net.h 1.0.3 05/25/93
*
* Authors: Orest Zborowski, <obz#Kodak.COM>
* Ross Biro
* Fred N. van Kempen, <waltje#uWalt.NL.Mugnet.ORG>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
.....
.....
.....
/**
* struct socket - general BSD socket
* #state: socket state (%SS_CONNECTED, etc)
* #type: socket type (%SOCK_STREAM, etc)
* #flags: socket flags (%SOCK_NOSPACE, etc)
* #ops: protocol specific socket operations
* #file: File back pointer for gc
* #sk: internal networking protocol agnostic socket representation
* #wq: wait queue for several uses
*/
struct socket {
socket_state state;
kmemcheck_bitfield_begin(type);
short type;
kmemcheck_bitfield_end(type);
unsigned long flags;
struct socket_wq __rcu *wq;
struct file *file;
struct sock *sk;
const struct proto_ops *ops;
};
linux-src/include/net/sock.h
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Definitions for the AF_INET socket handler.
*
* Version: #(#)sock.h 1.0.4 05/13/93
*
* Authors: Ross Biro
* Fred N. van Kempen, <waltje#uWalt.NL.Mugnet.ORG>
* Corey Minyard <wf-rch!minyard#relay.EU.net>
* Florian La Roche <flla#stud.uni-sb.de>
*
* Fixes:
* Alan Cox : Volatiles in skbuff pointers. See
* skbuff comments. May be overdone,
* better to prove they can be removed
* than the reverse.
* Alan Cox : Added a zapped field for tcp to note
* a socket is reset and must stay shut up
* Alan Cox : New fields for options
* Pauline Middelink : identd support
* Alan Cox : Eliminate low level recv/recvfrom
* David S. Miller : New socket lookup architecture.
* Steve Whitehouse: Default routines for sock_ops
* Arnaldo C. Melo : removed net_pinfo, tp_pinfo and made
* protinfo be just a void pointer, as the
* protocol specific parts were moved to
* respective headers and ipv4/v6, etc now
* use private slabcaches for its socks
* Pedro Hortas : New flags field for socket options
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
....
....
....
/**
* struct sock - network layer representation of sockets
* #__sk_common: shared layout with inet_timewait_sock
* #sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
* #sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings
* #sk_lock: synchronizer
* #sk_kern_sock: True if sock is using kernel lock classes
* #sk_rcvbuf: size of receive buffer in bytes
* #sk_wq: sock wait queue and async head
* #sk_rx_dst: receive input route used by early demux
* #sk_dst_cache: destination cache
* #sk_dst_pending_confirm: need to confirm neighbour
* #sk_policy: flow policy
* #sk_receive_queue: incoming packets
* #sk_wmem_alloc: transmit queue bytes committed
* #sk_tsq_flags: TCP Small Queues flags
* #sk_write_queue: Packet sending queue
* #sk_omem_alloc: "o" is "option" or "other"
* #sk_wmem_queued: persistent queue size
* #sk_forward_alloc: space allocated forward
* #sk_napi_id: id of the last napi context to receive data for sk
* #sk_ll_usec: usecs to busypoll when there is no data
* #sk_allocation: allocation mode
* #sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler)
* #sk_pacing_status: Pacing status (requested, handled by sch_fq)
* #sk_max_pacing_rate: Maximum pacing rate (%SO_MAX_PACING_RATE)
* #sk_sndbuf: size of send buffer in bytes
* #__sk_flags_offset: empty field used to determine location of bitfield
* #sk_padding: unused element for alignment
* #sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets
* #sk_no_check_rx: allow zero checksum in RX packets
* #sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
* #sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
* #sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
* #sk_gso_max_size: Maximum GSO segment size to build
* #sk_gso_max_segs: Maximum number of GSO segments
* #sk_lingertime: %SO_LINGER l_linger setting
* #sk_backlog: always used with the per-socket spinlock held
* #sk_callback_lock: used with the callbacks in the end of this struct
* #sk_error_queue: rarely used
* #sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt,
* IPV6_ADDRFORM for instance)
* #sk_err: last error
* #sk_err_soft: errors that don't cause failure but are the cause of a
* persistent failure not just 'timed out'
* #sk_drops: raw/udp drops counter
* #sk_ack_backlog: current listen backlog
* #sk_max_ack_backlog: listen backlog set in listen()
* #sk_uid: user id of owner
* #sk_priority: %SO_PRIORITY setting
* #sk_type: socket type (%SOCK_STREAM, etc)
* #sk_protocol: which protocol this socket belongs in this network family
* #sk_peer_pid: &struct pid for this socket's peer
* #sk_peer_cred: %SO_PEERCRED setting
* #sk_rcvlowat: %SO_RCVLOWAT setting
* #sk_rcvtimeo: %SO_RCVTIMEO setting
* #sk_sndtimeo: %SO_SNDTIMEO setting
* #sk_txhash: computed flow hash for use on transmit
* #sk_filter: socket filtering instructions
* #sk_timer: sock cleanup timer
* #sk_stamp: time stamp of last packet received
* #sk_tsflags: SO_TIMESTAMPING socket options
* #sk_tskey: counter to disambiguate concurrent tstamp requests
* #sk_zckey: counter to order MSG_ZEROCOPY notifications
* #sk_socket: Identd and reporting IO signals
* #sk_user_data: RPC layer private data
* #sk_frag: cached page frag
* #sk_peek_off: current peek_offset value
* #sk_send_head: front of stuff to transmit
* #sk_security: used by security modules
* #sk_mark: generic packet mark
* #sk_cgrp_data: cgroup data for this cgroup
* #sk_memcg: this socket's memory cgroup association
* #sk_write_pending: a write to stream socket waits to start
* #sk_state_change: callback to indicate change in the state of the sock
* #sk_data_ready: callback to indicate there is data to be processed
* #sk_write_space: callback to indicate there is bf sending space available
* #sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE)
* #sk_backlog_rcv: callback to process the backlog
* #sk_destruct: called at sock freeing time, i.e. when all refcnt == 0
* #sk_reuseport_cb: reuseport group container
* #sk_rcu: used during RCU grace period
*/
struct sock {
/*
* Now struct inet_timewait_sock also uses sock_common, so please just
* don't add nothing before this first member (__sk_common) --acme
*/
struct sock_common __sk_common;
#define sk_node __sk_common.skc_node
#define sk_nulls_node __sk_common.skc_nulls_node
#define sk_refcnt __sk_common.skc_refcnt
#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping
#define sk_dontcopy_begin __sk_common.skc_dontcopy_begin
#define sk_dontcopy_end __sk_common.skc_dontcopy_end
#define sk_hash __sk_common.skc_hash
#define sk_portpair __sk_common.skc_portpair
#define sk_num __sk_common.skc_num
#define sk_dport __sk_common.skc_dport
#define sk_addrpair __sk_common.skc_addrpair
#define sk_daddr __sk_common.skc_daddr
#define sk_rcv_saddr __sk_common.skc_rcv_saddr
#define sk_family __sk_common.skc_family
#define sk_state __sk_common.skc_state
#define sk_reuse __sk_common.skc_reuse
#define sk_reuseport __sk_common.skc_reuseport
#define sk_ipv6only __sk_common.skc_ipv6only
#define sk_net_refcnt __sk_common.skc_net_refcnt
#define sk_bound_dev_if __sk_common.skc_bound_dev_if
#define sk_bind_node __sk_common.skc_bind_node
#define sk_prot __sk_common.skc_prot
#define sk_net __sk_common.skc_net
#define sk_v6_daddr __sk_common.skc_v6_daddr
#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
#define sk_cookie __sk_common.skc_cookie
#define sk_incoming_cpu __sk_common.skc_incoming_cpu
#define sk_flags __sk_common.skc_flags
#define sk_rxhash __sk_common.skc_rxhash
socket_lock_t sk_lock;
atomic_t sk_drops;
int sk_rcvlowat;
struct sk_buff_head sk_error_queue;
struct sk_buff_head sk_receive_queue;
/*
* The backlog queue is special, it is always used with
* the per-socket spinlock held and requires low latency
* access. Therefore we special case it's implementation.
* Note : rmem_alloc is in this structure to fill a hole
* on 64bit arches, not because its logically part of
* backlog.
*/
struct {
atomic_t rmem_alloc;
int len;
struct sk_buff *head;
struct sk_buff *tail;
} sk_backlog;
#define sk_rmem_alloc sk_backlog.rmem_alloc
int sk_forward_alloc;
#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int sk_ll_usec;
/* ===== mostly read cache line ===== */
unsigned int sk_napi_id;
#endif
int sk_rcvbuf;
struct sk_filter __rcu *sk_filter;
union {
struct socket_wq __rcu *sk_wq;
struct socket_wq *sk_wq_raw;
};
#ifdef CONFIG_XFRM
struct xfrm_policy __rcu *sk_policy[2];
#endif
struct dst_entry *sk_rx_dst;
struct dst_entry __rcu *sk_dst_cache;
atomic_t sk_omem_alloc;
int sk_sndbuf;
/* ===== cache line for TX ===== */
int sk_wmem_queued;
refcount_t sk_wmem_alloc;
unsigned long sk_tsq_flags;
struct sk_buff *sk_send_head;
struct sk_buff_head sk_write_queue;
__s32 sk_peek_off;
int sk_write_pending;
__u32 sk_dst_pending_confirm;
u32 sk_pacing_status; /* see enum sk_pacing */
long sk_sndtimeo;
struct timer_list sk_timer;
__u32 sk_priority;
__u32 sk_mark;
u32 sk_pacing_rate; /* bytes per second */
u32 sk_max_pacing_rate;
struct page_frag sk_frag;
netdev_features_t sk_route_caps;
netdev_features_t sk_route_nocaps;
int sk_gso_type;
unsigned int sk_gso_max_size;
gfp_t sk_allocation;
__u32 sk_txhash;
/*
* Because of non atomicity rules, all
* changes are protected by socket lock.
*/
unsigned int __sk_flags_offset[0];
#ifdef __BIG_ENDIAN_BITFIELD
#define SK_FL_PROTO_SHIFT 16
#define SK_FL_PROTO_MASK 0x00ff0000
#define SK_FL_TYPE_SHIFT 0
#define SK_FL_TYPE_MASK 0x0000ffff
#else
#define SK_FL_PROTO_SHIFT 8
#define SK_FL_PROTO_MASK 0x0000ff00
#define SK_FL_TYPE_SHIFT 16
#define SK_FL_TYPE_MASK 0xffff0000
#endif
kmemcheck_bitfield_begin(flags);
unsigned int sk_padding : 1,
sk_kern_sock : 1,
sk_no_check_tx : 1,
sk_no_check_rx : 1,
sk_userlocks : 4,
sk_protocol : 8,
sk_type : 16;
#define SK_PROTOCOL_MAX U8_MAX
kmemcheck_bitfield_end(flags);
u16 sk_gso_max_segs;
unsigned long sk_lingertime;
struct proto *sk_prot_creator;
rwlock_t sk_callback_lock;
int sk_err,
sk_err_soft;
u32 sk_ack_backlog;
u32 sk_max_ack_backlog;
kuid_t sk_uid;
struct pid *sk_peer_pid;
const struct cred *sk_peer_cred;
long sk_rcvtimeo;
ktime_t sk_stamp;
u16 sk_tsflags;
u8 sk_shutdown;
u32 sk_tskey;
atomic_t sk_zckey;
struct socket *sk_socket;
void *sk_user_data;
#ifdef CONFIG_SECURITY
void *sk_security;
#endif
struct sock_cgroup_data sk_cgrp_data;
struct mem_cgroup *sk_memcg;
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk);
void (*sk_write_space)(struct sock *sk);
void (*sk_error_report)(struct sock *sk);
int (*sk_backlog_rcv)(struct sock *sk,
struct sk_buff *skb);
void (*sk_destruct)(struct sock *sk);
struct sock_reuseport __rcu *sk_reuseport_cb;
struct rcu_head sk_rcu;
};

Related

elf.h: No such file or directory when using the x86_64-w64-mingw32-gcc cross-compiler

I have been told by many developers to use a cross-compiler to compile my Operating System.
The issue is when I switched from using gcc to using x86_64-w64-mingw32-gcc, it gave me the error in the title of this post.
I am on Windows using WSL, and I checked /usr/include to see if elf.h was there, and it was. So I tried including that directory when compiling using -I/usr/include and it still did not work.
PS: I am trying to call my __main function inside kernel.cpp, and I need elf.h to get the header entry (unless there is a way to do it without elf.h that I don't know about).
Full Bootloader Makefile:
all:
x86_64-w64-mingw32-gcc -Ignu-efi/inc -Ignu-efi/inc/x86_64 -Ignu-efi/inc/protocol -c -o build/main.o c/main.c
x86_64-w64-mingw32-gcc -Ignu-efi/inc -Ignu-efi/inc/x86_64 -Ignu-efi/inc/protocol -c -o build/data.o gnu-efi/lib/data.c
x86_64-w64-mingw32-gcc -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -o essentials/main.efi build/main.o build/data.o
I am using UEFI Bare Bones (GNU-EFI Headers only).
Is there a way to stop the error, or is there an alternative to using elf.h?
Thanks for your help!
I fixed this issue by adding the structs manually to my main.c file:
typedef uint64_t Elf64_Addr;
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define EI_CLASS 4 /* File class byte index */
#define ELFCLASS64 2 /* 64-bit objects */
#define EI_DATA 5 /* Data encoding byte index */
#define ELFDATA2LSB 1 /* 2's complement, little endian */
#define ET_EXEC 2 /* Executable file */
#define PT_LOAD 1 /* Loadable program segment */
#ifdef __x86_64__
#define EM_MACH 62 /* AMD x86-64 architecture */
#endif
#ifdef __aarch64__
#define EM_MACH 183 /* ARM aarch64 architecture */
#endif
typedef struct
{
uint8_t e_ident[16]; /* Magic number and other info */
uint16_t e_type; /* Object file type */
uint16_t e_machine; /* Architecture */
uint32_t e_version; /* Object file version */
uint64_t e_entry; /* Entry point virtual address */
uint64_t e_phoff; /* Program header table file offset */
uint64_t e_shoff; /* Section header table file offset */
uint32_t e_flags; /* Processor-specific flags */
uint16_t e_ehsize; /* ELF header size in bytes */
uint16_t e_phentsize; /* Program header table entry size */
uint16_t e_phnum; /* Program header table entry count */
uint16_t e_shentsize; /* Section header table entry size */
uint16_t e_shnum; /* Section header table entry count */
uint16_t e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
typedef struct
{
uint32_t p_type; /* Segment type */
uint32_t p_flags; /* Segment flags */
uint64_t p_offset; /* Segment file offset */
uint64_t p_vaddr; /* Segment virtual address */
uint64_t p_paddr; /* Segment physical address */
uint64_t p_filesz; /* Segment size in file */
uint64_t p_memsz; /* Segment size in memory */
uint64_t p_align; /* Segment alignment */
} Elf64_Phdr;
Where I found these structs:
https://gitlab.com/bztsrc/posix-uefi/-/blob/master/examples/0F_exit_bs/exit_bs.c
If you have the file elf.h inside your /usr/include directory, you can also get these structs from that file.
You can copy the file to your preferred folder, like so:
cd some_dir/preferred_dir
cp /usr/include/elf.h .
And then copy the structs inside of it and paste them into your project.
If you are on Windows, you can use WSL to do this.
That is what I have learned.

bpf verifier log is truncated, how to get the full log?

As the following, bpf verifier log is truncated at the last. How could I get the full log ?
368=mmmmmmmm fp-376=mmmmmmmm fp-432=mmmmmmmm fp-440=inv fp-448=inv fp-456=map_value fp-464=inv
389: (73) *(u8 *)(r3 +322) = r1
390: (71) r1 = *(u8 *)(r2 +713)
R0=inv(id=0,umax_value=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=0,ks=260,vs=904,imm=0) R3=pkt(id=0,off=42,r=398,imm=0) R4_w=inv0 R6=invP0 R7=ctx(id=0,off=0,imm=0) R8=inv(id=0) R9=inv(id=9) R10=fp0 fp-32=????mmmm fp-40=mmmmmmmm
fp-48=mmmmmmmm fp-56=mmmmmmmm fp-64=mmmmmmmm fp-72=mmmmmmmm fp-80=mmmmmmmm fp-88=mmmmmmmm fp-96=mmmmmmmm fp-104=mmmmmmmm fp-112=mmmmmmmm fp-120=mmmmmmmm fp-128=mmmmmmmm fp-136=mmmmmmmm fp-144=mmmmmmmm
fp-152=mmmmmmmm fp-160=mmmmmmmm fp-168=mmmmmmmm fp-176=mmmmmmmm fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200=mmmmmmmm fp-208=mmmmmmmm fp-216=mmmmmmmm fp-224=mmmmmmmm fp-232=mmmmmmmm fp-240=mmmmmmmm fp-248=mmmmmmmm fp-256=mmmmmmmm fp-264=mmmmmmmm fp-272=mmmmmmmm fp-280=mmmmmmmm fp-288=mmmmmmmm fp-296=mmmm????
fp-304=??mmmmmm fp-312=mmmmmmmm fp-320=mmmmmmmm fp-328=?mmmmmmm fp-336=mmmmmmmm fp-344= (truncated...)
supplement:
Under the guide of #Qeole, I have solved the problem.
cilium/ebpf implement,It can be used as a reference.
https://github.com/cilium/ebpf/commit/f365a1e12f0a2477c41ee907a917db6f9bd9cf72
You need to pass a larger buffer (and to indicate its length accordingly) to the verifier when you load your program.
The kernel receives a pointer to a union bpf_attr, which for loading programs starts like this:
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
log_buf, of size log_size, is the buffer filled by the verifier. You don't usually set up these parameters yourself, how you should do it depends on what you use to load your program. Most loaders rely on libbpf, and in recent versions, they should automatically attempt to reload the program with a larger buffer size in case of error and if the verifier output is truncated.

Writing PCI driver for DMA transfer on Qemu

I am writing a PCI device on Qemu and driver(LKM) in the guest OS. While Qemu provides an example PCI device, edu(edu.txt and edu.c) with it's distribution, I am having trouble writing the kernel module to do DMA transfer. A basic driver has been covered here but it does not support DMA.
I am following the implementation of the link and this. I tried to transmit buffer to the PCI device from the IRQ handler. The device can read the data (pci_dma_read) but the I am not getting the correct data that I am supposed to receive. Here is the code segment that is doing DMA transfer:
static int write_to_HyPerf(void *dev, void* addr, uint32_t size)
{
/* ----------------------------------------------------------------------------
* PCI address 'addr':
* addr -> DMA source address
* 0x40000 -> DMA destination address
* 100 -> DMA transfer count
* 1 -> DMA command register
* while (DMA command register & 1)
*--------------------------------------------------------------------------------
*/
iowrite32((u32 *)dma_handle_to_device, mmio + IO_DMA_SRC);
iowrite32(DMA_START, mmio + IO_DMA_DST);
iowrite32((u32 *)size, mmio + IO_DMA_XCNT);
iowrite32(DMA_CMD | DMA_IRQ, mmio + IO_DMA_CMD);
}
I also have setup coherent mapping using dma_alloc_coherent.
vaddr_to_device = dma_alloc_coherent(&(dev->dev), DMA_SIZE, &dma_handle_to_device, GFP_ATOMIC);
The complete code is available here. What am I doing wrong?
Could be that you having problem in your driver.
In this case you can use this:
https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/qemu_edu.c
and you can use dd command as in this script to write and read from your device:
https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/qemu_edu.sh
Then all you need is to write the wanted dma values to the correct address
like in the edu.c code:
case 0x80:
dma_rw(edu, false, &val, &edu->dma.src, false);
break;
case 0x88:
dma_rw(edu, false, &val, &edu->dma.dst, false);
break;
case 0x90:
dma_rw(edu, false, &val, &edu->dma.cnt, false);
break;
case 0x98:
dma_rw(edu, false, &val, &edu->dma.cmd, false);
break;

(GSM module SM5100B + ATMEGA16A interface) Trouble sending SMS using AT commands in C code

I am having trouble with my university project for embedded systems. The goal is to establish an interface between a SM5100B GSM module and ATMEGA16A microcontroller, using UART (which I did, using the correct ports from the datasheets), and to be able to send/receive simple SMS messages by sending AT commands trough the Tx and Rx ports from atmega to gsm and vice versa, via C code in Atmel.(not using hyperterminal)
When I tested the GSM module using TeraTerm, i was able to connect properly, and send AT commands easily, also managed to send and recieve an SMS with the SIM card inserted, so everything works fine.
Now I'm trying to do that using the microcontroller.
Here is the code I have so far:
#define F_CPU 7372800UL
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/io.h>
#include <string.h>
#define BAUD 9600
#define MYUBRR ((F_CPU/16/BAUD)-1) //BAUD PRESCALAR (for Asynch. mode)
void GSM_init(unsigned int ubrr ) {
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
void USART_Transmit(char data ) {
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) );
/* Put data into buffer, sends the data */
UDR = data;
}
void USART_Transmits(char data[] ) {
int i;
for(i=0; i<strlen(data); i++) {
USART_Transmit(data[i]);
_delay_ms(300);
}
}
int main(void)
{
GSM_init(MYUBRR);
char text_mode[] = "AT+CMGF=1";
char send_sms[] = "AT+CMGS=";
char phone_number[] = "00385*********";
char sms[] = "gsm sadness";
USART_Transmits(text_mode);
_delay_ms(1000);
USART_Transmits(send_sms);
_delay_ms(1000);
USART_Transmit(34);//quotation mark "
//_delay_ms(300);
USART_Transmits(phone_number);
//_delay_ms(300);
USART_Transmit(34);//quotation mark "
//_delay_ms(300);
USART_Transmit(13);//enter
//_delay_ms(300);
USART_Transmits(sms);
_delay_ms(1000);
USART_Transmit(26);//ctrl+z
_delay_ms(300);
USART_Transmit(13);//enter
_delay_ms(3000);
while (1)
{
}
}
However, my code isn't working, it's not sending the message.
The functions for transmitting are taken from the datasheet and everywhere on the internet I search I find the same ones over and over again.
Is the problem in AT responses that I'm not reading correctly? Or in parsing AT commands to the serial port?
Can anybody help me understand where I'm going wrong with this, or where I can look for to understand how to make this work?

STM32F446 DFU : Hard fault with free() function

I currently try to upgrade my firmware by using Dfuse from ST. In application mode USB HS in VCP mode allow a communication between computer and µC and I use this communication and a non initialized variable for reset device and configure DFU interface with the followed code.
*/void MX_USB_DEVICE_Init(void)
{
if (DFU_OR_CDC==1)
{
/* Otherwise enters DFU mode to allow user programing his application */
/* Init Device Library */
USBD_Init(&USBD_Device, &DFU_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&USBD_Device, USBD_DFU_CLASS);
/* Add DFU Media interface */
USBD_DFU_RegisterMedia(&USBD_Device, &USBD_DFU_Flash_fops);
/* Start Device Process */
USBD_Start(&USBD_Device);
/* Set led1 for indicate that device that device works as CDC/VCP interface */
SetLed(LED2);
ResetLed(LED1);
while(1)
{
}
}
/* If CDC is selected configure and start USB CDC interface*/
else if (DFU_OR_CDC==2)
{
/* Init Device Library */
USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&hUSBDDevice, USBD_CDC_CLASS);
/* Add CDC Interface Class */
USBD_CDC_RegisterInterface(&hUSBDDevice, &USBD_CDC_fops);
/* Start Device Process */
USBD_Start(&hUSBDDevice);
/* Set led2 for indicate that device that device works as DFU interface */
SetLed(LED1);
ResetLed(LED2);
Readframe();
}
/*Auto select of CDC usb interface for the next plug, Reset after use of DFU mode*/
DFU_OR_CDC=2;
}
When I use only DFU by set manually the variable DFU_OR_CDC to DFU that's works fine, but if I use VCP and then DFU by using my command I have de HardFault which occur on DFU_DeInit (from example from ST), especially in free() function.
/**
* #brief USBD_DFU_Init
* De-Initialize the DFU layer
* #param pdev: device instance
* #param cfgidx: Configuration index
* #retval status
*/
static uint8_t USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
hdfu->wblock_num = 0;
hdfu->wlength = 0;
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;
hdfu->dev_status[4] = DFU_STATE_IDLE;
/* DeInit physical Interface components */
if(pdev->pClassData != NULL)
{
/* De-Initialize Hardware layer */
((USBD_DFU_MediaTypeDef *)pdev->pUserData)->DeInit();
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return USBD_OK;
}
The debugger indicate a UNDEFINSTR (Keil V5)with an address of 0x080089A8 for free function. UNDEFINSTR indicate that I try to branch to an address where no code is located, but I unable to understand why.
Any Help will be kind.
Its a known bug in ST's library.
Several of its versions mixes dynamic and static memory management.
Look closely to USBD_malloc / USBD_free.
Most likely, USBD_malloc simply return pointer to global variable, and USBD_free calls standart memory manager:
/* Memory management macros */
#define USBD_malloc (uint32_t *)USBD_static_malloc
#define USBD_free USBD_static_free
void *USBD_static_malloc(uint32_t size)
{
static uint8_t mem[sizeof(USBD_CDC_HandleTypeDef)];
return mem;
}
void USBD_static_free(void *p)
{
free(p);
}
To fix this, just remove call of free().
For resolve this I have used the method explained by FLIP in the following post.
StackOverFlow Jump to bootloader
I program my µC in two steps :
-DFU firmware. Programming start: beginning of Flash memory address, End : position on application firmware in flash memory.This firmware read a GPIO pin and according to this one will jump on my application or start DFU mode.
-Application firmware. Programming start: beginning of Flash memory address, End : position on application firmware in flash memory. Then I reconfigure HAL library,clocks and vector table offset then I enter in my infinity loop where my application run.