D-Bus tutorial in C to communicate with wpa_supplicant - linux

I'm trying to write some code to communicate with wpa_supplicant using DBUS. As I'm working in an embedded system (ARM), I'd like to avoid the use of Python or the GLib. I'm wondering if I'm stupid because I really have the feeling that there is no nice and clear documentation about D-Bus. Even with the official one, I either find the documentation too high level, or the examples shown are using Glib! Documentation I've looked at: http://www.freedesktop.org/wiki/Software/dbus
I found a nice article about using D-Bus in C: http://www.matthew.ath.cx/articles/dbus
However, this article is pretty old and not complete enough! I also found the c++-dbus API but also here, I don't find ANY documentation! I've been digging into wpa_supplicant and NetworkManager source code but it's quite a nightmare! I've been looking into the "low-level D-Bus API" as well but this doesn't tell me how to extract a string parameter from a D-Bus message! http://dbus.freedesktop.org/doc/api/html/index.html
Here is some code I wrote to test a little but I really have trouble to extract string values. Sorry for the long source code but if someone want to try it ... My D-Bus configuration seems fine because it "already" catches "StateChanged" signals from wpa_supplicant but cannot print the state:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <dbus/dbus.h>
//#include "wpa_supp_dbus.h"
/* Content of wpa_supp_dbus.h */
#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface"
#define WPAS_DBUS_NETWORKS_PART "Networks"
#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
int running = 1;
void stopLoop(int sig)
{
running = 0;
}
void sendScan()
{
// TODO !
}
void loop(DBusConnection* conn)
{
DBusMessage* msg;
DBusMessageIter args;
DBusMessageIter subArgs;
int argType;
int i;
int buffSize = 1024;
char strValue[buffSize];
const char* member = 0;
sendScan();
while (running)
{
// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't read a message
if (!msg)
{
printf("No message received, waiting a little ...\n");
sleep(1);
continue;
}
else printf("Got a message, will analyze it ...\n");
// Print the message member
printf("Got message for interface %s\n",
dbus_message_get_interface(msg));
member = dbus_message_get_member(msg);
if(member) printf("Got message member %s\n", member);
// Check has argument
if (!dbus_message_iter_init(msg, &args))
{
printf("Message has no argument\n");
continue;
}
else
{
// Go through arguments
while(1)
{
argType = dbus_message_iter_get_arg_type(&args);
if (argType == DBUS_TYPE_STRING)
{
printf("Got string argument, extracting ...\n");
/* FIXME : got weird characters
dbus_message_iter_get_basic(&args, &strValue);
*/
/* FIXME : segmentation fault !
dbus_message_iter_get_fixed_array(
&args, &strValue, buffSize);
*/
/* FIXME : segmentation fault !
dbus_message_iter_recurse(&args, &subArgs);
*/
/* FIXME : deprecated!
if(dbus_message_iter_get_array_len(&args) > buffSize)
printf("message content to big for local buffer!");
*/
//printf("String value was %s\n", strValue);
}
else
printf("Arg type not implemented yet !\n");
if(dbus_message_iter_has_next(&args))
dbus_message_iter_next(&args);
else break;
}
printf("No more arguments!\n");
}
// free the message
dbus_message_unref(msg);
}
}
int main(int argc, char* argv[])
{
DBusError err;
DBusConnection* conn;
int ret;
char signalDesc[1024]; // Signal description as string
// Signal handling
signal(SIGKILL, stopLoop);
signal(SIGTERM, stopLoop);
// Initialize err struct
dbus_error_init(&err);
// connect to the bus
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (!conn)
{
exit(1);
}
// request a name on the bus
ret = dbus_bus_request_name(conn, WPAS_DBUS_SERVICE, 0, &err);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "Name Error (%s)\n", err.message);
dbus_error_free(&err);
}
/* Connect to signal */
// Interface signal ..
sprintf(signalDesc, "type='signal',interface='%s'",
WPAS_DBUS_IFACE_INTERFACE);
dbus_bus_add_match(conn, signalDesc, &err);
dbus_connection_flush(conn);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "Match Error (%s)\n", err.message);
exit(1);
}
// Network signal ..
sprintf(signalDesc, "type='signal',interface='%s'",
WPAS_DBUS_IFACE_NETWORK);
dbus_bus_add_match(conn, signalDesc, &err);
dbus_connection_flush(conn);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "Match Error (%s)\n", err.message);
exit(1);
}
// Bssid signal ..
sprintf(signalDesc, "type='signal',interface='%s'",
WPAS_DBUS_IFACE_BSSID);
dbus_bus_add_match(conn, signalDesc, &err);
dbus_connection_flush(conn);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "Match Error (%s)\n", err.message);
exit(1);
}
// Do main loop
loop(conn);
// Main loop exited
printf("Main loop stopped, exiting ...\n");
dbus_connection_close(conn);
return 0;
}
Any pointer to any nice, complete, low-level C tutorial is strongly appreciated! I'm also planning to do some remote method call, so if the tutorial covers this subject it would be great! Saying I'm not very smart because I don't get it with the official tutorial is also appreciated :-p!
Or is there another way to communicate with wpa_supplicant (except using wpa_cli)?
EDIT 1:
Using 'qdbusviewer' and the introspection capabilty, this helped me a lot discovering what and how wpa_supplicant works using dbus. Hopping that this would help someone else!
Edit 2:
Will probably come when I'll find a way to read string values on D-Bus!

