summaryrefslogtreecommitdiffstats
path: root/_ont/ont-huawei-ma5671a-root-web.md
blob: 8a1ee7443548a95c32657aa1cf1d14635467b4c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
---
title: Root Procedure for Huawei MA5671A (V3)
has_children: false
parent: Huawei MA5671A
layout: default
---

# Root the stick

Connect the SFP adapter to the TTL adapter according to the following diagram:

| USB TTL (UART) Adapter | wire colour in picture | SFP 20pins Molex connector |
| ---------------------- | ---------------------- | -------------------------- |
| 3.3V                   | red                    | 3.3 (pin #15 and #16)       |
| TX                     | green                  | RX (pin #2)                |
| RX                     | blue                   | TX (pin #7)                |
| GND                    | black                  | GND (pin #14)              |

{% include image.html file="web-root-procedure/ttl-sfp.jpg" alt="Example of how the molex SFP - TTL connection should look like" caption="Example of how the molex SFP - TTL connection should look like" %}

{% include image.html file="web-root-procedure/sfp-sfp.jpg" alt="Example of how the SFP - molex SFP connection should look like" caption="Example of how the SFP - molex SFP connection should look like" %}

{% include alert.html content="Try PIN 10 or other GND PINs if the connection doesn't work with PIN 14." alert="Note" icon="svg-warning" color="yellow" %}

{% include alert.html content="Some USB TTL adapters label TX and RX pins the other way around: try to swap them if the connection doesn't work." alert="Note" icon="svg-warning" color="yellow" %}

Connect the TTL adapter to the computer, once done press the following button. A window will open that will execute the root.

{: .text-center .fs-6 }
<button id="start-button" class="btn btn-blue" data-jtd-toogle="modal" data-jtd-target="#root-modal" disabled>Start root!</button>

<div id="browser-error" style="display:none">{% include alert.html content="This browser is not compatible with the web-root procedure. See the <a href='https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility'>Browser compatibility</a>" alert="Note"  icon="svg-warning" color="red" %}</div>
<noscript>
{% include alert.html content="Your browser does not support JavaScript!" alert="Note"  icon="svg-warning" color="red" %}
</noscript>


# Connect to the stick via SSH

After this is done, reboot the stick, after connecting it to the router via an ethernet mediaconverter or directly plug it in an SFP port, with the port's IP set to whatever IP of the `192.168.1.0/24` subnet (the stick has the IP `192.168.1.10`)

{% include alert.html content="If your subnet is `192.168.1.0/24` make sure you have no ip conflicts." alert="Note" icon="svg-warning" color="yellow" %}

{% include alert.html content="On some SFP host devices you might not be able to connect to the stick if there's no optical signal (RX loss), in that case you need to connect the fiber to make changes on the stick" alert="Note" icon="svg-warning" color="yellow" %}

Run the terminal and login to the stick with ssh

```shell
ssh root@192.168.1.10
```

The password is `admin123`.

{% include alert.html content="If you use a modern OpenSSH version (e.g. >= 8.8) you will have to enable some deprecated algorithms: `ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-dss root@192.168.1.10`" alert="Info" icon="svg-info" color="blue" %}

# TX Fault / Serial

The stick stays in a perpetual "TX Fault" state since the same SFP pin is used for both serial and TX Fault signaling, if that causes you issues (normally it shouldn't) you can issue the commands below to disable it. Note that it will disable both the TX Fault signal and Serial on the stick after boot.

```sh
fw_setenv asc0 1
fw_setenv preboot "gpio set 3;gpio input 100;gpio input 105;gpio input 106;gpio input 107;gpio input 108"
```

In case you need to re-enable it issue the following commands from the bootloader (FALCON)

```sh
FALCON => setenv asc0 0
FALCON => saveenv
```

<div class="modal" data-jtd-modal="root-modal" data-jtd-modal-backdrop="static" id="root-modal">
    <div class="modal-content">
        <div class="modal-header">
        <span class="close">&times;</span>
        <h2>Root status</h2>
        </div>
        <div class="modal-body" style="display:flex">
            <div class="animated" id="root-step-1"  style="width:50%" >
                <p>Step 1</p>
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
                    <circle class="path circle" fill="none" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" cx="65.1" cy="65.1" r="62.1"/>
                    <polyline class="path check success" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "/>
                    <line class="path line error" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="34.4" y1="37.9" x2="95.8" y2="92.3"/>
                    <line class="path line error" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="95.8" y1="38" x2="34.4" y2="92.2"/>
                    <line class="path line pause" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="34.4" y1="37.9" x2="95.8" y2="92.3"/>
                    <line class="path line pause" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="95.8" y1="38" x2="34.4" y2="92.2"/>
                </svg>
                <p id="root-text-step-1"></p>
            </div>
            <div class="animated" id="root-step-2" style="width:50%"  >
                <p>Step 2</p>
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
                    <circle class="path circle" fill="none" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" cx="65.1" cy="65.1" r="62.1"/>
                    <polyline class="path check success" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "/>
                    <line class="path line error" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="34.4" y1="37.9" x2="95.8" y2="92.3"/>
                    <line class="path line error" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="95.8" y1="38" x2="34.4" y2="92.2"/>
                    <line class="path line pause" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="49.4" y1="37.9" x2="49.4" y2="92.3"/>
                    <line class="path line pause" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" x1="80.8" y1="38" x2="80.8" y2="92.2"/>
                </svg>
                <p id="root-text-step-2"></p>
            </div>
        </div>
    </div>
</div>
<script>
    if ('serial' in navigator) {
        document.getElementById('start-button').disabled = false;
    } else {
        document.getElementById('browser-error').style.display = 'block';
    }
    const acontroller = new AbortController();
    const cs = acontroller.signal;
    class LineBreakTransformer {
        constructor() { 
            this.chunks = "";
        }
        transform(chunk, controller) {
            this.chunks += chunk;
            const lines = this.chunks.split("\n");
            this.chunks = lines.pop();
            lines.forEach((line) => controller.enqueue(line));
        }
        flush(controller) {
            controller.enqueue(this.chunks);
        }
    }
    let rootModal = document.getElementById("root-modal");
    let rootStep = [document.getElementById('root-step-1'),document.getElementById('root-step-2')];
    let rootStepText = [document.getElementById('root-text-step-1'), document.getElementById('root-text-step-2')];
    rootModal.addEventListener('modal-jtd-close', async function(event) {
        acontroller.abort();
    });
    rootModal.addEventListener('modal-jtd-open', async function(event) {
        root({signal: cs});
    });
    function pause(message, i) {
        rootStep[i].classList.add('pause');
        rootStep[i].classList.remove('complete');
        rootStep[i].classList.remove('loading');
        rootStep[i].classList.remove('error');
        rootStep[i].classList.remove('success');
        rootStepText[i].textContent = message;
    }
    function loading(message, i) {
        rootStep[i].classList.remove('pause');
        rootStep[i].classList.remove('complete');
        rootStep[i].classList.add('loading');
        rootStep[i].classList.remove('error');
        rootStep[i].classList.remove('success');
        rootStepText[i].textContent = message;
    }
    function showError(message, i) {
        rootStep[i].classList.remove('pause');
        rootStep[i].classList.remove('complete');
        rootStep[i].classList.remove('success');
        rootStep[i].classList.remove('loading');
        rootStep[i].classList.add('error');
        rootStepText[i].textContent = message;
    }
    function showSuccess(message, i) {
        rootStep[i].classList.remove('pause');
        rootStep[i].classList.remove('error');
        rootStep[i].classList.remove('loading');
        rootStep[i].classList.remove('complete');
        rootStep[i].classList.add('success');
        rootStepText[i].textContent = message;
    }
    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    async function waitUbootStop(writer, reader) {
        const interval = setInterval(function() {
            writer.write(String.fromCharCode(3));
        }, 10);

        while (true) {
            const { value, done } = await reader.read();

            if (value.startsWith('U-Boot')) {
                loading("Root in progress: Trigger characters received. DO NOT TOUCH THE HUAWEI MA5671A UNTIL THE PROCEDURE IS COMPLETED!",0);
                await delay(5000);
                clearInterval(interval);
                break;
            }
        }
    }
    async function checkUbootUnlocked(reader) {
        while (true) {
            try {
                const { value, done } = await Promise.race([
                    reader.read(),
                    new Promise((_, reject) => setTimeout(reject, 2000, new Error("timeout")))
                ]);

                if (value.startsWith('Press SPACE to delay and Ctrl-C to abort autoboot')) {
                    return true;
                }
            } catch (err) {
                return false;
            }
        }
    }
    async function waitFailbackShell(writer, reader) {
        while (true) {
            const { value, done } = await reader.read();

            if (value.startsWith('Press the [f] key and hit [enter] to enter failsafe mode')) {
                const interval = setInterval(function() {
                    writer.write('f\n');
                }, 10);

                loading("Root in progress: Trigger characters received. Waiting for boot to end...",1);
                await delay(3000);
                clearInterval(interval);
                break;
            }
        }

        const interval = setInterval(function() {
            writer.write(String.fromCharCode(10));
        }, 10);

        while (true) {
            const { value, done } = await reader.read();

            if (value.includes('root@(none)')) {
                await delay(1000);
                clearInterval(interval);
                break;
            }
        }
    }
    async function root({ signal } = {}) {
        loading("Waiting for the user to choose the port",0);
        pause("",1);
        let port;
        try {
            port = await navigator.serial.requestPort();
        } catch (err) {
            showError(`Error: ${err.message}`,0);
            console.log(`Error: ${err.message}\n`);
            return;
        }
        if (!port) {
            showError('Error: port not open',0);
            console.log('Error: port not open\n');
            return;
        }
        loading("Please disconnect the Huawei MA5671A from the SFP adapter if it is currently plugged in!",0);
        try {
            await port.open({ baudRate: 115200 });
        } catch (err) {
            showError(`Error: ${err.message}`,0);
            console.log(`Error: ${err.message}\n`);
            return;
        }
        const textDecoder = new TextDecoderStream();
        const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
        const reader = textDecoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();
        const textEncoderStream = new TextEncoderStream();
        const writerStreamClosed = textEncoderStream.readable.pipeTo(port.writable);
        const writer = textEncoderStream.writable.getWriter();
        try {
            await delay(10000);
            loading("Now you need to insert the Huawei MA5671A into the SFP adapter, if the procedure does not go ahead, check the connections and then remove and reconnect the Huawei MA5671A again",0);
            while(true) {
                await waitUbootStop(writer, reader);
                const ubootUnlocked = await checkUbootUnlocked(reader);

                if (ubootUnlocked == true) {
                    break;
                }

                loading("Root in progress: Set U-Boot bootdelay to 5...",0);
                writer.write('setenv bootdelay 5\n');
                await delay(1000);
                loading("Root in progress: Enable ASC serial...",0);
                writer.write('setenv asc0 0\n');
                await delay(1000);
                loading("Root in progress: Set GPIO to unlock serial...",0);
                writer.write('setenv preboot "gpio set 3;gpio input 2;gpio input 105;gpio input 106;gpio input 107;gpio input 108"\n');
                await delay(1000);
                loading("Root in progress: Save changes...",0);
                writer.write('saveenv\n');
                await delay(1000);
                loading("Root in progress: Rebooting...",0);
                writer.write('reset\n');
                await delay(1000);
            }

            loading("Root in progress: Rebooting...",0);
            writer.write('reset\n');
            await delay(1000);
            showSuccess("Congratulations! Step completed.",0);
        } catch (err) {
            showError(`Error: ${err.message}`,0);
            console.log(`Error: ${err.message}\n`);
            reader.cancel();
            await readableStreamClosed.catch(() => { /* Ignore the error */ });
            writer.close();
            await writerStreamClosed;
            await port.close();
            return;
        }
        try {
            loading("Waiting for reboot",1);
            await waitFailbackShell(writer, reader);
            loading("Root in progress: Enable full Linux shell...",1);
            writer.write('mount_root && mkdir -p /overlay/etc && sed "s|/opt/lantiq/bin/minishell|/bin/ash|g" /rom/etc/passwd > /overlay/etc/passwd\n');
            await delay(1000);
            loading("Root in progress: Umount rootfs partitions...",1);
            writer.write('umount /overlay && umount -a\n');
            await delay(1000);
            showSuccess("Congratulations! Step completed.",1);
        } catch (err) {
            showError(`Error: ${err.message}`,1);
            console.log(`Error: ${err.message}\n`);
            reader.cancel();
            await readableStreamClosed.catch(() => { /* Ignore the error */ });
            writer.close();
            await writerStreamClosed;
            await port.close();
            return;
        }

        reader.cancel();
        await readableStreamClosed.catch(() => { /* Ignore the error */ });
        writer.close();
        await writerStreamClosed;
        await port.close();
    }
</script>

# Miscellaneous Links
- [List of root procedure for Huawei MA5671A](/ont-huawei-ma5671a-root)