1 | /* -*- c-basic-offset: 8 -*-
|
---|
2 | rdesktop: A Remote Desktop Protocol client.
|
---|
3 | Support for the Matrox "lspci" channel
|
---|
4 | Copyright (C) 2005 Matrox Graphics Inc.
|
---|
5 | Copyright 2018 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
---|
6 |
|
---|
7 | This program is free software: you can redistribute it and/or modify
|
---|
8 | it under the terms of the GNU General Public License as published by
|
---|
9 | the Free Software Foundation, either version 3 of the License, or
|
---|
10 | (at your option) any later version.
|
---|
11 |
|
---|
12 | This program is distributed in the hope that it will be useful,
|
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | GNU General Public License for more details.
|
---|
16 |
|
---|
17 | You should have received a copy of the GNU General Public License
|
---|
18 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 |
|
---|
21 | /*
|
---|
22 | * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
|
---|
23 | * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
|
---|
24 | * the General Public License version 2 (GPLv2) at this time for any software where
|
---|
25 | * a choice of GPL license versions is made available with the language indicating
|
---|
26 | * that GPLv2 or any later version may be used, or where a choice of which version
|
---|
27 | * of the GPL is applied is otherwise unspecified.
|
---|
28 | */
|
---|
29 |
|
---|
30 | #include "rdesktop.h"
|
---|
31 | #include <sys/types.h>
|
---|
32 | #include <unistd.h>
|
---|
33 |
|
---|
34 | static VCHANNEL *lspci_channel;
|
---|
35 |
|
---|
36 | typedef struct _pci_device
|
---|
37 | {
|
---|
38 | uint16 klass;
|
---|
39 | uint16 vendor;
|
---|
40 | uint16 device;
|
---|
41 | uint16 subvendor;
|
---|
42 | uint16 subdevice;
|
---|
43 | uint8 revision;
|
---|
44 | uint8 progif;
|
---|
45 | } pci_device;
|
---|
46 |
|
---|
47 | static pci_device current_device;
|
---|
48 |
|
---|
49 | static void lspci_send(const char *output);
|
---|
50 |
|
---|
51 |
|
---|
52 | /* Handle one line of output from the lspci subprocess */
|
---|
53 | static RD_BOOL
|
---|
54 | handle_child_line(const char *line, void *data)
|
---|
55 | {
|
---|
56 | const char *val;
|
---|
57 | char buf[1024];
|
---|
58 |
|
---|
59 | if (str_startswith(line, "Class:"))
|
---|
60 | {
|
---|
61 | val = line + sizeof("Class:");
|
---|
62 | /* Skip whitespace and second Class: occurance */
|
---|
63 | val += strspn(val, " \t") + sizeof("Class");
|
---|
64 | current_device.klass = strtol(val, NULL, 16);
|
---|
65 | }
|
---|
66 | else if (str_startswith(line, "Vendor:"))
|
---|
67 | {
|
---|
68 | val = line + sizeof("Vendor:");
|
---|
69 | current_device.vendor = strtol(val, NULL, 16);
|
---|
70 | }
|
---|
71 | else if (str_startswith(line, "Device:"))
|
---|
72 | {
|
---|
73 | val = line + sizeof("Device:");
|
---|
74 | /* Sigh, there are *two* lines tagged as Device:. We
|
---|
75 | are not interested in the domain/bus/slot/func */
|
---|
76 | if (!strchr(val, ':'))
|
---|
77 | current_device.device = strtol(val, NULL, 16);
|
---|
78 | }
|
---|
79 | else if (str_startswith(line, "SVendor:"))
|
---|
80 | {
|
---|
81 | val = line + sizeof("SVendor:");
|
---|
82 | current_device.subvendor = strtol(val, NULL, 16);
|
---|
83 | }
|
---|
84 | else if (str_startswith(line, "SDevice:"))
|
---|
85 | {
|
---|
86 | val = line + sizeof("SDevice:");
|
---|
87 | current_device.subdevice = strtol(val, NULL, 16);
|
---|
88 | }
|
---|
89 | else if (str_startswith(line, "Rev:"))
|
---|
90 | {
|
---|
91 | val = line + sizeof("Rev:");
|
---|
92 | current_device.revision = strtol(val, NULL, 16);
|
---|
93 | }
|
---|
94 | else if (str_startswith(line, "ProgIf:"))
|
---|
95 | {
|
---|
96 | val = line + sizeof("ProgIf:");
|
---|
97 | current_device.progif = strtol(val, NULL, 16);
|
---|
98 | }
|
---|
99 | else if (strspn(line, " \t") == strlen(line))
|
---|
100 | {
|
---|
101 | /* Blank line. Send collected information over channel */
|
---|
102 | snprintf(buf, sizeof(buf), "%04x,%04x,%04x,%04x,%04x,%02x,%02x\n",
|
---|
103 | current_device.klass, current_device.vendor,
|
---|
104 | current_device.device, current_device.subvendor,
|
---|
105 | current_device.subdevice, current_device.revision, current_device.progif);
|
---|
106 | lspci_send(buf);
|
---|
107 | memset(¤t_device, 0, sizeof(current_device));
|
---|
108 | }
|
---|
109 | else
|
---|
110 | {
|
---|
111 | warning("lspci: Unrecoqnized line '%s'\n", line);
|
---|
112 | }
|
---|
113 | return True;
|
---|
114 | }
|
---|
115 |
|
---|
116 |
|
---|
117 | /* Process one line of input from virtual channel */
|
---|
118 | static RD_BOOL
|
---|
119 | lspci_process_line(const char *line, void *data)
|
---|
120 | {
|
---|
121 | char *lspci_command[5] = { "lspci", "-m", "-n", "-v", NULL };
|
---|
122 |
|
---|
123 | if (!strcmp(line, "LSPCI"))
|
---|
124 | {
|
---|
125 | memset(¤t_device, 0, sizeof(current_device));
|
---|
126 | subprocess(lspci_command, handle_child_line, NULL);
|
---|
127 | /* Send single dot to indicate end of enumeration */
|
---|
128 | lspci_send(".\n");
|
---|
129 | }
|
---|
130 | else
|
---|
131 | {
|
---|
132 | error("lspci protocol error: Invalid line '%s'\n", line);
|
---|
133 | }
|
---|
134 | return True;
|
---|
135 | }
|
---|
136 |
|
---|
137 |
|
---|
138 | /* Process new data from the virtual channel */
|
---|
139 | static void
|
---|
140 | lspci_process(STREAM s)
|
---|
141 | {
|
---|
142 | unsigned int pkglen;
|
---|
143 | static char *rest = NULL;
|
---|
144 | char *buf;
|
---|
145 | struct stream packet = *s;
|
---|
146 |
|
---|
147 | if (!s_check(s))
|
---|
148 | {
|
---|
149 | rdp_protocol_error("lspci_process(), stream is in unstable state", &packet);
|
---|
150 | }
|
---|
151 |
|
---|
152 | pkglen = s->end - s->p;
|
---|
153 | /* str_handle_lines requires null terminated strings */
|
---|
154 | buf = xmalloc(pkglen + 1);
|
---|
155 | STRNCPY(buf, (char *) s->p, pkglen + 1);
|
---|
156 | #if 0
|
---|
157 | printf("lspci recv:\n");
|
---|
158 | hexdump(s->p, pkglen);
|
---|
159 | #endif
|
---|
160 |
|
---|
161 | str_handle_lines(buf, &rest, lspci_process_line, NULL);
|
---|
162 | xfree(buf);
|
---|
163 | }
|
---|
164 |
|
---|
165 | /* Initialize this module: Register the lspci channel */
|
---|
166 | RD_BOOL
|
---|
167 | lspci_init(void)
|
---|
168 | {
|
---|
169 | lspci_channel =
|
---|
170 | channel_register("lspci", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
|
---|
171 | lspci_process);
|
---|
172 | return (lspci_channel != NULL);
|
---|
173 | }
|
---|
174 |
|
---|
175 | /* Send data to channel */
|
---|
176 | static void
|
---|
177 | lspci_send(const char *output)
|
---|
178 | {
|
---|
179 | STREAM s;
|
---|
180 | size_t len;
|
---|
181 |
|
---|
182 | len = strlen(output);
|
---|
183 | s = channel_init(lspci_channel, len);
|
---|
184 | out_uint8p(s, output, len) s_mark_end(s);
|
---|
185 |
|
---|
186 | #if 0
|
---|
187 | printf("lspci send:\n");
|
---|
188 | hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
|
---|
189 | #endif
|
---|
190 |
|
---|
191 | channel_send(s, lspci_channel);
|
---|
192 | }
|
---|