I try to find a way, in C code, to distinguish whether a network interface is virtual or physical.
I was thinking to check whether the network interface is mapped to a driver, assuming that if there is no driver, it is most likely a virtual adapter (is there a more relevant method?).
Example (on a physical adapter):
$ ethtool -i eth0
driver: e1000
....
Example (on a virtual adapter):
$ ethtool -i eth10
Cannot get driver information: Operation not supported
Naturally, I looked at the source of ethtool to understand how it accesses the driver info: https://github.com/torvalds/linux/blob/master/net/core/ethtool.c
Here's the part that interests us:
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
void __user *useraddr)
{
struct ethtool_drvinfo info;
const struct ethtool_ops *ops = dev->ethtool_ops;
memset(&info, 0, sizeof(info));
info.cmd = ETHTOOL_GDRVINFO;
if (ops->get_drvinfo) {
ops->get_drvinfo(dev, &info);
} else if (dev->dev.parent && dev->dev.parent->driver) {
strlcpy(info.bus_info, dev_name(dev->dev.parent),
sizeof(info.bus_info));
strlcpy(info.driver, dev->dev.parent->driver->name,
sizeof(info.driver));
} else {
return -EOPNOTSUPP;
}
...
}
To get the net_device, there is a call to __dev_get_by_name(net, ifr->ifr_name), this function is apparently defined in
Problem is that __dev_get_by_name() and the required structures are defined in kernel files which I am not sure I can access from an external program.
Besides when I try to include headers such as , I get tons of redefinition of structures already defined in ...
I was wondering if there is a better way to get the driver info having a ifreq structure (http://man7.org/linux/man-pages/man7/netdevice.7.html).
ifreq structure is mostly a compatibility thing, as the new API in Linux is rtnetlink, but I do not recommend exploring it, unless you really have to. The ip shell utility gives access to more or less the entire stable part of the API, but I do not think it can show you the hardware device that is responsible for the device.
But:
I would have checked /sys/class/net/DEVICE_NAME/device symlink (is it present?)
Related
I would like to get a list of the wireless networks available. Ideally this would be via some C call, but I don't mind if I have to kludge it with a system call. Even better if the required C call or program doesn't require some exotic 3rd party package.
The internet seems to suggest I use sudo iwlist <interface> scan which does seem to do the trick from the command line, but I'd rather not require root permissions. I only want to see the basics, not change anything.
It's pretty easy to do a scan in the command line. The man pages are your friend here (check out iwconfig and iwlist). But using the C interface is a little more difficult so I'll focus on that.
First of all, as other people have mentioned, definitely download out the wireless tools source code. All the documentation for the programming interface is in the .c files. As far as I can tell, there is no web documentation for the api. However, the source code is pretty easy to read through. You pretty much only need iwlib.h and iwlib.c for this question.
While you can use iw_set_ext and iw_get_ext, the libiw implements a basic scanning function iw_scan, from which you can extract most of the information that you need.
Here is a simple program to get the ESSID for all available wireless networks. Compile with -liw and run with sudo.
#include <stdio.h>
#include <time.h>
#include <iwlib.h>
int main(void) {
wireless_scan_head head;
wireless_scan *result;
iwrange range;
int sock;
/* Open socket to kernel */
sock = iw_sockets_open();
/* Get some metadata to use for scanning */
if (iw_get_range_info(sock, "wlan0", &range) < 0) {
printf("Error during iw_get_range_info. Aborting.\n");
exit(2);
}
/* Perform the scan */
if (iw_scan(sock, "wlan0", range.we_version_compiled, &head) < 0) {
printf("Error during iw_scan. Aborting.\n");
exit(2);
}
/* Traverse the results */
result = head.result;
while (NULL != result) {
printf("%s\n", result->b.essid);
result = result->next;
}
exit(0);
}
DISCLAIMER: This is just a demonstration program. It's possible for some results to not have an essid. In addition, this assumes your wireless interface is "wlan0". You get the idea.
Read the iwlib source code!
The Wireless Tools package -- of which iwlist is a part -- also contains a Wireless Tools Helper Library. You need to include iwlib.h and link with libiw.a (i.e. add -liw). Then look up the documentation for the iw_set_ext function. The SIOCSIWSCAN parameter will be of most use. For an example of how to use this interface, take a look at the KWifiManager source in the KDE library (see: Interface_wireless_wirelessextensions::get_available_networks method). Alternatively, you can also download the Wireless Tools source code and take a look at how the iwlib iw_set_ext function is also used for scanning in iwlist.c.
As for privileges, I imagine the process will need to run as root to perform the scan. I'd love to know if this could be done otherwise as well.
Since you are using Ubuntu 8.04 the libiw-dev package should be of use.
You can use nmcli which does not require root permissions or name of WIFI interface.
nmcli -t -f ssid dev wifi
I will give a detailed exp of the program and lead to the issue regarding the use of netlink socket communication.
The last paragraph asks the actual question I need an answer for, so you might wanna start by peeking it first.
Disclaimer before I start:
- I have made an earlier search before asking here and did not find complete solution / alternative to my issue.
- I know how to initialize a module and insert it to kernel.
- I know to handle communication between module and user-space without using netlink sockets. Meaning using struct file_operations func pointers assignments to later be invoked by the module program whenever a user attempts to read/write etc. and answer to the user using copy_to_user / copy_from_user.
- This topic refers to Linux OS, Mint 17 dist.
- Language is C
Okay, so I am building a system with 3 components:
1. user.c : user application (user types commands here)
2. storage.c : storage device ('virtual' disk-on-key)
3. device.ko : kernel module (used as proxy between 1. and 2.)
The purpose of this system is to be able (as a user) to:
- Copy files to the virtual disk-on-key device (2) - like an "upload" from local directory that belongs to the user.
- Save files from the virtual device on local directory - like "download" from the device storage to the user directory.
Design:
Assuming programs (1),(2) are compiled and running + (3) has successfully inserted using the bash command ' sudo insmod device.ko ' , the following should work like this (simulation ofc):
Step 1 (in user.c) -> user types 'download file.txt'
Step 2 (in device.ko) -> the device recognizes the user have tried to 'write' to it (actually user just passing the string "download file.txt") and invokes the 'write' implementation of the method we set on struct file_operation earlier on module_init().
The device (kernel module) now passes the data (string with a command) to the storage.c application, expecting an answer to later be retrieved to the user.c application.
Step 3 (in storage.c) -> now, lets say this program performs a busy-wait loop of 'readmsg()' and that's how a request from module event is triggered and recognized, the storage device now recognizes that the module has sent a request (string with a command \ data). Now, the storage programs shall perform an implementation of some function 'X' to send the data requested using sendmsg() somewhere inside the function.
Now, here comes the issue.
Usually, on all of the examples I've looked on web, the communication between the kernel-module and a user-space (or the storage.c program in our case) using netlink is triggered by the user-space and not vice versa. Meaning that the sendmsg() function from the user-space invokes the 'request(struct sk_buff *skb)' method (which is set on the module_init() part as following:
struct netlink_kernel_cfg cfg = {
.input = request // when storage.c sends something, it invokes the request function
};
so when the storage.c performs something like:
sendmsg(sock_fd,&msg,0); // send a msg to the module
the module invokes and runs the:
static void request(struct sk_buff *skb) {
char *msg ="Hello from kernel";
msg_size=strlen(msg);
netlink_holder=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(netlink_holder));
pid = netlink_holder->nlmsg_pid; // pid of sending process
skb_out = nlmsg_new(msg_size,0);
if(!skb_out){
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
netlink_holder=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0); // add a new netlink message to an skb. more info: http://elixir.free-electrons.com/linux/v3.2/source/include/net/netlink.h#L491
NETLINK_CB(skb_out).dst_group = 0; // not in multicast group
strncpy(nlmsg_data(netlink_holder),msg,msg_size); // assign data as char* (variable msg)
result=nlmsg_unicast(sock_netlink,skb_out,pid); // send data to storage. more info: http://elixir.free-electrons.com/linux/latest/source/include/net/netlink.h#L598
if(result<0)
printk(KERN_INFO "Error while sending bak to user\n");
}
and from all that big chunk, the only thing that im interesting in is actually doing this:
result=nlmsg_unicast(sock_netlink,skb_out,pid); // send data to storage.
BUT I can't use nlmsg_unicast() without having the strcut sk_buff* which is provided automatically for me whenever there's an invoke from storage.c !
To sum up everything:
How do I send a msg from the device.ko (kernel module) to the user-space withtout having to wait for request to invoke / rely on the provided strcut sk_buff parameter from the earlier shown 'request()' method ?
Hope this sums up the point.
Thanks.
The only question here is that you need the user-space program connected to kernel-space first to get the pid of your user-program.
After get the pid, you can manually construct the skb_out and send it out through netlink_unicast or nlmsg_unicast.
The pid is always needed, you can set it as static and let your user-space program connect to your device.ko to make a long-maintained link.
Although this question is asked at 2017, I believe OP has already found the answer :D
I am developing a WiFi tool in Ubuntu Linux 12.04 environment and I need to switch the WiFi interface between different channels.
Currently I found the solution in Wireshark source code ws80211_utils.c in function called ws80211_set_freq but I do not know how to implement it into my source code and which libs to include and how to compile so I could test it.
The problem is that there are too many arguments and flags you have to use. Also, this is the first time I develop a netlink wifi tool.
If there are any good manuals available where to start and how to use netlink calls for WiFi please provide me with the link.
Thanks a lot i advance!
In current Linux versions, nl80211 is the right way to "talk" to the wireless subsystem. Be aware that you cannot arbitrarily set a channel with every driver and every operating mode (master, client, monitor etc.) Some drivers allow a channel change only when the corresponding interface is "down". In modes such as client ("managed"), the channel cannot be set at all because it is defined by the access point.
Also note that not all wireless device drivers use mac80211/cfg80211. For those drivers not using it, you either have to use the old wireless extensions API or (even worse) a driver-specific proprietary API.
Sadly, there seems to be no up-to-date and complete documentation of the nl80211 interface. Please correct me if I am wrong!
Your approach of looking into the source code of other programs seems to be a reasonable way. You could also use the source code of the iw command line utility. iw has an option to set the channel:
$ iw --help
Usage: iw [options] command
Options:
--debug enable netlink debugging
--version show version (3.2)
Commands:
…
dev <devname> set channel <channel> [HT20|HT40+|HT40-]
…
In iw's phy.c, line 91ff. you can find the code called when iw wlan0 set channel is executed. However, this code is definitely not easy to read. It looks like the
NL80211_CMD_SET_WIPHYcommand in conjunction with the NL80211_ATTR_WIPHY_FREQ attribute is the way to go.
In this SO answer you can find a skeleton program for using nl80211. Also, the code of Aircrack-ng (src/osdep/linux.c, function linux_set_channel_nl80211) could act as a blueprint.
The accepted answer is currently correct, but there's no example code posted yet which solves the OP's question (even if nearly 4 years late), so I thought I would add this here for any future search engine users. It's adapted from this SO question and the specific Aircrack-ng file (/src/aircrack-osdep/linux.c, line 1050) that were both previously mentioned.
#include <net/if.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <linux/nl80211.h>
int main(int argc, char *argv[])
{
/* The device's name and the frequency we wish to set it to. */
char *device = "wlan1";
int frequencyMhz = 2442;
/* Create the socket and connect to it. */
struct nl_sock *sckt = nl_socket_alloc();
genl_connect(sckt);
/* Allocate a new message. */
struct nl_msg *mesg = nlmsg_alloc();
/* Check /usr/include/linux/nl80211.h for a list of commands and attributes. */
enum nl80211_commands command = NL80211_CMD_SET_WIPHY;
/* Create the message so it will send a command to the nl80211 interface. */
genlmsg_put(mesg, 0, 0, genl_ctrl_resolve(sckt, "nl80211"), 0, 0, command, 0);
/* Add specific attributes to change the frequency of the device. */
NLA_PUT_U32(mesg, NL80211_ATTR_IFINDEX, if_nametoindex(device));
NLA_PUT_U32(mesg, NL80211_ATTR_WIPHY_FREQ, frequencyMhz);
/* Finally send it and receive the amount of bytes sent. */
int ret = nl_send_auto_complete(sckt, mesg);
printf("%d Bytes Sent\n", ret);
nlmsg_free(mesg);
return EXIT_SUCCESS;
nla_put_failure:
nlmsg_free(mesg);
printf("PUT Failure\n");
return EXIT_FAILURE;
}
Compile this with gcc main.c $(pkg-config --cflags --libs libnl-3.0 libnl-genl-3.0).
Once executed, check the frequency/channel of your device with e.g. iw wlan1 info or iwconfig. There's no serious error checking here, so all you will notice is if the message was sent or not. Hopefully this helps anyone like me making the transition from Wireless Extensions to cfg80211 and nl80211.
Problem: I have to configure various LCD displays to be used by Android Platform. Almost in all cases there are no electrical specifications freely available for LCD displays on interest. But through experience and reverse engineering the parameters can be guessed reasonably well. I am trying to use Loadable Kernel Modules to fine tune the display parameters (any other suggestions are welcome too). Please find the relevant information below.
HW: Atmel SAMA5D31-EK (ARM 5 processor)
SW: Andriod Linux (Target), Ubuntu (Host System), Sourcery CodeBench (Cross Compiler)
Code Snippets from board-dt.c file
static struct fb_videomode at91_tft_vga_modes[] = {
.....
.xres =435;
.yres =235;
....
}
static struct fb_monspecs at91fb_default_monspecs = {
.........
.modedb = at91_tft_vga_modes,
......
}
static struct atmel_lcd_fb_info __initdata ek_lcdc_data = {
..........
.default_monspecs = & at91fb_default_monspecs;
.........
}
I added this code so the Loadable Kernel Module has access to lcdc_data structure
extern void set_fb_video(struct fb_videomode *mg_set_tft_vga_modes)
{
ek_lcdc_data.default_monspecs->modedb->xres = mg_set_tft_vga_modes->xres;
}
EXPORT_SYMBOL(set_fb_video);
When I execute the loadable kernel module I don’t notice any change in the display. I suspect although I am changing the variable (memory) but registers are not been affected.
Question: What am I missing? I have read about making calls to platform_driver_register() and platform_driver_unregister().
Thank you for your help in advance.
I want to capture packets going out of my machine, and I'm using libpcap (version 1.0.0-1) for the same. The problem is, that a basic program like this -
#include <stdio.h>
#include <pcap.h>
int main(int argc, char *argv[]) {
char *dev, errbuf[PCAP_ERRBUF_SIZE];
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "%s\n", errbuf);
return (2);
}
printf("Device : %s\n", dev);
return (0);
}
does not seem to display the wireless interface. Everytime I compile and run the program, it detects eth0. How can I make it capture the wireless interfaces as well?
pcap_lookupdev() returns the default networking device on the system, which is usually the first device listed. pcap_findalldevs() returns an enumeration of all devices in the system, which you can use to select a device and capture from it.
try using pcap_findalldevs(). i guess pcap_lookupdev() matches the first entry in the list is suitable interfaces
As others have stated, pcap_lookupdev() simply returns the first device found. You need to use pcap_findalldevs() to build a list of all available devices, then prompt the user to pick one (or let the user specify a number n on the command line, and then use the _n_th device).
But, if this is just a quick-and-dirty test program, you can find out the interface name and code it directly into your program. You can use ifconfig or tcpdump -D to find out the interface names on your system, then make a call like pcap_create("en1", errbuf).