00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "m_ipmodem.h"
00024 #include "controller.h"
00025 #include "data.h"
00026 #include "debug.h"
00027 #include <sstream>
00028 #include <string.h>
00029 #include "sha1.h"
00030
00031 namespace Barry { namespace Mode {
00032
00033 const char special_flag[] = { 0x78, 0x56, 0x34, 0x12 };
00034 const char start[] = { 0x01, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 };
00035 const char pw_start[] = { 0x01, 0, 0, 0, 1, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 };
00036 const char stop[] = { 0x01, 0, 0, 0, 0, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 };
00037
00038
00039
00040
00041 IpModem::IpModem(Controller &con,
00042 DeviceDataCallback callback,
00043 void *callback_context)
00044 : m_con(con)
00045 , m_dev(con.m_dev)
00046 , m_continue_reading(false)
00047 , m_callback(callback)
00048 , m_callback_context(callback_context)
00049 {
00050 memset(m_session_key, 0, sizeof(m_session_key));
00051 }
00052
00053 IpModem::~IpModem()
00054 {
00055 try {
00056 Close();
00057 } catch( std::exception &e ) {
00058 dout("Exception caught in IpModem destructor, ignoring: "
00059 << e.what());
00060 }
00061 }
00062
00063 bool IpModem::SendPassword( const char *password, uint32_t seed )
00064 {
00065 if( !password || strlen(password) == 0 ) {
00066 throw BadPassword("Logic error: No password provided in SendPassword.", 0, false);
00067 }
00068
00069 int read_ep = m_con.GetProbeResult().m_epModem.read;
00070 int write_ep = m_con.GetProbeResult().m_epModem.write;
00071 unsigned char pwdigest[SHA_DIGEST_LENGTH];
00072 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
00073 unsigned char pw_response[SHA_DIGEST_LENGTH + 8];
00074 uint32_t new_seed;
00075 Data data;
00076
00077 if( !password || strlen(password) == 0 ) {
00078 throw BadPassword("No password provided.", 0, false);
00079 }
00080
00081
00082
00083 SHA1((unsigned char *) password, strlen(password), pwdigest);
00084
00085
00086 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
00087 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
00088
00089
00090 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
00091
00092
00093 const char pw_rsphdr[] = { 0x03, 0x00, 0x00, 0x00 };
00094 memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr));
00095 memcpy(&pw_response[4], pwdigest, SHA_DIGEST_LENGTH);
00096 memcpy(&pw_response[24], special_flag, sizeof(special_flag));
00097
00098
00099 m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response));
00100 m_dev.BulkRead(read_ep, data);
00101 ddout("IPModem: Read password response.\n" << data);
00102
00103
00104 if( data.GetSize() >= 16 && data.GetData()[0] == 0x00 ) {
00105 try {
00106 m_dev.BulkRead(read_ep, data, 500);
00107 ddout("IPModem: Null Response Packet:\n" << data);
00108 }
00109 catch( Usb::Timeout &to ) {
00110
00111 ddout("IPModem: Null Response Timeout");
00112 }
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 if( data.GetSize() >= 9 && data.GetData()[0] == 0x04 ) {
00127 memcpy(&new_seed, data.GetData() + 4, sizeof(uint32_t));
00128 seed++;
00129 if( seed == new_seed || new_seed == 0 ) {
00130 ddout("IPModem: Password accepted.\n");
00131
00132 #if SHA_DIGEST_LENGTH < SB_IPMODEM_SESSION_KEY_LENGTH
00133 #error Session key field must be smaller than SHA digest
00134 #endif
00135
00136 memcpy(&m_session_key[0],
00137 pwdigest + SHA_DIGEST_LENGTH - sizeof(m_session_key),
00138 sizeof(m_session_key));
00139
00140
00141 memset(pwdigest, 0, sizeof(pwdigest));
00142 memset(prefixedhash, 0, sizeof(prefixedhash));
00143 return true;
00144 }
00145 else {
00146 ddout("IPModem: Invalid password.\n" << data);
00147 throw BadPassword("Password rejected by device.", data.GetData()[8], false);
00148 }
00149 }
00150
00151 ddout("IPModem: Error unknown packet.\n" << data);
00152 return false;
00153 }
00154
00155
00156
00157
00158 void *IpModem::DataReadThread(void *userptr)
00159 {
00160 IpModem *ipmodem = (IpModem*) userptr;
00161
00162 int read_ep = ipmodem->m_con.GetProbeResult().m_epModem.read;
00163 Data data;
00164
00165 while( ipmodem->m_continue_reading ) {
00166
00167 try {
00168
00169 ipmodem->m_dev.BulkRead(read_ep, data, 5000);
00170
00171
00172 if( data.GetSize() > 4 &&
00173 memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag)) == 0 ) {
00174
00175 ddout("IPModem: Special packet:\n" << data);
00176 continue;
00177 }
00178
00179
00180 if( ipmodem->m_callback ) {
00181 (*ipmodem->m_callback)(ipmodem->m_callback_context,
00182 data.GetData(),
00183 data.GetSize());
00184 }
00185
00186
00187
00188
00189
00190 }
00191 catch( Usb::Timeout &to ) {
00192
00193 ddout("IPModem: Timeout in DataReadThread!");
00194 }
00195 catch( std::exception &e ) {
00196 eout("Exception in IpModem::DataReadThread: " << e.what());
00197 }
00198 }
00199
00200 return 0;
00201 }
00202
00203
00204
00205
00206 void IpModem::Open(const char *password)
00207 {
00208 int read_ep = m_con.GetProbeResult().m_epModem.read;
00209 int write_ep = m_con.GetProbeResult().m_epModem.write;
00210 unsigned char response[28];
00211 uint32_t seed;
00212 Data data;
00213
00214
00215 const Usb::EndpointPair &pair = m_con.GetProbeResult().m_epModem;
00216 if( !pair.IsComplete() ) {
00217 std::ostringstream oss;
00218 oss << "IP Modem not supported by this device: "
00219 << "read: " << std::hex << (unsigned int) pair.read
00220 << " write: " << std::hex << (unsigned int) pair.write
00221 << " type: " << std::hex << (unsigned int) pair.type;
00222 eout(oss.str());
00223 throw Barry::Error(oss.str());
00224 }
00225
00226
00227 m_dev.ClearHalt(pair.read);
00228 m_dev.ClearHalt(pair.write);
00229
00230
00231 ddout("IPModem: Sending Stop Response:\n");
00232 m_dev.BulkWrite(write_ep, stop, sizeof(stop));
00233 try {
00234 m_dev.BulkRead(read_ep, data, 500);
00235 ddout("IPModem: Stop Response Packet:\n" << data);
00236 }
00237 catch( Usb::Timeout &to ) {
00238
00239 ddout("IPModem: Stop Response Timeout");
00240 }
00241
00242
00243 ddout("IPModem: Sending Start Response:\n");
00244 m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start));
00245 m_dev.BulkRead(read_ep, data, 5000);
00246 ddout("IPModem: Start Response Packet:\n" << data);
00247
00248
00249 if( data.GetSize() >= 9 && data.GetData()[0] == 0x02 &&
00250 memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag))== 0 ) {
00251
00252 ddout("IPModem: Password request packet:\n" << data);
00253
00254
00255 if( data.GetData()[8] < BARRY_MIN_PASSWORD_TRIES ) {
00256 throw BadPassword("Fewer than " BARRY_MIN_PASSWORD_TRIES_ASC " password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device.",
00257 data.GetData()[8],
00258 true);
00259 }
00260 memcpy(&seed, data.GetData() + 4, sizeof(seed));
00261
00262 if( !SendPassword(password, seed) ) {
00263 throw Barry::Error("IpModem: Error sending password.");
00264 }
00265
00266
00267 ddout("IPModem: Re-sending Start Response:\n");
00268 m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start));
00269 m_dev.BulkRead(read_ep, data);
00270 ddout("IPModem: Start Response Packet:\n" << data);
00271 }
00272
00273
00274 unsigned char response_header[] = { 0x00, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0xc2, 1, 0 };
00275 memcpy(&response[0], response_header, sizeof(response_header));
00276 memcpy(&response[16], m_session_key, sizeof(m_session_key));
00277 memcpy(&response[24], special_flag, sizeof(special_flag));
00278 ddout("IPModem: Sending Session key:\n");
00279 m_dev.BulkWrite(write_ep, response, sizeof(response));
00280 if( data.GetSize() >= 16 ) {
00281 switch(data.GetData()[0])
00282 {
00283 case 0x00:
00284 break;
00285
00286 case 0x02:
00287 memcpy(&seed, data.GetData() + 4, sizeof(uint32_t));
00288 if( !SendPassword( password, seed ) ) {
00289 throw Barry::Error("IpModem: Error sending password.");
00290 }
00291 break;
00292 case 0x04:
00293 break;
00294
00295 default:
00296 ddout("IPModem: Unknown response.\n");
00297 break;
00298 }
00299 }
00300
00301
00302 const char modem_command[] = { "AT\r" };
00303 m_dev.BulkWrite(write_ep, modem_command, strlen(modem_command));
00304 m_dev.BulkRead(read_ep, data);
00305 ddout("IPModem: Test command response.\n" << data);
00306 if( data.GetSize() >= 1 ) {
00307 switch(data.GetData()[0])
00308 {
00309 case 0x00:
00310 try {
00311 m_dev.BulkRead(read_ep, data, 5000);
00312 ddout("IPModem: AT Response Packet:\n" << data);
00313 }
00314 catch( Usb::Timeout &to ) {
00315
00316 ddout("IPModem: AT Response Timeout");
00317 }
00318 break;
00319
00320 case 0x02:
00321 if( !password || strlen(password) == 0 ) {
00322 throw BadPassword("This device requested a password.",
00323 data.GetSize() >= 9 ? data.GetData()[8] : 0, false);
00324 }
00325 else {
00326 memcpy(&seed, data.GetData() + 4, sizeof(seed));
00327 if( !SendPassword( password, seed ) ) {
00328 throw Barry::Error("IpModem: Error sending password.");
00329 }
00330 }
00331 break;
00332 case 0x04:
00333 break;
00334
00335 case 0x07:
00336 throw BadPassword("This device requires a password.", 0, false);
00337
00338 default:
00339 ddout("IPModem: Unknown AT command response.\n");
00340 break;
00341 }
00342 }
00343 ddout("IPModem: Modem Ready.\n");
00344
00345
00346 m_continue_reading = true;
00347 int ret = pthread_create(&m_modem_read_thread, NULL, &IpModem::DataReadThread, this);
00348 if( ret ) {
00349 m_continue_reading = false;
00350 throw Barry::ErrnoError("IpModem: Error creating USB read thread.", ret);
00351 }
00352 }
00353
00354 void IpModem::Write(const Data &data, int timeout)
00355 {
00356 if( data.GetSize() == 0 )
00357 return;
00358
00359
00360
00361
00362
00363 m_dev.BulkWrite(m_con.GetProbeResult().m_epModem.write,
00364 m_filter.Write(data), timeout);
00365 }
00366
00367 void IpModem::Close()
00368 {
00369
00370
00371
00372
00373
00374 unsigned char end[28];
00375 int read_ep = m_con.GetProbeResult().m_epModem.read;
00376 int write_ep = m_con.GetProbeResult().m_epModem.write;
00377 Data data;
00378
00379
00380 ddout("IpModem: Closing connection.");
00381 memset(end, 0, sizeof(end));
00382 end[4] = 0xb0;
00383 end[13] = 0xc2;
00384 end[14] = 0x01;
00385 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00386 memcpy(&end[24], special_flag, sizeof(special_flag));
00387 m_dev.BulkWrite(write_ep, end, sizeof(end));
00388
00389
00390 memset(end, 0, sizeof(end));
00391 end[4] = 0x20;
00392 end[8] = 0x03;
00393 end[13] = 0xc2;
00394 end[14] = 0x01;
00395 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00396 memcpy(&end[24], special_flag, sizeof(special_flag));
00397 m_dev.BulkWrite(write_ep, end, sizeof(end));
00398
00399
00400
00401 memset(end, 0, sizeof(end));
00402 end[4] = 0x30;
00403 end[13] = 0xc2;
00404 end[14] = 0x01;
00405 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00406 memcpy(&end[24], special_flag, sizeof(special_flag));
00407 m_dev.BulkWrite(write_ep, end, sizeof(end));
00408 m_dev.BulkWrite(write_ep, stop, sizeof(stop));
00409 try {
00410 m_dev.BulkRead(read_ep, data, 5000);
00411 ddout("IPModem: Close read packet:\n" << data);
00412 }
00413 catch( Usb::Timeout &to ) {
00414
00415 ddout("IPModem: Close Read Timeout");
00416 }
00417
00418 if( m_continue_reading ) {
00419 m_continue_reading = false;
00420 pthread_join(m_modem_read_thread, NULL);
00421 }
00422 ddout("IPmodem: Closed!");
00423
00424 }
00425
00426 }}
00427