blob: e4d4e746ef552feff13aa16ba724a1b6ccafe60f [file] [log] [blame]
/*@file lynq-ndis-uevent.c
* @brief adb default port is closed, The uevent event of NDIS is reported to switch port.
* @author dongyu
* @date 2022-10-14
* @version V1.0
* @copyright MobileTek
*/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <include/lynq_uci.h>
#define _GNU_SOURCE
#define UEVENT_MSG_LEN 1024
#define LOG_UCI_FILE "lynq_uci"
#define LOG_UCI_MODULE "lynq_rndis"
int rndis_initiate_mode = 0;
struct uevent{
const char *action;
const char *path;
const char *subsystem;
const char *firmware;
const char *calluser;
int major;
int minor;
};
static int lynq_open_uevent_socket(void)
{
struct sockaddr_nl addr;
int sz = 64*1024;
int on = 1;
int socketfd;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;
socketfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(socketfd < 0){
return -1;
}
setsockopt(socketfd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
setsockopt(socketfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if(bind(socketfd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
close(socketfd);
return -1;
}
return socketfd;
}
static void lynq_parse_event(const char *msg, struct uevent *uevent)
{
uevent->action = "";
uevent->path = "";
uevent->subsystem = "";
uevent->firmware = "";
uevent->calluser = "";
uevent->major = -1;
uevent->minor = -1;
/* currently ignoring SEQNUM */
while(*msg){
printf("%s\n", msg);
if(!strncmp(msg, "ACTION=", 7)){
msg += 7;
uevent->action = msg;
} else if(!strncmp(msg, "DEVPATH=", 8)){
msg += 8;
uevent->path = msg;
} else if(!strncmp(msg, "SUBSYSTEM=", 10)){
msg += 10;
uevent->subsystem = msg;
} else if(!strncmp(msg, "FIRMWARE=", 9)){
msg += 9;
uevent->firmware = msg;
} else if(!strncmp(msg, "MAJOR=", 6)){
msg += 6;
uevent->major = atoi(msg);
} else if(!strncmp(msg, "MINOR=", 6)){
msg += 6;
uevent->minor = atoi(msg);
} else if(!strncmp(msg, "CALL_USER=", 10)){
msg += 10;
uevent->calluser = msg;
}
/* advance to after the next \0 */
while(*msg++);
}
printf("event { '%s', '%s', '%s', '%s', %d, %d }\n",
uevent->action, uevent->path, uevent->subsystem,
uevent->firmware, uevent->major, uevent->minor);
}
void lynq_handle_device_fd(int fd)
{
printf("enter %s\n", __func__);
for(;;) {
char msg[UEVENT_MSG_LEN+2];
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
struct iovec iov = {msg, sizeof(msg)};
struct sockaddr_nl snl;
struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};
ssize_t n = recvmsg(fd, &hdr, 0);
if (n <= 0){
break;
}
if ((snl.nl_groups != 1) || (snl.nl_pid != 0)){
/* ignoring non-kernel netlink multicast message */
continue;
}
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS){
/* no sender credentials received, ignore message */
continue;
}
struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);
if (cred->uid != 0){
/* message from non-root user, ignore */
continue;
}
if(n >= UEVENT_MSG_LEN){
/* overflow -- discard */
continue;
}
msg[n] = '\0';
msg[n+1] = '\0';
printf("2022 ::: msg = %s\n", msg);
struct uevent uevent;
lynq_parse_event(msg, &uevent);
if(strcmp(uevent.path,"/devices/virtual/android_usb/android0") == 0
&& strcmp(uevent.calluser, "/usr/bin/usb uevent reporting") == 0){
system("/usr/bin/usb_switch ets");
printf("USB login port switch successfully!\n");
while(1){
sleep(1);
}
}
}
}
int main(void)
{
int fd = 0;
char tmp[20];
fd = lynq_open_uevent_socket();
if (fd < 0){
printf("error!\n");
return -1;
}
lynq_get_value(LOG_UCI_FILE, LOG_UCI_MODULE, "initiate", tmp);
rndis_initiate_mode=atoi(tmp);
if(rndis_initiate_mode == 1){
lynq_handle_device_fd(fd);
while(1){
sleep(1);
}
}
else{
while(1){
sleep(1);
}
}
return 0;
}