2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
3 * Distributed under the terms of the MIT License.
8 #include "ModemDevice.h"
9 #include "ACFCHandler.h"
12 #include <core_funcs.h>
18 #include <settings_tools.h>
22 static char sDigits
[] = "0123456789ABCDEF";
24 dump_packet(struct mbuf
*packet
)
29 uint8
*data
= mtod(packet
, uint8
*);
31 uint8 bufferIndex
= 0;
33 TRACE("Dumping packet;len=%ld;pkthdr.len=%d\n", packet
->m_len
,
34 packet
->m_flags
& M_PKTHDR
? packet
->m_pkthdr
.len
: -1);
36 for(uint32 index
= 0; index
< packet
->m_len
; index
++) {
37 buffer
[bufferIndex
++] = sDigits
[data
[index
] >> 4];
38 buffer
[bufferIndex
++] = sDigits
[data
[index
] & 0x0F];
39 if(bufferIndex
== 32 || index
== packet
->m_len
- 1) {
40 buffer
[bufferIndex
] = 0;
41 TRACE("%s\n", buffer
);
50 modem_put_line(int32 handle
, const char *string
, int32 length
)
56 sprintf(line
, "%s\r", string
);
57 return write(handle
, line
, length
+ 1);
62 modem_get_line(int32 handle
, char *string
, int32 length
, const char *echo
)
64 if(!string
|| length
< 40)
67 int32 result
, position
= 0;
69 while(position
< length
) {
70 result
= read(handle
, string
+ position
, 1);
73 else if(result
== 1) {
74 if(string
[position
] == '\r') {
76 if(!strcasecmp(string
, echo
)) {
94 worker_thread(void *data
)
96 ModemDevice
*device
= (ModemDevice
*) data
;
97 int32 handle
= device
->Handle();
98 uint8 buffer
[MODEM_MTU
];
101 if(modem_put_line(handle
, device
->InitString(), strlen(device
->InitString())) < 0
102 || modem_get_line(handle
, (char*) buffer
, sizeof(buffer
),
103 device
->InitString()) < 0
104 || strcmp((char*) buffer
, "OK")) {
105 device
->FailedDialing();
110 if(modem_put_line(handle
, device
->DialString(), strlen(device
->DialString())) < 0
111 || modem_get_line(handle
, (char*) buffer
, sizeof(buffer
),
112 device
->DialString()) < 0
113 || strncmp((char*) buffer
, "CONNECT", 7)) {
114 device
->FailedDialing();
118 if(strlen((char*) buffer
) > 8)
119 device
->SetSpeed(atoi((char*) buffer
+ 8));
121 device
->SetSpeed(19200);
123 // TODO: authenticate if needed
125 device
->FinishedDialing();
128 int32 length
= 0, position
= 0;
129 bool inPacket
= true, needsEscape
= false;
132 // ignore data if buffer is full
133 if(position
== MODEM_MTU
)
136 length
= read(handle
, buffer
+ position
, MODEM_MTU
- position
);
138 if(length
< 0 || !device
->IsUp()) {
139 device
->ConnectionLost();
144 for(int32 index
= 0; index
< length
; ) {
145 if(buffer
[position
] == FLAG_SEQUENCE
) {
146 if(inPacket
&& position
> 0)
147 device
->DataReceived(buffer
, position
);
148 // DataReceived() will check FCS
150 length
= length
- index
- 1;
151 // remaining data length
152 memmove(buffer
, buffer
+ position
+ 1, length
);
153 position
= index
= 0;
160 if(buffer
[position
+ index
] < 0x20) {
166 buffer
[position
] = buffer
[position
+ index
] ^ 0x20;
169 } else if(buffer
[position
+ index
] == CONTROL_ESCAPE
) {
173 buffer
[position
] = buffer
[position
+ index
];
181 ModemDevice::ModemDevice(KPPPInterface
& interface
, driver_parameter
*settings
)
182 : KPPPDevice("Modem", 0, interface
, settings
),
190 TRACE("ModemDevice: Constructor\n");
191 if(!settings
|| !settings
->parameters
)
192 TRACE("ModemDevice::ctor: No settings!\n");
195 fACFC
= new ACFCHandler(REQUEST_ACFC
| ALLOW_ACFC
, interface
);
196 if(!interface
.LCP().AddOptionHandler(fACFC
)) {
197 fInitStatus
= B_ERROR
;
201 interface
.SetPFCOptions(PPP_REQUEST_PFC
| PPP_ALLOW_PFC
);
205 // MTU size does not contain PPP header
207 fPortName
= get_parameter_value(MODEM_PORT_KEY
, settings
);
208 fInitString
= get_parameter_value(MODEM_INIT_KEY
, settings
);
209 fDialString
= get_parameter_value(MODEM_DIAL_KEY
, settings
);
211 TRACE("ModemDevice::ctor: interfaceName: %s\n", fPortName
);
215 ModemDevice::~ModemDevice()
217 TRACE("ModemDevice: Destructor\n");
222 ModemDevice::InitCheck() const
224 if(fState
!= INITIAL
&& Handle() == -1)
227 return PortName() && InitString() && DialString()
228 && KPPPDevice::InitCheck() == B_OK
? B_OK
: B_ERROR
;
235 TRACE("ModemDevice: Up()\n");
237 if(InitCheck() != B_OK
)
246 // check if we are allowed to go up now (user intervention might disallow that)
251 // there was no error
258 if(fWorkerThread
== -1) {
259 fWorkerThread
= spawn_kernel_thread(worker_thread
, "Modem: worker_thread",
260 B_NORMAL_PRIORITY
, this);
261 resume_thread(fWorkerThread
);
271 TRACE("ModemDevice: Down()\n");
273 if(InitCheck() != B_OK
)
276 fState
= TERMINATING
;
286 // this tells StateMachine that DownEvent() does not mean we lost connection
288 // worker_thread will notice that we are terminating (IsUp() == false)
289 // ConnectionLost() will be called so we can terminate the connection there.
291 wait_for_thread(fWorkerThread
, &tmp
);
300 ModemDevice::SetSpeed(uint32 bps
)
302 fInputTransferRate
= bps
/ 8;
303 fOutputTransferRate
= (fInputTransferRate
* 60) / 100;
304 // 60% of input transfer rate
309 ModemDevice::InputTransferRate() const
311 return fInputTransferRate
;
316 ModemDevice::OutputTransferRate() const
318 return fOutputTransferRate
;
323 ModemDevice::CountOutputBytes() const
330 ModemDevice::OpenModem()
335 fHandle
= open(PortName(), O_RDWR
);
338 struct termios options
;
339 if(ioctl(fHandle
, TCGETA
, &options
) != B_OK
) {
340 ERROR("ModemDevice: Could not retrieve port options!\n");
345 options
.c_cflag
&= ~CBAUD
;
346 options
.c_cflag
|= B115200
;
347 options
.c_cflag
|= (CLOCAL
| CREAD
);
348 options
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ISIG
);
349 options
.c_oflag
&= ~OPOST
;
350 options
.c_cc
[VMIN
] = 0;
351 options
.c_cc
[VTIME
] = 10;
354 if(ioctl(fHandle
, TCSETA
, &options
) != B_OK
) {
355 ERROR("ModemDevice: Could not init port!\n");
362 ModemDevice::CloseModem()
372 ModemDevice::FinishedDialing()
381 ModemDevice::FailedDialing()
391 ModemDevice::ConnectionLost()
393 // switch to command mode and disconnect
396 snooze(ESCAPE_DELAY
);
397 if(write(Handle(), ESCAPE_SEQUENCE
, strlen(ESCAPE_SEQUENCE
)) < 0)
399 snooze(ESCAPE_DELAY
);
401 modem_put_line(Handle(), AT_HANG_UP
, strlen(AT_HANG_UP
));
407 ModemDevice::Send(struct mbuf
*packet
, uint16 protocolNumber
)
410 TRACE("ModemDevice: Send()\n");
416 else if(InitCheck() != B_OK
|| protocolNumber
!= 0) {
421 return PPP_NO_CONNECTION
;
424 // we might need room for our header
425 if(fACFC
->LocalState() != ACFC_ACCEPTED
) {
426 M_PREPEND(packet
, 2);
431 int32 position
= 0, length
;
432 if(packet
->m_flags
& M_PKTHDR
)
433 length
= packet
->m_pkthdr
.len
;
435 length
= packet
->m_len
;
437 // we need a contiguous chunk of memory
438 packet
= m_pullup(packet
, length
);
442 uint8 buffer
[2 * (MODEM_MTU
+ PACKET_OVERHEAD
)], *data
= mtod(packet
, uint8
*);
445 if(fACFC
->LocalState() != ACFC_ACCEPTED
) {
446 data
[0] = ALL_STATIONS
;
452 fcs
= pppfcs16(fcs
, data
, length
);
454 data
[length
++] = fcs
& 0x00ff;
455 data
[length
++] = (fcs
& 0xff00) >> 8;
458 buffer
[position
++] = FLAG_SEQUENCE
;
459 // mark beginning of packet
460 for(int32 index
= 0; index
< length
; index
++) {
461 if(data
[index
] < 0x20 || data
[index
] == FLAG_SEQUENCE
462 || data
[index
] == CONTROL_ESCAPE
) {
463 buffer
[position
++] = CONTROL_ESCAPE
;
464 buffer
[position
++] = data
[index
] ^ 0x20;
466 buffer
[position
++] = data
[index
];
468 buffer
[position
++] = FLAG_SEQUENCE
;
469 // mark end of packet
474 atomic_add((int32
*) &fOutputBytes
, position
);
475 if(write(Handle(), buffer
, position
) < 0)
476 return PPP_NO_CONNECTION
;
477 atomic_add((int32
*) &fOutputBytes
, -position
);
484 ModemDevice::DataReceived(uint8
*buffer
, uint32 length
)
486 // TODO: report corrupted packets to KPPPInterface
493 fcs
= pppfcs16(fcs
, buffer
, length
- 2);
495 if(buffer
[length
- 2] != fcs
& 0x00ff || buffer
[length
- 1] != (fcs
& 0xff00) >> 8)
498 if(buffer
[0] == ALL_STATIONS
&& buffer
[1] == UI
)
501 mbuf
*packet
= m_gethdr(MT_DATA
);
502 packet
->m_len
= packet
->m_pkthdr
.len
= length
- 2;
503 uint8
*data
= mtod(packet
, uint8
*);
504 memcpy(data
, buffer
, length
- 2);
506 return Receive(packet
);
511 ModemDevice::Receive(struct mbuf
*packet
, uint16 protocolNumber
)
513 // we do not need to lock because only the worker_thread calls this method
517 else if(InitCheck() != B_OK
|| !IsUp()) {
522 return Interface().ReceiveFromDevice(packet
);