You have given up the tools that would help you to learn D-Bus more easily and are using the low level libdbus implementation, so maybe you deserve to be in pain. BTW, are you talking about ARM, like a cell phone ARM ? With maybe 500 Mhz and 256 MB RAM ? In this case the processor is well suited to using glib, Qt or even python. And D-Bus is most useful when you're writing asynchronous event driven code, with an integrated main loop, for example from glib, even when you're using the low level libdbus (it has functions to connect to the glib main loop, for example).
Since you're using the low level library, then documentation is what you already have:
http://dbus.freedesktop.org/doc/api/html/index.html
Also, libdbus source code is also part of the documentation:
http://dbus.freedesktop.org/doc/api/html/files.html
The main entry point for the documentation is the Modules page (in particular, the public API section):
http://dbus.freedesktop.org/doc/api/html/modules.html
For message handling, the section DBusMessage is the relevant one:
DBusMessage
There you have the documentation for functions that parse item values. In your case, you started with a dbus_message_iter_get_basic. As described in the docs, retrieving the string requires a const char ** variable, since the returned value will point to the pre-allocated string in the received message:
So for int32 it should be a "dbus_int32_t*" and for string a "const char**". The returned value is by reference and should not be freed.
So you can't define an array, because libdbus won't copy the text to your array. If you need to save the string, first get the constant string reference, then strcpy to your own array.
Then you tried to get a fixed array without moving the iterator. You need a call to the next iterator (dbus_message_iter_next) between the basic string and the fixed array. Same right before recursing into the sub iterator.
Finally, you don't call get_array_len to get the number of elements on the array. From the docs, it only returns byte counts. Instead you loop over the sub iterator using iter_next the same way you should have done with the main iterator. After you have iterated past the end of the array, dbus_message_iter_get_arg_type will return DBUS_TYPE_INVALID.
For more info, read the reference manual, don't look for a tutorial. Or just use a reasonable d-bus implementation:
https://developer.gnome.org/gio/2.36/gdbus-codegen.html
GIO's GDBus automatically creates wrappers for your d-bus calls.
http://qt-project.org/doc/qt-4.8/intro-to-dbus.html
http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
etc.

You don't need to use/understand working of dbus If you just need to write a C program to communicate with wpa_supplicant. I reverse engineered the wpa_cli's source code. Went through its implementation and used functions provided in wpa_ctrl.h/c. This implementation takes care of everything. You can use/modify whatever you want, build your executable and you're done!
Here's the official link to wpa_supplicant's ctrl_interface:
http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html

