-
Notifications
You must be signed in to change notification settings - Fork 7
/
vmodem.sh
302 lines (259 loc) · 9.82 KB
/
vmodem.sh
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
#!/bin/bash
#
# --------------------------------
# VMODEM - Virtual Modem bootstrap
# --------------------------------
# Oliver Molini 2021
#
# Billy Stoughton II for bug fixes and contributions
#
# Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License
# https://creativecommons.org/licenses/by-nc-sa/4.0/
# Tested working out of box with the following client configurations:
#
# o Standard VT100 terminal
# o HyperTerminal
# o PuTTY
#
# PPP connectivity will initialize correctly under the following configurations:
#
# o Microsoft Windows 3.1
# - Trumpet Winsock
#
# o Microsoft Windows 95 OSR 2.5 + DUN 1.4
# - Generic
# - Standard 28800 bps Modem
#
# o Microsoft Windows 98
# - Generic
# - Standard 9 600 bps modem
# - Standard 33 600 bps modem
# - Standard 56 000 bps V90 modem
# - Standard 56 000 bps X2 modem
# - Standard 56 000 bps K56Flex modem
#
# Script version
vmodver=1.5.3
# CONFIGURATION
# -----------------------
# Variable: serport
# serport specifies which local serial device to use.
# For example, "ttyUSB0" will tell the script to use
# to use /dev/ttyUSB0 for communication.
# Common values: ttyUSB0 or ttyAMA0
#
serport=ttyUSB0
# Variable: baud
# baud will tell the script to open the serial port at
# specified symbol rate. When connecting, make sure
# your client computer uses the same baud than what
# has been specified here.
# Common baud rates: 9600, 19200, 38400, 57600
#
# Default:
# baud=57600
#
#baud=9600
#baud=38400
baud=57600
# Variable: etherp
# Sets the name of the ethernet device for PPP connections.
# Usually eth0 for wired and wlan0 for wireless.
#
etherp=eth0
# Variable: echoser
# echoser sets the default behaviour of echoing serial
# data back to the client terminal. The default is 1.
#
echoser=1
# Variable: resultverbose
# Controls default behavior when printing Hayes result
# codes.
# When 0, prints result codes in numerical form. (eg. 0)
# When 1, prints result codes in english. (eg. CONNECT)
# Default is 1.
resultverbose=1
# Variable: TERM
# Tells the script and environment which type of terminal to emulate.
# It is only useful to change this, if you're using a serial
# terminal to connect to this script. If you're connecting form a ANSI
# cabable machine such as DOS, you may want to use TERM="ansi"
#
TERM="vt100"
# EXPORT SHELL VARS
# -----------------
export serport
export baud
export etherp
export TERM
# FUNCTIONS
# ---------
#
#INITIALIZE SERIAL SETTINGS
ttyinit () {
stty -F /dev/$serport $baud
stty -F /dev/$serport sane
stty -F /dev/$serport raw
stty -F /dev/$serport -echo -icrnl clocal
}
# SEND MESSAGE ON SCREEN AND OVER SERIAL
sendtty () {
echo -en "$1\n";
echo -en "$1\x0d\x0a" >/dev/$serport
}
export -f sendtty
export -f ttyinit
# Open serial port for use. Allocate file descriptor
# and treat the serial port as a file.
ttyinit
exec 99<>/dev/$serport
sendtty ""
sendtty "VMODEM - Virtual Modem bootstrap for PPP link v$vmodver"
sendtty "Connection speed set to $baud baud"
sendtty ""
sendtty "TYPE HELP FOR COMMANDS"
sendtty "READY."
# MAIN LOOP
while [ "$continue" != "1" ]; do
charhex=`head -c 1 /dev/$serport | xxd -p -`
char="`echo -e "\x$charhex"`"
#ECHO SERIAL INPUT TO TTY
echo -n "$char"
#ECHO SERIAL INPUT
if [ "$echoser" = "1" ]; then echo -n "$char" > /dev/$serport; fi
#CHECK IF NEWLINE IS SENT
if [ "$charhex" = "0d" -o "$charhex" = "0a" ]; then
line=$buffer
# PARSE COMMAND
cmd=`echo -en $buffer | tr a-z A-Z`
buffer=
char=
#NEWLINE SENT - ECHO NEWLINE TO CONSOLE
if [ "$echoser" = "0" ]; then echo; fi
if [ "$echoser" = "1" ]; then sendtty; fi
#
# --- HAYES EMULATION ---
#
if [[ $cmd == AT* ]]; then
# ok, the client issued an AT command
#
# default to error result code, if command not recognized
result=4
if [[ $cmd == AT ]]; then result=0; fi
# Get hayes string
seq=`echo $cmd |cut -b3-`
# ATA
if [[ $seq == A ]]; then result=0; fi
# ATH Go on-hook, hang up.
if [[ $seq == H* ]]; then result=0; fi # H0 Go on-hook (Hang up)
if [[ $seq == H1* ]]; then result=0; fi # H1 Go off-hook
# ATZ Reset modem
if [[ $seq == Z* ]]; then echoser=1; resultverbose=1; result=0; fi # Zn Restore stored profile n
# AT&F Restore factory settings
if [[ $seq == *\&F* ]]; then echoser=1; resultverbose=1; result=0; fi # &Fn Use profile n
# ATE Command echo to host
if [[ $seq == *E* ]]; then echoser=0; result=0; fi # E0 Commands are not echoed
if [[ $seq == *E1* ]]; then echoser=1; result=0; fi # E1 Commands are echoed
# ATV Result codes in numerical or verbose form
if [[ $seq == *V* ]]; then resultverbose=0; result=0; fi # V0 Returns the code in numerical form
if [[ $seq == *V1* ]]; then resultverbose=1; result=0; fi # V1 Full-word result codes
# ATM Speaker control
if [[ $seq == *M* ]]; then result=0; fi # M0 Speaker always off
if [[ $seq == *M1* ]]; then result=0; fi # M1 Speaker on until carrier detected
if [[ $seq == *M2* ]]; then result=0; fi # M2 Speaker always on
if [[ $seq == *M3* ]]; then result=0; fi # M3 Speaker on only while answering
# AT&Cn Carrier-detect
if [[ $seq == *\&C0* ]]; then result=0; fi
if [[ $seq == *\&C1* ]]; then result=0; fi
# AT&Dn Data Terminal Ready settings
if [[ $seq == *\&D0* ]]; then result=0; fi # Modem ignores DTR
if [[ $seq == *\&D1* ]]; then result=0; fi # Go to command mode on ON-to-OFF DTR transition.
if [[ $seq == *\&D2* ]]; then result=0; fi # Hang up on DTR-drop and go to command mode
if [[ $seq == *\&D3* ]]; then result=0; fi # Reset (ATZ) on DTR-drop. Modem hangs up.
# AT&Sn DSR Override
if [[ $seq == *\&S0* ]]; then result=0; fi # &S0 DSR will remain on at all times.
if [[ $seq == *\&S1* ]]; then result=0; fi # &S1 DSR will become active after answer tone has been detected and inactive after the carrier has been lost
# ATQn Result codes
if [[ $seq == *Q0* ]]; then resultverbose=0; result=0; fi # Q0 Modem returns result codes
if [[ $seq == *Q1* ]]; then resultverbose=2; result=0; fi # Q1 Quiet mode. Modem gives no result codes.
# ATXn Extended result codes
if [[ $seq == *X0* ]]; then resultverbose=1; result=0; fi # X0 Disable extended result codes (Hayes Smartmodem 300 compatible result codes)
if [[ $seq == *X1* ]]; then resultverbose=0; result=0; fi # X1 Add connection speed to basic result codes (e.g. CONNECT 1200)
if [[ $seq == *X2* ]]; then resultverbose=0; result=0; fi # X2 Add dial tone detection (preventing blind dial, and sometimes preventing ATO)
if [[ $seq == *X3* ]]; then resultverbose=0; result=0; fi # X3 Add busy signal detection
if [[ $seq == *X4* ]]; then resultverbose=0; result=0; fi # X4 Add both busy signal and dial tone detection
# ATD Dial number
if [[ $cmd == ATD* ]]; then
# Get number, if applicable
number=`echo $seq |tr -dc '0-9'`
if [ ! -z "$number" ]; then
if [[ $resultverbose == 1 ]]; then sendtty "RINGING"; sleep 1; fi
if [ -f "$number.sh" ]; then
if [[ $resultverbose == 1 ]]; then sendtty "CONNECT $baud"; else sendtty "1"; fi
# Execute dialed script!
# For compatibility, explicitly tell the terminal to default to CR/LF
# when pressing enter, to avoid cases where the terminal just sends CR.
echo -en "\x1b[20h" > /dev/$serport
# Run script with getty
/sbin/getty -8 -L $serport $baud $TERM -n -l "./$number.sh"
# Reset serial settings
ttyinit
result=3
else
# Phone number is valid, but no internal script by that name exists
result=3
fi
else
# No number specified, return OK status code
result=0
fi
fi
#
# --- PRINT RESULT CODE ---
#
if [[ $resultverbose == 0 ]]; then
sendtty $result;
elif [[ $resultverbose == 1 ]]; then
if [[ $result == 0 ]]; then sendtty "OK"; fi
if [[ $result == 1 ]]; then sendtty "CONNECT"; fi
if [[ $result == 2 ]]; then sendtty "RING"; fi
if [[ $result == 3 ]]; then sendtty "NO CARRIER"; fi
if [[ $result == 4 ]]; then sendtty "ERROR"; fi
if [[ $result == 5 ]]; then sendtty "CONNECT 1200"; fi
if [[ $result == 6 ]]; then sendtty "NO DIALTONE"; fi
if [[ $result == 7 ]]; then sendtty "BUSY"; fi
if [[ $result == 8 ]]; then sendtty "NO ANSWER"; fi
fi
fi
if [[ $cmd = HELP ]]; then
sendtty "Command Reference for Virtual Modem Bootstrap v$vmodver"
sendtty
sendtty "AT......Tests modem link, prints OK if successful"
sendtty "ATE0....Switch terminal echo off"
sendtty "ATE1....Switch terminal echo on"
sendtty "ATD?....Fork program ?.sh and output on terminal"
sendtty "ATDT1...Open PPPD connection"
sendtty "ATZ.....Reset modem settings"
sendtty "HELP....Display command reference"
sendtty "LOGIN...Fork a new linux login on serial"
sendtty "EXIT....End this script"
sendtty
sendtty "To establish connection over PPP, dial 1 using tone dialing (ATDT1)"
sendtty
sendtty "READY."
fi
# LOGIN - FORK LOGIN SESSION
if [[ $cmd == LOGIN ]]; then
exec 99>&-
/sbin/getty -8 -L $serport $baud $TERM
ttyinit
exec 99<>/dev/$serport
sendtty; sendtty "READY."
fi
# EXIT - EXIT SCRIPT
if [ "$cmd" = "EXIT" ]; then sendtty "OK"; continue="1"; fi
fi
buffer=$buffer$char
done
#Close serial port
exec 99>&-