1 #include <err.h>
2 #include <errno.h>
3 #include <libgen.h>
4 #include <linux/qrtr.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12 
13 #include "libqrtr.h"
14 #include "logging.h"
15 #include "ns.h"
16 #include "util.h"
17 
18 #define DIAG_SERVICE 4097
19 
20 static const struct {
21 	unsigned int service;
22 	unsigned int ifilter;
23 	const char *name;
24 } common_names[] = {
25 	{ 0, 0, "Control service" },
26 	{ 1, 0, "Wireless Data Service" },
27 	{ 2, 0, "Device Management Service" },
28 	{ 3, 0, "Network Access Service" },
29 	{ 4, 0, "Quality Of Service service" },
30 	{ 5, 0, "Wireless Messaging Service" },
31 	{ 6, 0, "Position Determination Service" },
32 	{ 7, 0, "Authentication service" },
33 	{ 8, 0, "AT service" },
34 	{ 9, 0, "Voice service" },
35 	{ 10, 0, "Card Application Toolkit service (v2)" },
36 	{ 11, 0, "User Identity Module service" },
37 	{ 12, 0, "Phonebook Management service" },
38 	{ 13, 0, "QCHAT service" },
39 	{ 14, 0, "Remote file system service" },
40 	{ 15, 0, "Test service" },
41 	{ 16, 0, "Location service (~ PDS v2)" },
42 	{ 17, 0, "Specific absorption rate service" },
43 	{ 18, 0, "IMS settings service" },
44 	{ 19, 0, "Analog to digital converter driver service" },
45 	{ 20, 0, "Core sound driver service" },
46 	{ 21, 0, "Modem embedded file system service" },
47 	{ 22, 0, "Time service" },
48 	{ 23, 0, "Thermal sensors service" },
49 	{ 24, 0, "Thermal mitigation device service" },
50 	{ 25, 0, "Service access proxy service" },
51 	{ 26, 0, "Wireless data administrative service" },
52 	{ 27, 0, "TSYNC control service" },
53 	{ 28, 0, "Remote file system access service" },
54 	{ 29, 0, "Circuit switched videotelephony service" },
55 	{ 30, 0, "Qualcomm mobile access point service" },
56 	{ 31, 0, "IMS presence service" },
57 	{ 32, 0, "IMS videotelephony service" },
58 	{ 33, 0, "IMS application service" },
59 	{ 34, 0, "Coexistence service" },
60 	{ 36, 0, "Persistent device configuration service" },
61 	{ 38, 0, "Simultaneous transmit service" },
62 	{ 39, 0, "Bearer independent transport service" },
63 	{ 40, 0, "IMS RTP service" },
64 	{ 41, 0, "RF radiated performance enhancement service" },
65 	{ 42, 0, "Data system determination service" },
66 	{ 43, 0, "Subsystem control service" },
67 	{ 47, 0, "Data Port Mapper service" },
68 	{ 49, 0, "IPA control service" },
69 	{ 51, 0, "CoreSight remote tracing service" },
70 	{ 52, 0, "Dynamic Heap Memory Sharing" },
71 	{ 64, 0, "Service registry locator service" },
72 	{ 66, 0, "Service registry notification service" },
73 	{ 69, 0, "ATH10k WLAN firmware service" },
74 	{ 224, 0, "Card Application Toolkit service (v1)" },
75 	{ 225, 0, "Remote Management Service" },
76 	{ 226, 0, "Open Mobile Alliance device management service" },
77 	{ 312, 0, "QBT1000 Ultrasonic Fingerprint Sensor service" },
78 	{ 769, 0, "SLIMbus control service" },
79 	{ 771, 0, "Peripheral Access Control Manager service" },
80 	{ 4096, 0, "TFTP" },
81 	{ DIAG_SERVICE, 0, "DIAG service" },
82 };
83 
diag_instance_base_str(unsigned int instance_base)84 static const char *diag_instance_base_str(unsigned int instance_base)
85 {
86 	switch (instance_base) {
87 		case 0: return "MODEM";
88 		case 1: return "LPASS";
89 		case 2: return "WCNSS";
90 		case 3: return "SENSORS";
91 		case 4: return "CDSP";
92 		case 5: return "WDSP";
93 		default: return "<unk>";
94 	}
95 }
96 
diag_instance_str(unsigned int instance)97 static const char *diag_instance_str(unsigned int instance)
98 {
99 	switch (instance) {
100 		case 0: return "CNTL";
101 		case 1: return "CMD";
102 		case 2: return "DATA";
103 		case 3: return "DCI_CMD";
104 		case 4: return "DCI";
105 		default: return "<unk>";
106 	}
107 }
108 
get_diag_instance_info(char * str,size_t size,unsigned int instance)109 static int get_diag_instance_info(char *str, size_t size, unsigned int instance)
110 {
111 	return snprintf(str, size, "%s:%s",
112 			diag_instance_base_str(instance >> 6),
113 			diag_instance_str(instance & 0x3f));
114 }
115 
read_num_le(const char * str,int * rcp)116 static unsigned int read_num_le(const char *str, int *rcp)
117 {
118 	unsigned int ret;
119 	char *e;
120 
121 	if (*rcp)
122 		return 0;
123 
124 	errno = 0;
125 	ret = strtoul(str, &e, 0);
126 	*rcp = -(errno || *e);
127 
128 	return cpu_to_le32(ret);
129 }
130 
main(int argc,char ** argv)131 int main(int argc, char **argv)
132 {
133 	struct qrtr_ctrl_pkt pkt;
134 	struct sockaddr_qrtr sq;
135 	unsigned int instance;
136 	unsigned int service;
137 	unsigned int version;
138 	unsigned int node;
139 	unsigned int port;
140 	socklen_t sl = sizeof(sq);
141 	struct timeval tv;
142 	int sock;
143 	int len;
144 	int rc;
145 	const char *progname = basename(argv[0]);
146 
147 	qlog_setup(progname, false);
148 
149 	rc = 0;
150 	memset(&pkt, 0, sizeof(pkt));
151 
152 	switch (argc) {
153 	default:
154 		rc = -1;
155 		break;
156 	case 3: pkt.server.instance = read_num_le(argv[2], &rc);
157 	case 2: pkt.server.service = read_num_le(argv[1], &rc);
158 	case 1: break;
159 	}
160 	if (rc) {
161 		fprintf(stderr, "Usage: %s [<service> [<instance> [<filter>]]]\n", progname);
162 		exit(1);
163 	}
164 
165 	sock = socket(AF_QIPCRTR, SOCK_DGRAM, 0);
166 	if (sock < 0)
167 		PLOGE_AND_EXIT("sock(AF_QIPCRTR)");
168 
169 	rc = getsockname(sock, (void *)&sq, &sl);
170 	if (rc || sq.sq_family != AF_QIPCRTR || sl != sizeof(sq))
171 		PLOGE_AND_EXIT("getsockname()");
172 
173 	sq.sq_port = QRTR_PORT_CTRL;
174 
175 	tv.tv_sec = 1;
176 	tv.tv_usec = 0;
177 
178 	pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_LOOKUP);
179 
180 	rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
181 	if (rc)
182 		PLOGE_AND_EXIT("setsockopt(SO_RCVTIMEO)");
183 
184 	rc = sendto(sock, &pkt, sizeof(pkt), 0, (void *)&sq, sizeof(sq));
185 	if (rc < 0)
186 		PLOGE_AND_EXIT("sendto()");
187 
188 	printf("  Service Version Instance Node  Port\n");
189 
190 	while ((len = recv(sock, &pkt, sizeof(pkt), 0)) > 0) {
191 		unsigned int type = le32_to_cpu(pkt.cmd);
192 		const char *name = NULL;
193 		unsigned int i;
194 
195 		if (len < sizeof(pkt) || type != QRTR_TYPE_NEW_SERVER) {
196 			PLOGW("invalid/short packet");
197 			continue;
198 		}
199 
200 		if (!pkt.server.service && !pkt.server.instance &&
201 		    !pkt.server.node && !pkt.server.port)
202 			break;
203 
204 		service = le32_to_cpu(pkt.server.service);
205 		version = le32_to_cpu(pkt.server.instance) & 0xff;
206 		instance = le32_to_cpu(pkt.server.instance) >> 8;
207 		node = le32_to_cpu(pkt.server.node);
208 		port = le32_to_cpu(pkt.server.port);
209 
210 		for (i = 0; i < sizeof(common_names)/sizeof(common_names[0]); ++i) {
211 			if (service != common_names[i].service)
212 				continue;
213 			if (instance &&
214 			   (instance & common_names[i].ifilter) != common_names[i].ifilter)
215 				continue;
216 			name = common_names[i].name;
217 		}
218 		if (!name)
219 			name = "<unknown>";
220 
221 		if (service == DIAG_SERVICE) {
222 			char buf[24];
223 			instance = le32_to_cpu(pkt.server.instance);
224 			get_diag_instance_info(buf, sizeof(buf), instance);
225 			printf("%9d %7s %8d %4d %5d %s (%s)\n",
226 				service, "N/A", instance, node, port, name, buf);
227 		} else {
228 			printf("%9d %7d %8d %4d %5d %s\n",
229 				service, version, instance, node, port, name);
230 		}
231 	}
232 
233 	if (len < 0)
234 		PLOGE_AND_EXIT("recv()");
235 
236 	close(sock);
237 
238 	return 0;
239 }
240