I doubt this answer will still be relevant to the author of this question,
but for anybody who stumbles upon this like I did:
The situation is now better than all those years ago if you don't want to include GTK/QT in your project to access dbus.
There is dbus API in Embedded Linux Library by Intel (weird I remember it being open, maybe it is just for registered users now?)
and systemd sd-bus library now offers public API. You probably run systemd anyway unless you have a really constrained embedded system.
I have worked with GDbus, dbus-cpp and sd-bus and although I wanted a C++ library,
I found sd-bus to be the simplest and the least problematic experience.
I did not try its C++ bindings but they also look nice
#include <stdio.h>
#include <systemd/sd-bus.h>
#include <stdlib.h>
const char* wpa_service = "fi.w1.wpa_supplicant1";
const char* wpa_root_obj_path = "/fi/w1/wpa_supplicant1";
const char* wpa_root_iface = "fi.w1.wpa_supplicant1";
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus* system_bus = NULL;
sd_event* loop = NULL;
sd_bus_message* reply = NULL;
void cleanup() {
sd_event_unref(loop);
sd_bus_unref(system_bus);
sd_bus_message_unref(reply);
sd_bus_error_free(&error);
}
void print_error(const char* msg, int code) {
fprintf(stderr, "%s %s\n", msg, strerror(-code));
exit(EXIT_FAILURE);
}
const char* get_interface(const char* iface) {
int res = sd_bus_call_method(system_bus,
wpa_service,
wpa_root_obj_path,
wpa_root_iface,
"GetInterface",
&error,
&reply,
"s",
"Ifname", "s", iface,
"Driver", "s", "nl80211");
if (res < 0) {
fprintf(stderr, "(get) error response: %s\n", error.message);
return NULL;
}
const char* iface_path;
/*
* an object path was returned in reply
* this works like an iterator, if a method returns (osu), you could call message_read_basic in succession
* with arguments SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_STRING, SD_BUS_TYPE_UINT32 or you could
* call sd_bus_message_read() and provides the signature + arguments in one call
* */
res = sd_bus_message_read_basic(reply, SD_BUS_TYPE_OBJECT_PATH, &iface_path);
if (res < 0) {
print_error("getIface: ", res);
return NULL;
}
return iface_path;
}
const char* create_interface(const char* iface) {
int res = sd_bus_call_method(system_bus,
wpa_service,
wpa_root_obj_path,
wpa_root_iface,
"CreateInterface",
&error,
&reply,
"a{sv}", 2, //pass array of str:variant (dbus dictionary) with 2
//entries to CreateInterface
"Ifname", "s", iface, // "s" variant parameter contains string, then pass the value
"Driver", "s", "nl80211");
if (res < 0) {
fprintf(stderr, "(create) error response: %s\n", error.message);
return NULL;
}
const char* iface_path;
res = sd_bus_message_read_basic(reply, SD_BUS_TYPE_OBJECT_PATH, &iface_path);
if (res < 0) {
print_error("createIface: ", res);
}
return iface_path;
}
int main() {
int res;
const char* iface_path;
//open connection to system bus - default either opens or reuses existing connection as necessary
res = sd_bus_default_system(&system_bus);
if (res < 0) {
print_error("open: ", res);
}
//associate connection with event loop, again default either creates or reuses existing
res = sd_event_default(&loop);
if (res < 0) {
print_error("event: ", res);
}
// get obj. path to the wireless interface on dbus so you can call methods on it
// this is a wireless interface (e.g. your wifi dongle) NOT the dbus interface
// if you don't know the interface name in advance, you will have to read the Interfaces property of
// wpa_supplicants root interface — call Get method on org.freedesktop.DBus properties interface,
// while some libraries expose some kind of get_property convenience function sd-bus does not
const char* ifaceName = "wlp32s0f3u2";
if (!(iface_path = get_interface(ifaceName))) { //substitute your wireless iface here
// sometimes the HW is present and listed in "ip l" but dbus does not reflect that, this fixes it
if (!(iface_path = create_interface(ifaceName))) {
fprintf(stderr, "can't create iface: %s" , ifaceName);
cleanup();
return EXIT_FAILURE;
}
}
/*
call methods with obj. path iface_path and dbus interface of your choice
this will likely be "fi.w1.wpa_supplicant1.Interface", register for signals etc...
you will need the following to receive those signals
*/
int runForUsec = 1000000; //usec, not msec!
sd_event_run(loop, runForUsec); //or sd_event_loop(loop) if you want to loop forever
cleanup();
printf("Finished OK\n");
return 0;
}
I apologize if the example above does not work perfectly. It is an excerpt from an old project I rewrote to C from C++ (I think it's C(-ish), compiler does not protest and you asked for C) but I can't test it as all my dongles refuse to work with my desktop right now. It should give you a general idea though.
Note that you will likely encounter several magical or semi-magical issues.
To ensure smooth developing/testing do the following:
make sure other network management applications are disabled (networkmanager, connman...)
restart the wpa_supplicant service
make sure the wireless interface is UP in ip link
Also, because is not that well-documented right now:
You can access arrays and inner variant values by sd_bus_message_enter_container
and _exit counterpart. sd_bus_message_peek_type might come handy while doing that.
Or sd_bus_message_read_array for a homogenous array.

The below snippet works for me
if (argType == DBUS_TYPE_STRING)
{
printf("Got string argument, extracting ...\n");
char* strBuffer = NULL;
dbus_message_iter_get_basic(&args, &strBuffer);
printf("Received string: \n %s \n",strBuffer);
}

Related

(windows nvidia video codec sdk) How to set up an hevc encode session in c++ that asynchrnously encodes a dxgi surface texture and outputs to stdout?

I'm working on a c++ executable that grabs my display output using DXGI output duplication in the form of DXGI surface textures(I think), directly encodes it in HEVC using my GPU hardware encoder, which then downloads the bitstream to system memory so it can be output to stdout.
I would like to encode asynchronously, which is reported to be possible in the docs. As I understand it, asynchronously would mean a single blocking method call that accepts a video frame in gpu memory and returns a compressed frame (nal unit I think it's called)
The executable is part of a remote access implementation I'm working on and would be ran as a subprocess by a main golang app when the client connects and authenticates.
Here's my code so far:
#include <iostream>
#pragma comment(lib, "d3d11")
#include <d3d11.h>
#pragma comment(lib, "dxgi")
#include <dxgi1_2.h>
//#include <nvEncodeAPI.h>
using namespace std;
int main()
{
//NvEncodeAPICreateInstance();
// intermediate variables for casting
IDXGIOutput* pDisplay_old;
IDXGIFactory1* pFactory;
IDXGIAdapter* pGPU;
ID3D11Device* pD3D;
IDXGIOutput1* pDisplay;
// create DXGI factory
if (CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory) != S_OK) return 1;
// get GPU adapter
if (pFactory -> EnumAdapters(0, &pGPU) != S_OK) return 2;
// create D3D11 device
D3D_FEATURE_LEVEL D3DFeatures [6]
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
if (D3D11CreateDevice(pGPU, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, D3DFeatures, ARRAYSIZE(D3DFeatures), D3D11_SDK_VERSION, &pD3D, NULL, NULL) != S_OK) return 3;
// get display
if (pGPU -> EnumOutputs(0, &pDisplay_old) != S_OK) return 4;
pDisplay_old -> QueryInterface(&pDisplay);
IDXGIOutputDuplication* pCapture;
DXGI_OUTDUPL_DESC captureDesc;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource* pFrame;
HRESULT captureResult;
do
{
// create capture
if (pDisplay -> DuplicateOutput(pD3D, &pCapture) != S_OK) return 5;
pCapture -> GetDesc(&captureDesc);
cout << captureDesc.ModeDesc.Width << ' ' << captureDesc.ModeDesc.Height;
do
{
captureResult = pCapture -> AcquireNextFrame(INFINITE, &frameInfo, &pFrame);
if (captureResult == S_OK)
{
if (frameInfo.LastPresentTime.QuadPart != 0)
{
// === async blocking Encode logic and printing to stdout should be here =========
// =========================================================
}
captureResult = pCapture -> ReleaseFrame();
}
else if (captureResult == DXGI_ERROR_ACCESS_LOST) break;
else return 6;
}
while (true);
}
while (true);
}
It successfully grabs the display framebuffer in the form of IDXGIResource objects, which I (pCapture is the pointer to them), and now I need to figure out how to setup the nvenc session, get it to accept these strange objects as frame input, and getting the output into system memoryin a form that can be printed to stdout. (ideally async as described above)
I had a look at the docs https://docs.nvidia.com/video-technologies/video-codec-sdk/nvenc-video-encoder-api-prog-guide/index.html, and while it's reasonably descriptive, it doesn't seem to offer any code examples, and I couldn't find any examples online either.
I downloaded the SDK headers and tried some stuff but I feel that it would be better for those familiar to guide me through this.
Thanks!

Windows application using libusb: runtime error due to mutex lock

I am trying to establish communication between a laptop and an embedded board over USB. USB driver for board has been installed and it has been detected in Windows device manager. Now I am developing code in Visual Studio 2013 (Win32 Console Application) using libusb.
The libusb_init() function does not return an error however when I try to open the device with libusb_open_device_with_vid_pid(), execution breaks at function usbi_mutex_init() in the threads_windows.c file of the libusb library. This file contains the source for "libusb synchronization on Microsoft Windows".
I also tried to call function libusb_get_device_list() but get the same error. Could you please suggest a solution?
main.cpp from my application source code -->
#include <iostream>
#include "libusb.h"
using namespace std;
int main()
{
int init_status = 0;
libusb_context *context = NULL;
libusb_device_handle *device;
init_status = libusb_init(&context);
if (init_status<0)
{
cout << "could not initialize";
return -1;
}
device = libusb_open_device_with_vid_pid(NULL, 0x0483, 0x5750); //execution breaks here
if (device == NULL)
{
cout << "could not open device";
return -1;
}
else
{
cout << "Device opened successfukky";
}
return 0;
}
threads_windows.c from libusb source code -->
int usbi_mutex_lock(usbi_mutex_t *mutex) {
DWORD result;
if(!mutex) return ((errno=EINVAL));
result = WaitForSingleObject(*mutex, INFINITE); //execution breaks here
if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
return 0; // acquired (ToDo: check that abandoned is ok)
return ((errno=EINVAL)); // don't know how this would happen
// so don't know proper errno
}
Looks to me like you get a specific, non-default context with your libusb_init() but when you use libusb_open_device_with_vid_pid() you are pass NULL which means to use the default context rather than the context created by the libusb_init().
You may just want to use the default context if it is a single device and you only need a single session. The documentation indicates that there are "limitations" with libusb_open_device_with_vid_pid() and it is not intended for anything other than test applications. I assume this is because in real applications there may be multiple devices and this convenience function just takes the first one matching the arguments. However the issue you are seeing is probably related to the context.
For a one off type of specific project your code would look something like:
#include <iostream>
#include "libusb.h"
using namespace std;
int main()
{
int init_status = 0;
libusb_device_handle *device;
// specify NULL for the context address so that libusb_init will use default content.
// this means that any libusb function with a context argument will be called with NULL.
init_status = libusb_init (NULL);
if (init_status < 0)
{
cout << "could not initialize";
return -1;
}
// open the first device found in the device list with this vendor id and product id
// for a real application in a multi-device environment we would need to
// iterate through the various devices using libusb_get_device_list() to get
// the list of devices then using libusb_get_device_descriptor() to iterate
// through the list to find the device we want. also need libusb_free_device_list ()
// after finishing with the list. lots of work for a simple one off project
device = libusb_open_device_with_vid_pid (NULL, 0x0483, 0x5750);
if (device == NULL)
{
cout << "could not open device";
return -1;
} else {
cout << "Device opened successfully";
}
return 0;
}

console application runtime problems

I have a problem with my console application. I'm following some kind of a tutorial on networking, and when I try to run in debug I have a weird runtime error I have never seen before.
When I put a breakpoint on the first new line inside the main function and go through the code with Step Over (F10), visual studio executes the first ~3 lines of code including WSAStartup(), then suddenly reaches acomment section:
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include "wsh_includes.h"
int main(int argc, const char* argv[])
{
//You have to make a call to WSAStartup() before doing anything else with the sockets library
//WSADATA wsaData; // if this doesn't work
WSAData wsaData; // then try this instead
wsh::errcheck(WSAStartup(MAKEWORD(2, 2), &wsaData), "WSAStartup failed");
//----------
//You also have to tell your compiler to link in the Winsock library, usually called
//wsock32.lib or winsock32.lib, or ws2_32.lib for Winsock 2.0
//----------
//you can't use close() to close a socket—you need to use closesocket()
//----------
//select() only works with socket descriptors, not file descriptors (like 0 for stdin).
//There is also a socket class that you can use, CSocket
//----------
int status;
addrinfo hints, *res, *p;
char ipstr[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints)); //make sure it's empty
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM; //TCP stream sockets
status = getaddrinfo("www.example.net", NULL, &hints, &res);
wsh::errcheck(status, "getaddrinfo failed");
//servinfo now points to a linked list of 1 or more struct addrinfos
//... do everything until you don't need servinfo anymore ...
printf("IP addresses for %s:\n\n", argv[1]);
for (p = res; p != NULL; p = p->ai_next) {
void* addr;
char* ipver;
//get the pointer to the address itself
//different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) {
sockaddr_in* ipv4 = (sockaddr_in*)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
}
else {
sockaddr_in6* ipv6 = (sockaddr_in6*)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
//convert the IP to a string and print it:
inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
printf(" %s: %s\n", ipver, ipstr);
}
std::cin.get();
freeaddrinfo(res); //free the linked list
//----------
//Finally, you need to call WSACleanup() when you're all through with the sockets library.
wsh::errcheck(WSACleanup(), "WSACleanup failed");
return 0;
}
When it gets there, it suddenly moves to the file crtexe.c in the middle of the commented section.
More specifically, it jumps to:
#ifdef WPRFLAG
__winitenv = envp;
mainret = wmain(argc, argv, envp);
#else /* WPRFLAG */
__initenv = envp;
mainret = main(argc, argv, envp); //here
then to:
#else /* !defined (_WINMAIN_) && defined (_CRT_APP) */
if ( !managedapp )
{
#ifndef _CRT_APP
exit(mainret); //here
I have tried getting rid of all the comments, when I run in debug then the code will behave differently (yet not really as expected).
What exactly is going on here and how can I fix it?
This is usually caused by mismatched line endings (some lines ending with a CR/LF, some ending with just a CR or LF), which causes the IDE not to be able to keep the code editor and debugger in synch.
VS often recognizes this condition and displays a dialog asking about whether you want to normalize line endings (see What does Visual Studio mean by normalizing line endings? for more information).
You can fix this yourself by using the File->Advanced Save Options menu item, and setting the Line Endings to Windows (CR LF).

Please help me to make this fake character linux device driver work

Hello I am trying to write to a fake char device driver using:
echo > /dev/
and reading it using:
cat /dev/
My problem is that I am getting continuously the first character written printed on the terminal when I do a read with the above mentioned "cat" read method after writing using the echo method above.
My aim is to get the entire set of characters written to the driver back...
I am using dynamic memory allocation for this purpose but not getting the final result after trying many ways of rewriting the code of read() and write() in the driver. Please help..
my Makefile is correct... (I am using ubuntu with a kernel version of 2.6.33...)
My code is as below:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
static dev_t first;
static struct cdev c_dev;
static struct class *cl;
static char* k_buf = NULL;
static int my_open(struct inode *i,struct file *f)
{
printk(KERN_INFO "In driver open()\n");
return 0;
}
static int my_close(struct inode *i,struct file *f)
{
printk(KERN_INFO "In driver close()\n");
return 0;
}
static ssize_t my_read(struct file *f,char __user *buf,size_t len,loff_t *off)
{
printk(KERN_INFO "In driver read()\n");
if(k_buf == NULL)
{
printk(KERN_INFO "You cannot read before writing!\n");
return -1;
}
while(*k_buf != 'EOF')
{
if(copy_to_user(buf,k_buf,1))
return -EFAULT;
off++;
return 1;
}
return 0;
}
static ssize_t my_write(struct file *f,const char __user *buf,size_t len,loff_t *off)
{
printk(KERN_INFO "In driver write()\n");
k_buf = (char*) kmalloc(sizeof(len),GFP_KERNEL);
if(copy_from_user(k_buf,buf,len))
return -EFAULT;
off += len;
return (len);
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write
};
static int __init rw_init(void) /*Constructor*/
{
printk(KERN_INFO "hello: rw_ch_driver registered\n");
if(alloc_chrdev_region(&first,0,1,"krishna") < 0)
{
return -1;
}
if ((cl = class_create(THIS_MODULE,"chardev")) == NULL)
{
unregister_chrdev_region(first,1);
return -1;
}
if (device_create(cl,NULL,first,NULL,"rw_char_driver") == NULL)
{
class_destroy(cl);
unregister_chrdev_region(first,1);
return -1;
}
cdev_init(&c_dev,&fops);
if(cdev_add(&c_dev,first,1) == -1)
{
device_destroy(cl,first);
class_destroy(cl);
unregister_chrdev_region(first,1);
return -1;
}
return 0;
}
static void __exit rw_exit(void)/*destructor*/
{
cdev_del(&c_dev);
device_destroy(cl,first);
class_destroy(cl);
unregister_chrdev_region(first,1);
printk(KERN_INFO "bye rw_chardriver unregistered");
}
module_init(rw_init);
module_exit(rw_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("krishna");
MODULE_DESCRIPTION("read write character driver");
Take a careful look at your while loop in my_read().
Most important note first: you don't need this loop. You've put a return statement in it, so it is never going to execute more than once, because the whole function is going to exit when the return is reached. It looks like you're trying to make the function return a single byte at a time repeatedly, but you should just call copy_to_user once, and pass it the number of bytes you want to give back to the user instead. If you only send one character at a time that's fine. It will be up to the user to make the read call again to get the next character.
The nice thing about copy_to_user, is that its return code will tell you if it failed because of bad array bounds, so there's no need to check for EOF on every character. In fact, you are not going to get 'EOF' as a character when you are reading from your buffer because it doesn't exist. Your buffer will store characters and usually a null terminator, '\0', but there is no 'EOF' character in C. EOF is a state you need to identify yourself and report to whoever called open. For the "cat" command, this is done by returning 0 from read. That being said, you should still check your array bounds so we don't end up with another Heartbleed. This SO answer has a good suggestion for how to do bounds checking to make sure you don't send more bytes than your buffer has.
Also, give [this post(https://meta.stackexchange.com/questions/981/syntax-highlighting-language-hints) a read. If you don't have your language in your question tags, it is helpful to other readers to tag your. I've edited your question to clean it up, so you can click "edit" now to see how I did it.

How to use a function and pass its variables to the user app defined in the linux driver LM70?

Hi i would like to know how is it possible to call/run the following function from user space.
static ssize_t lm70_sense_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
//some code
.
.
status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
.
.
//some code
}
This function is defined in lm70.c driver located in the kernel/drivers/hwmon folder of the linux source? Is it possible to pass the values of this functions internal variables to the user application? I would like to retrieve the value of val variable in the above function...
I don't know well the kernel internals. However, I grepped for lm70_sense_temp in the entire kernel source tree, and it appears only in the file linux-3.7.1/drivers/hwmon/lm70.c, first as a static function, then as the argument to DEVICE_ATTR.
Then I googled for linux kernel DEVICE_ATTR and found immediately device.txt which shows that you probably should read that thru the sysfs, i.e. under /sys; read sysfs-rules.txt; so a user application could very probably read something relevant under /sys/
I'm downvoting your question because I feel that you could have searched a few minutes like I did (and I am not a kernel expert).
You don't need to call this function from user space to get that value - it is already exported to you via sysfs.
You could use grep to find which hwmon device it is:
grep -rl "lm70" /sys/class/hwmon/*/name /sys/class/hwmon/*/*/name
Then you can read the temperature input from your user space program, e.g:
#include <stdio.h>
#include <fcntl.h>
#define SENSOR_FILE "/sys/class/hwmon/hwmon0/temp1_input"
int readSensor(void)
{
int fd, val = -1;
char buf[32];
fd = open(SENSOR_FILE, O_RDONLY);
if (fd < 0) {
printf("Failed to open %s\n", SENSOR_FILE);
return val;
}
if (read(fd, &buf, sizeof(buf)) > 0) {
val = atoi(buf);
printf("Sensor value = %d\n", val);
} else {
printf("Failed to read %s\n", SENSOR_FILE);
}
close(fd);
return val;
}
As others have already stated - you can't call kernel code from user space, thems the breaks.
You cannot call a driver function directly from user space.
If that function is exported with EXPORT_SYMBOL or EXPORT_SYMBOL_GPL then we can write a simple kernel module and call that function directly. The result can be sent to user space through FIFO or shared memory.
But in your case, this function is not exported. so you should not do in this way.

Resources