kernel: Disable IXP4xx physmap by default
[openwrt/staging/mkresin.git] / package / network / config / ltq-vdsl-app / src / src / dsl_cpe_ubus.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2020 Andre Heider <a.heider@gmail.com>
4 */
5
6 #include <sys/ioctl.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <fcntl.h>
10 #include <libubus.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include "dsl_cpe_control.h"
17 #include <drv_dsl_cpe_api_ioctl.h>
18 #ifdef INCLUDE_DSL_CPE_API_VRX
19 #include <drv_mei_cpe_interface.h>
20 #endif
21
22 #define U16(v1, v2) ( \
23 ((uint16_t)(v1) << 8) | \
24 ((uint16_t)(v2)))
25
26 #define U32(v1, v2, v3, v4) ( \
27 ((uint32_t)(v1) << 24) | \
28 ((uint32_t)(v2) << 16) | \
29 ((uint32_t)(v3) << 8) | \
30 ((uint32_t)(v4)))
31
32 #define STR_CASE(id, text) \
33 case id: \
34 str = text; \
35 break;
36
37 #define IOCTL(type, request) \
38 type out; \
39 memset(&out, 0, sizeof(type)); \
40 if (ioctl(fd, request, &out)) \
41 return;
42
43 #define IOCTL_DIR(type, request, dir) \
44 type out; \
45 memset(&out, 0, sizeof(type)); \
46 out.nDirection = dir; \
47 if (ioctl(fd, request, &out)) \
48 return;
49
50 #define IOCTL_DIR_DELT(type, request, dir, delt) \
51 type out; \
52 memset(&out, 0, sizeof(type)); \
53 out.nDirection = dir; \
54 out.nDeltDataType = delt; \
55 if (ioctl(fd, request, &out)) \
56 return;
57
58 typedef enum {
59 ANNEX_UNKNOWN = 0,
60 ANNEX_A,
61 ANNEX_B,
62 ANNEX_C,
63 ANNEX_I,
64 ANNEX_J,
65 ANNEX_L,
66 ANNEX_M,
67 } annex_t;
68
69 typedef enum {
70 STD_UNKNOWN = 0,
71 STD_T1_413,
72 STD_TS_101_388,
73 STD_G_992_1,
74 STD_G_992_2,
75 STD_G_992_3,
76 STD_G_992_4,
77 STD_G_992_5,
78 STD_G_993_1,
79 STD_G_993_2,
80 } standard_t;
81
82 typedef enum {
83 VECTOR_UNKNOWN = 0,
84 VECTOR_OFF,
85 VECTOR_ON_DS,
86 VECTOR_ON_DS_US,
87 } vector_t;
88
89 typedef enum {
90 PROFILE_UNKNOWN = 0,
91 PROFILE_8A,
92 PROFILE_8B,
93 PROFILE_8C,
94 PROFILE_8D,
95 PROFILE_12A,
96 PROFILE_12B,
97 PROFILE_17A,
98 PROFILE_30A,
99 PROFILE_35B,
100 } profile_t;
101
102 static DSL_CPE_ThreadCtrl_t thread;
103 static struct ubus_context *ctx;
104 static struct blob_buf b;
105
106 static inline void m_double(const char *id, double value) {
107 blobmsg_add_double(&b, id, value);
108 }
109
110 static inline void m_bool(const char *id, bool value) {
111 blobmsg_add_u8(&b, id, value);
112 }
113
114 static inline void m_u32(const char *id, uint32_t value) {
115 blobmsg_add_u32(&b, id, value);
116 }
117
118 static inline void m_str(const char *id, const char *value) {
119 blobmsg_add_string(&b, id, value);
120 }
121
122 static inline void m_db(const char *id, int value) {
123 m_double(id, (double)value / 10);
124 }
125
126 static inline void m_array(const char *id, const uint8_t *value, uint8_t len) {
127 void *c = blobmsg_open_array(&b, id);
128
129 for (uint8_t i = 0; i < len; ++i)
130 blobmsg_add_u16(&b, "", value[i]);
131
132 blobmsg_close_array(&b, c);
133 }
134
135 static void m_vendor(const char *id, const uint8_t *value) {
136 // ITU-T T.35: U.S.
137 if (U16(value[0], value[1]) != 0xb500)
138 return;
139
140 const char *str = NULL;
141 switch (U32(value[2], value[3], value[4], value[5])) {
142 STR_CASE(0x414C4342, "Alcatel")
143 STR_CASE(0x414E4456, "Analog Devices")
144 STR_CASE(0x4244434D, "Broadcom")
145 STR_CASE(0x43454E54, "Centillium")
146 STR_CASE(0x4753504E, "Globespan")
147 STR_CASE(0x494B4E53, "Ikanos")
148 STR_CASE(0x4946544E, "Infineon")
149 STR_CASE(0x54535443, "Texas Instruments")
150 STR_CASE(0x544D4D42, "Thomson MultiMedia Broadband")
151 STR_CASE(0x5443544E, "Trend Chip Technologies")
152 STR_CASE(0x53544D49, "ST Micro")
153 };
154
155 if (!str)
156 return;
157
158 if ((value[6] == 0) && (value[7] == 0)) {
159 m_str(id, str);
160 return;
161 }
162
163 char buf[64];
164 sprintf(buf, "%s %d.%d", str, value[6], value[7]);
165 m_str(id, buf);
166
167 return;
168 }
169
170 annex_t get_annex(const uint8_t *xtse) {
171 if ((xtse[0] & XTSE_1_01_A_T1_413) ||
172 (xtse[0] & XTSE_1_03_A_1_NO) ||
173 (xtse[0] & XTSE_1_04_A_1_O) ||
174 (xtse[1] & XTSE_2_01_A_2_NO) ||
175 (xtse[2] & XTSE_3_03_A_3_NO) ||
176 (xtse[2] & XTSE_3_04_A_3_O) ||
177 (xtse[3] & XTSE_4_01_A_4_NO) ||
178 (xtse[3] & XTSE_4_02_A_4_O) ||
179 (xtse[5] & XTSE_6_01_A_5_NO) ||
180 (xtse[5] & XTSE_6_02_A_5_O) ||
181 (xtse[7] & XTSE_8_01_A))
182 return ANNEX_A;
183
184 if ((xtse[0] & XTSE_1_05_B_1_NO) ||
185 (xtse[0] & XTSE_1_06_B_1_O) ||
186 (xtse[1] & XTSE_2_02_B_2_O) ||
187 (xtse[2] & XTSE_3_05_B_3_NO) ||
188 (xtse[2] & XTSE_3_06_B_3_O) ||
189 (xtse[5] & XTSE_6_03_B_5_NO) ||
190 (xtse[5] & XTSE_6_04_B_5_O) ||
191 (xtse[7] & XTSE_8_02_B))
192 return ANNEX_B;
193
194 if ((xtse[0] & XTSE_1_02_C_TS_101388) ||
195 (xtse[0] & XTSE_1_07_C_1_NO) ||
196 (xtse[0] & XTSE_1_08_C_1_O) ||
197 (xtse[1] & XTSE_2_03_C_2_NO) ||
198 (xtse[1] & XTSE_2_04_C_2_O) ||
199 (xtse[7] & XTSE_8_03_C))
200 return ANNEX_C;
201
202 if ((xtse[3] & XTSE_4_05_I_3_NO) ||
203 (xtse[3] & XTSE_4_06_I_3_O) ||
204 (xtse[4] & XTSE_5_01_I_4_NO) ||
205 (xtse[4] & XTSE_5_02_I_4_O) ||
206 (xtse[5] & XTSE_6_07_I_5_NO) ||
207 (xtse[5] & XTSE_6_08_I_5_O))
208 return ANNEX_I;
209
210 if ((xtse[3] & XTSE_4_07_J_3_NO) ||
211 (xtse[3] & XTSE_4_08_J_3_O) ||
212 (xtse[6] & XTSE_7_01_J_5_NO) ||
213 (xtse[6] & XTSE_7_02_J_5_O))
214 return ANNEX_J;
215
216 if ((xtse[4] & XTSE_5_03_L_3_NO) ||
217 (xtse[4] & XTSE_5_04_L_3_NO) ||
218 (xtse[4] & XTSE_5_05_L_3_O) ||
219 (xtse[4] & XTSE_5_06_L_3_O))
220 return ANNEX_L;
221
222 if ((xtse[4] & XTSE_5_07_M_3_NO) ||
223 (xtse[4] & XTSE_5_08_M_3_O) ||
224 (xtse[6] & XTSE_7_03_M_5_NO) ||
225 (xtse[6] & XTSE_7_04_M_5_O))
226 return ANNEX_M;
227
228 return ANNEX_UNKNOWN;
229 }
230
231 static standard_t get_standard(const uint8_t *xtse) {
232 if (xtse[0] & XTSE_1_01_A_T1_413)
233 return STD_T1_413;
234
235 if (xtse[0] & XTSE_1_02_C_TS_101388)
236 return STD_TS_101_388;
237
238 if ((xtse[0] & XTSE_1_03_A_1_NO) ||
239 (xtse[0] & XTSE_1_04_A_1_O) ||
240 (xtse[0] & XTSE_1_05_B_1_NO) ||
241 (xtse[0] & XTSE_1_06_B_1_O) ||
242 (xtse[0] & XTSE_1_07_C_1_NO) ||
243 (xtse[0] & XTSE_1_08_C_1_O))
244 return STD_G_992_1;
245
246 if ((xtse[1] & XTSE_2_01_A_2_NO) ||
247 (xtse[1] & XTSE_2_02_B_2_O) ||
248 (xtse[1] & XTSE_2_03_C_2_NO) ||
249 (xtse[1] & XTSE_2_04_C_2_O))
250 return STD_G_992_2;
251
252 if ((xtse[2] & XTSE_3_03_A_3_NO) ||
253 (xtse[2] & XTSE_3_04_A_3_O) ||
254 (xtse[2] & XTSE_3_05_B_3_NO) ||
255 (xtse[2] & XTSE_3_06_B_3_O) ||
256 (xtse[3] & XTSE_4_05_I_3_NO) ||
257 (xtse[3] & XTSE_4_06_I_3_O) ||
258 (xtse[3] & XTSE_4_07_J_3_NO) ||
259 (xtse[3] & XTSE_4_08_J_3_O) ||
260 (xtse[4] & XTSE_5_03_L_3_NO) ||
261 (xtse[4] & XTSE_5_04_L_3_NO) ||
262 (xtse[4] & XTSE_5_05_L_3_O) ||
263 (xtse[4] & XTSE_5_06_L_3_O) ||
264 (xtse[4] & XTSE_5_07_M_3_NO) ||
265 (xtse[4] & XTSE_5_08_M_3_O))
266 return STD_G_992_3;
267
268 if ((xtse[3] & XTSE_4_01_A_4_NO) ||
269 (xtse[3] & XTSE_4_02_A_4_O) ||
270 (xtse[4] & XTSE_5_01_I_4_NO) ||
271 (xtse[4] & XTSE_5_02_I_4_O))
272 return STD_G_992_4;
273
274 if ((xtse[5] & XTSE_6_01_A_5_NO) ||
275 (xtse[5] & XTSE_6_02_A_5_O) ||
276 (xtse[5] & XTSE_6_03_B_5_NO) ||
277 (xtse[5] & XTSE_6_04_B_5_O) ||
278 (xtse[5] & XTSE_6_07_I_5_NO) ||
279 (xtse[5] & XTSE_6_08_I_5_O) ||
280 (xtse[6] & XTSE_7_01_J_5_NO) ||
281 (xtse[6] & XTSE_7_02_J_5_O) ||
282 (xtse[6] & XTSE_7_03_M_5_NO) ||
283 (xtse[6] & XTSE_7_04_M_5_O))
284 return STD_G_992_5;
285
286 if (xtse[7] & XTSE_8_08)
287 return STD_G_993_1;
288
289 if ((xtse[7] & XTSE_8_01_A) ||
290 (xtse[7] & XTSE_8_02_B) ||
291 (xtse[7] & XTSE_8_03_C))
292 return STD_G_993_2;
293
294 return STD_UNKNOWN;
295 }
296
297 static void version_information(int fd) {
298 IOCTL(DSL_VersionInformation_t, DSL_FIO_VERSION_INFORMATION_GET)
299
300 m_str("api_version", out.data.DSL_DriverVersionApi);
301 m_str("firmware_version", out.data.DSL_ChipSetFWVersion);
302 m_str("chipset", out.data.DSL_ChipSetType);
303 m_str("driver_version", out.data.DSL_DriverVersionMeiBsp);
304 }
305
306 static void line_state(int fd) {
307 IOCTL(DSL_LineState_t, DSL_FIO_LINE_STATE_GET)
308
309 const char *str;
310 switch (out.data.nLineState) {
311 STR_CASE(DSL_LINESTATE_NOT_INITIALIZED, "Not initialized")
312 STR_CASE(DSL_LINESTATE_EXCEPTION, "Exception")
313 STR_CASE(DSL_LINESTATE_NOT_UPDATED, "Not updated")
314 STR_CASE(DSL_LINESTATE_IDLE_REQUEST, "Idle request")
315 STR_CASE(DSL_LINESTATE_IDLE, "Idle")
316 STR_CASE(DSL_LINESTATE_SILENT_REQUEST, "Silent request")
317 STR_CASE(DSL_LINESTATE_SILENT, "Silent")
318 STR_CASE(DSL_LINESTATE_HANDSHAKE, "Handshake")
319 STR_CASE(DSL_LINESTATE_BONDING_CLR, "Bonding CLR")
320 STR_CASE(DSL_LINESTATE_FULL_INIT, "Full init")
321 STR_CASE(DSL_LINESTATE_SHORT_INIT_ENTRY, "Short init entry")
322 STR_CASE(DSL_LINESTATE_DISCOVERY, "Discovery")
323 STR_CASE(DSL_LINESTATE_TRAINING, "Training")
324 STR_CASE(DSL_LINESTATE_ANALYSIS, "Analysis")
325 STR_CASE(DSL_LINESTATE_EXCHANGE, "Exchange")
326 STR_CASE(DSL_LINESTATE_SHOWTIME_NO_SYNC, "Showtime without TC-Layer sync")
327 STR_CASE(DSL_LINESTATE_SHOWTIME_TC_SYNC, "Showtime with TC-Layer sync")
328 STR_CASE(DSL_LINESTATE_FASTRETRAIN, "Fastretrain")
329 STR_CASE(DSL_LINESTATE_LOWPOWER_L2, "Lowpower L2")
330 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_ACTIVE, "Loopdiagnostic active")
331 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_EXCHANGE, "Loopdiagnostic data exchange")
332 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_REQUEST, "Loopdiagnostic data request")
333 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_COMPLETE, "Loopdiagnostic complete")
334 STR_CASE(DSL_LINESTATE_RESYNC, "Resync")
335 STR_CASE(DSL_LINESTATE_TEST, "Test")
336 STR_CASE(DSL_LINESTATE_TEST_LOOP, "Test loop")
337 STR_CASE(DSL_LINESTATE_TEST_REVERB, "Test reverb")
338 STR_CASE(DSL_LINESTATE_TEST_MEDLEY, "Test medley")
339 STR_CASE(DSL_LINESTATE_TEST_SHOWTIME_LOCK, "Showtime lock")
340 STR_CASE(DSL_LINESTATE_TEST_QUIET, "Quiet")
341 STR_CASE(DSL_LINESTATE_LOWPOWER_L3, "Lowpower L3")
342 #ifndef INCLUDE_DSL_CPE_API_DANUBE
343 STR_CASE(DSL_LINESTATE_DISABLED, "Disabled")
344 STR_CASE(DSL_LINESTATE_T1413, "T1413")
345 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN_REQUEST, "Orderly shutdown request")
346 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN, "Orderly shutdown")
347 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_ACTIVE, "Test filterdetection active")
348 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_COMPLETE, "Test filterdetection complete")
349 #endif
350 default:
351 str = NULL;
352 break;
353 };
354 if (str)
355 m_str("state", str);
356
357 m_bool("up", out.data.nLineState == DSL_LINESTATE_SHOWTIME_TC_SYNC);
358 }
359
360 static void pm_channel_counters_showtime(int fd) {
361 IOCTL_DIR(DSL_PM_ChannelCounters_t, DSL_FIO_PM_CHANNEL_COUNTERS_SHOWTIME_GET, DSL_NEAR_END);
362
363 m_u32("uptime", out.interval.nElapsedTime);
364 }
365
366 static void g997_line_inventory(int fd) {
367 IOCTL_DIR(DSL_G997_LineInventory_t, DSL_FIO_G997_LINE_INVENTORY_GET, DSL_DOWNSTREAM)
368
369 m_array("vendor_id", out.data.G994VendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
370 m_vendor("vendor", out.data.G994VendorID);
371 m_array("system_vendor_id", out.data.SystemVendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
372 m_vendor("system_vendor", out.data.SystemVendorID);
373 m_array("version", out.data.VersionNumber, DSL_G997_LI_MAXLEN_VERSION);
374 m_array("serial", out.data.SerialNumber, DSL_G997_LI_MAXLEN_SERIAL);
375 }
376
377 static void g997_power_management_status(int fd) {
378 IOCTL(DSL_G997_PowerManagementStatus_t, DSL_FIO_G997_POWER_MANAGEMENT_STATUS_GET)
379
380 const char *str;
381 switch (out.data.nPowerManagementStatus) {
382 STR_CASE(DSL_G997_PMS_NA, "Power management state is not available")
383 STR_CASE(DSL_G997_PMS_L0, "L0 - Synchronized")
384 STR_CASE(DSL_G997_PMS_L1, "L1 - Power Down Data transmission (G.992.2)")
385 STR_CASE(DSL_G997_PMS_L2, "L2 - Power Down Data transmission (G.992.3 and G.992.4)")
386 STR_CASE(DSL_G997_PMS_L3, "L3 - No power")
387 default:
388 str = NULL;
389 break;
390 };
391 if (str)
392 m_str("power_state", str);
393 }
394
395 static void g997_xtu_system_enabling(int fd, standard_t *standard) {
396 IOCTL(DSL_G997_XTUSystemEnabling_t, DSL_FIO_G997_XTU_SYSTEM_ENABLING_STATUS_GET)
397
398 m_array("xtse", out.data.XTSE, DSL_G997_NUM_XTSE_OCTETS);
399
400 const char *str;
401 switch (get_annex(out.data.XTSE)) {
402 STR_CASE(ANNEX_A, "A")
403 STR_CASE(ANNEX_B, "B")
404 STR_CASE(ANNEX_C, "C")
405 STR_CASE(ANNEX_I, "I")
406 STR_CASE(ANNEX_J, "J")
407 STR_CASE(ANNEX_L, "L")
408 STR_CASE(ANNEX_M, "M")
409 default:
410 str = NULL;
411 break;
412 };
413 if (str)
414 m_str("annex", str);
415
416 *standard = get_standard(out.data.XTSE);
417
418 switch (*standard) {
419 STR_CASE(STD_T1_413, "T1.413")
420 STR_CASE(STD_TS_101_388, "TS 101 388")
421 STR_CASE(STD_G_992_1, "G.992.1")
422 STR_CASE(STD_G_992_2, "G.992.2")
423 STR_CASE(STD_G_992_3, "G.992.3")
424 STR_CASE(STD_G_992_4, "G.992.4")
425 STR_CASE(STD_G_992_5, "G.992.5")
426 STR_CASE(STD_G_993_1, "G.993.1")
427 STR_CASE(STD_G_993_2, "G.993.2")
428 default:
429 str = NULL;
430 break;
431 }
432 if (str)
433 m_str("standard", str);
434 }
435
436 static vector_t get_vector_status() {
437 #ifdef INCLUDE_DSL_CPE_API_VRX
438 int fd = open(DSL_CPE_DSL_LOW_DEV "/0", O_RDWR, 0644);
439 if (fd < 0)
440 return VECTOR_UNKNOWN;
441
442 IOCTL_MEI_dsmStatus_t out;
443 memset(&out, 0, sizeof(IOCTL_MEI_dsmStatus_t));
444 int ret = ioctl(fd, FIO_MEI_DSM_STATUS_GET, &out);
445 close(fd);
446
447 if (ret)
448 return VECTOR_UNKNOWN;
449
450 switch (out.eVectorStatus) {
451 case e_MEI_VECTOR_STAT_OFF:
452 return VECTOR_OFF;
453 case e_MEI_VECTOR_STAT_ON_DS:
454 return VECTOR_ON_DS;
455 case e_MEI_VECTOR_STAT_ON_DS_US:
456 return VECTOR_ON_DS_US;
457 default:
458 return VECTOR_UNKNOWN;
459 };
460 #else
461 return VECTOR_UNKNOWN;
462 #endif
463 }
464
465 static void band_plan_status(int fd, profile_t *profile) {
466 #if (INCLUDE_DSL_CPE_API_VDSL_SUPPORT == 1)
467 IOCTL(DSL_BandPlanStatus_t, DSL_FIO_BAND_PLAN_STATUS_GET)
468
469 switch (out.data.nProfile) {
470 case DSL_PROFILE_8A:
471 *profile = PROFILE_8A;
472 break;
473 case DSL_PROFILE_8B:
474 *profile = PROFILE_8B;
475 break;
476 case DSL_PROFILE_8C:
477 *profile = PROFILE_8C;
478 break;
479 case DSL_PROFILE_8D:
480 *profile = PROFILE_8D;
481 break;
482 case DSL_PROFILE_12A:
483 *profile = PROFILE_12A;
484 break;
485 case DSL_PROFILE_12B:
486 *profile = PROFILE_12B;
487 break;
488 case DSL_PROFILE_17A:
489 *profile = PROFILE_17A;
490 break;
491 case DSL_PROFILE_30A:
492 *profile = PROFILE_30A;
493 break;
494 case DSL_PROFILE_35B:
495 *profile = PROFILE_35B;
496 break;
497 default:
498 *profile = PROFILE_UNKNOWN;
499 break;
500 };
501
502 const char *str;
503 switch (*profile) {
504 STR_CASE(PROFILE_8A, "8a")
505 STR_CASE(PROFILE_8B, "8b")
506 STR_CASE(PROFILE_8C, "8c")
507 STR_CASE(PROFILE_8D, "8d")
508 STR_CASE(PROFILE_12A, "12a")
509 STR_CASE(PROFILE_12B, "12b")
510 STR_CASE(PROFILE_17A, "17a")
511 STR_CASE(PROFILE_30A, "30a")
512 STR_CASE(PROFILE_35B, "35b")
513 default:
514 str = NULL;
515 break;
516 };
517 if (str)
518 m_str("profile", str);
519 #endif
520 }
521
522 static void line_feature_config(int fd, DSL_AccessDir_t direction) {
523 IOCTL_DIR(DSL_LineFeature_t, DSL_FIO_LINE_FEATURE_STATUS_GET, direction)
524
525 m_bool("trellis", out.data.bTrellisEnable);
526 m_bool("bitswap", out.data.bBitswapEnable);
527 m_bool("retx", out.data.bReTxEnable);
528 m_bool("virtual_noise", out.data.bVirtualNoiseSupport);
529 }
530
531 static void g997_channel_status(int fd, DSL_AccessDir_t direction) {
532 IOCTL_DIR(DSL_G997_ChannelStatus_t, DSL_FIO_G997_CHANNEL_STATUS_GET, direction);
533
534 m_u32("interleave_delay", out.data.ActualInterleaveDelay * 10);
535 #ifndef INCLUDE_DSL_CPE_API_DANUBE
536 // prefer ACTNDR, see comments in drv_dsl_cpe_api_g997.h
537 m_u32("data_rate", out.data.ActualNetDataRate);
538 #else
539 m_u32("data_rate", out.data.ActualDataRate);
540 #endif
541 }
542
543 static void g997_line_status(int fd, DSL_AccessDir_t direction) {
544 IOCTL_DIR_DELT(DSL_G997_LineStatus_t, DSL_FIO_G997_LINE_STATUS_GET, direction, DSL_DELT_DATA_SHOWTIME);
545
546 m_db("latn", out.data.LATN);
547 m_db("satn", out.data.SATN);
548 m_db("snr", out.data.SNR);
549 m_db("actps", out.data.ACTPS);
550 m_db("actatp", out.data.ACTATP);
551 m_u32("attndr", out.data.ATTNDR);
552 }
553
554 static void pm_line_sec_counters_total(int fd, DSL_XTUDir_t direction) {
555 IOCTL_DIR(DSL_PM_LineSecCountersTotal_t, DSL_FIO_PM_LINE_SEC_COUNTERS_TOTAL_GET, direction)
556
557 m_u32("es", out.data.nES);
558 m_u32("ses", out.data.nSES);
559 m_u32("loss", out.data.nLOSS);
560 m_u32("uas", out.data.nUAS);
561 m_u32("lofs", out.data.nLOFS);
562 #ifndef INCLUDE_DSL_CPE_API_DANUBE
563 m_u32("fecs", out.data.nFECS);
564 #endif
565 }
566
567 static void pm_data_path_counters_total(int fd, DSL_XTUDir_t direction) {
568 IOCTL_DIR(DSL_PM_DataPathCountersTotal_t, DSL_FIO_PM_DATA_PATH_COUNTERS_TOTAL_GET, direction);
569
570 m_u32("hec", out.data.nHEC);
571 m_u32("ibe", out.data.nIBE);
572 m_u32("crc_p", out.data.nCRC_P);
573 m_u32("crcp_p", out.data.nCRCP_P);
574 m_u32("cv_p", out.data.nCV_P);
575 m_u32("cvp_p", out.data.nCVP_P);
576 }
577
578 static void retx_statistics(int fd, DSL_XTUDir_t direction) {
579 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
580 #ifdef INCLUDE_DSL_CPE_PM_RETX_THRESHOLDS
581 IOCTL_DIR(DSL_ReTxStatistics_t, DSL_FIO_RETX_STATISTICS_GET, direction);
582
583 m_u32("rx_corrupted", out.data.nRxCorruptedTotal);
584 m_u32("rx_uncorrected_protected", out.data.nRxUncorrectedProtected);
585 m_u32("rx_retransmitted", out.data.nRxRetransmitted);
586 m_u32("rx_corrected", out.data.nRxCorrected);
587 m_u32("tx_retransmitted", out.data.nTxRetransmitted);
588 #endif
589 #endif
590 }
591
592 static void describe_mode(standard_t standard, profile_t profile, vector_t vector) {
593 char buf[128];
594
595 switch (standard) {
596 case STD_T1_413:
597 strcpy(buf, "T1.413");
598 break;
599 case STD_TS_101_388:
600 strcpy(buf, "TS 101 388");
601 break;
602 case STD_G_992_1:
603 strcpy(buf, "G.992.1 (ADSL)");
604 break;
605 case STD_G_992_2:
606 strcpy(buf, "G.992.2 (ADSL lite)");
607 break;
608 case STD_G_992_3:
609 strcpy(buf, "G.992.3 (ADSL2)");
610 break;
611 case STD_G_992_4:
612 strcpy(buf, "G.992.4 (ADSL2 lite)");
613 break;
614 case STD_G_992_5:
615 strcpy(buf, "G.992.5 (ADSL2+)");
616 break;
617 case STD_G_993_1:
618 strcpy(buf, "G.993.1 (VDSL)");
619 break;
620 case STD_G_993_2:
621 strcpy(buf, "G.993.2 (VDSL2");
622
623 switch (profile) {
624 case PROFILE_8A:
625 strcat(buf, ", Profile 8a");
626 break;
627 case PROFILE_8B:
628 strcat(buf, ", Profile 8b");
629 break;
630 case PROFILE_8C:
631 strcat(buf, ", Profile 8c");
632 break;
633 case PROFILE_8D:
634 strcat(buf, ", Profile 8d");
635 break;
636 case PROFILE_12A:
637 strcat(buf, ", Profile 12a");
638 break;
639 case PROFILE_12B:
640 strcat(buf, ", Profile 12b");
641 break;
642 case PROFILE_17A:
643 strcat(buf, ", Profile 17a");
644 break;
645 case PROFILE_30A:
646 strcat(buf, ", Profile 30a");
647 break;
648 case PROFILE_35B:
649 strcat(buf, ", Profile 35b");
650 break;
651 default:
652 break;
653 };
654
655 switch (vector) {
656 case VECTOR_ON_DS:
657 strcat(buf, ", with downstream vectoring");
658 break;
659 case VECTOR_ON_DS_US:
660 strcat(buf, ", with down- and upstream vectoring");
661 break;
662 default:
663 break;
664 };
665
666 strcat(buf, ")");
667 break;
668 default:
669 return;
670 };
671
672 m_str("mode", buf);
673 }
674
675 static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
676 struct ubus_request_data *req, const char *method,
677 struct blob_attr *msg)
678 {
679 int fd;
680 void *c, *c2;
681 standard_t standard = STD_UNKNOWN;
682 profile_t profile = PROFILE_UNKNOWN;
683 vector_t vector = VECTOR_UNKNOWN;
684
685 #ifndef INCLUDE_DSL_CPE_API_DANUBE
686 fd = open(DSL_CPE_DEVICE_NAME "0", O_RDWR, 0644);
687 #else
688 fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
689 #endif
690 if (fd < 0)
691 return UBUS_STATUS_UNKNOWN_ERROR;
692
693 blob_buf_init(&b, 0);
694
695 version_information(fd);
696 line_state(fd);
697 pm_channel_counters_showtime(fd);
698
699 c = blobmsg_open_table(&b, "atu_c");
700 g997_line_inventory(fd);
701 blobmsg_close_table(&b, c);
702
703 g997_power_management_status(fd);
704 g997_xtu_system_enabling(fd, &standard);
705
706 if (standard == STD_G_993_2) {
707 band_plan_status(fd, &profile);
708 vector = get_vector_status();
709 }
710
711 describe_mode(standard, profile, vector);
712
713 c = blobmsg_open_table(&b, "upstream");
714 switch (vector) {
715 case VECTOR_OFF:
716 m_bool("vector", false);
717 break;
718 case VECTOR_ON_DS_US:
719 m_bool("vector", true);
720 break;
721 default:
722 break;
723 };
724 line_feature_config(fd, DSL_UPSTREAM);
725 g997_channel_status(fd, DSL_UPSTREAM);
726 g997_line_status(fd, DSL_UPSTREAM);
727 blobmsg_close_table(&b, c);
728
729 c = blobmsg_open_table(&b, "downstream");
730 switch (vector) {
731 case VECTOR_OFF:
732 m_bool("vector", false);
733 break;
734 case VECTOR_ON_DS:
735 case VECTOR_ON_DS_US:
736 m_bool("vector", true);
737 break;
738 default:
739 break;
740 };
741 line_feature_config(fd, DSL_DOWNSTREAM);
742 g997_channel_status(fd, DSL_DOWNSTREAM);
743 g997_line_status(fd, DSL_DOWNSTREAM);
744 blobmsg_close_table(&b, c);
745
746 c = blobmsg_open_table(&b, "errors");
747 c2 = blobmsg_open_table(&b, "near");
748 pm_line_sec_counters_total(fd, DSL_NEAR_END);
749 pm_data_path_counters_total(fd, DSL_NEAR_END);
750 retx_statistics(fd, DSL_NEAR_END);
751 blobmsg_close_table(&b, c2);
752
753 c2 = blobmsg_open_table(&b, "far");
754 pm_line_sec_counters_total(fd, DSL_FAR_END);
755 pm_data_path_counters_total(fd, DSL_FAR_END);
756 retx_statistics(fd, DSL_FAR_END);
757 blobmsg_close_table(&b, c2);
758 blobmsg_close_table(&b, c);
759
760 ubus_send_reply(ctx, req, b.head);
761
762 close(fd);
763
764 return 0;
765 }
766
767 static const struct ubus_method dsl_methods[] = {
768 UBUS_METHOD_NOARG("metrics", metrics),
769 };
770
771 static struct ubus_object_type dsl_object_type =
772 UBUS_OBJECT_TYPE("dsl", dsl_methods);
773
774 static struct ubus_object dsl_object = {
775 .name = "dsl",
776 .type = &dsl_object_type,
777 .methods = dsl_methods,
778 .n_methods = ARRAY_SIZE(dsl_methods),
779 };
780
781 static DSL_int_t ubus_main(DSL_CPE_Thread_Params_t *params) {
782 uloop_run();
783 return 0;
784 }
785
786 void ubus_init() {
787 uloop_init();
788
789 ctx = ubus_connect(NULL);
790 if (!ctx)
791 return;
792
793 if (ubus_add_object(ctx, &dsl_object)) {
794 ubus_free(ctx);
795 ctx = NULL;
796 return;
797 }
798
799 ubus_add_uloop(ctx);
800
801 DSL_CPE_ThreadInit(&thread, "ubus", ubus_main, DSL_CPE_PIPE_STACK_SIZE, DSL_CPE_PIPE_PRIORITY, 0, 0);
802 }
803
804 void ubus_deinit() {
805 if (!ctx)
806 return;
807
808 ubus_free(ctx);
809 uloop_done();
810
811 DSL_CPE_ThreadShutdown(&thread, 1000);
812 }