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)
00064 {
00065 if( !password || strlen(password) == 0 ) {
00066 throw BadPassword("No password provided.", 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 Data data;
00072
00073 m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start));
00074 m_dev.BulkRead(read_ep, data);
00075 ddout("IPModem read packet.\n" << data);
00076
00077
00078
00079 if( data.GetSize() >= 9 && data.GetData()[0] == 0x02 &&
00080 memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag))== 0 ) {
00081
00082 ddout("IPModem password request packet:\n" << data);
00083
00084
00085 if( data.GetData()[8] < BARRY_MIN_PASSWORD_TRIES ) {
00086 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.",
00087 data.GetData()[8],
00088 true);
00089 }
00090
00091
00092 unsigned char pwdigest[SHA_DIGEST_LENGTH];
00093 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
00094 unsigned char pw_response[SHA_DIGEST_LENGTH + 8];
00095 unsigned char seed[4];
00096
00097
00098 SHA1((unsigned char *) password, strlen(password), pwdigest);
00099
00100
00101 memcpy(&seed[0], data.GetData() + 4, sizeof(uint32_t));
00102 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
00103 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
00104
00105
00106 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
00107
00108
00109 const char pw_rsphdr[] = { 0x03, 0x00, 0x00, 0x00 };
00110 memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr));
00111 memcpy(&pw_response[4], pwdigest, SHA_DIGEST_LENGTH);
00112 memcpy(&pw_response[24], special_flag, sizeof(special_flag));
00113
00114
00115 m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response));
00116 m_dev.BulkRead(read_ep, data);
00117 ddout("IPModem read password response.\n" << data);
00118
00119
00120
00121
00122 if( data.GetSize() >= 9 && data.GetData()[0] == 0x04 ) {
00123 if( memcmp(data.GetData() + 4, seed, sizeof(seed)) == 0 ) {
00124 ddout("IPModem invalid password.\n" << data);
00125 throw BadPassword("Password rejected by device.", data.GetData()[8], false);
00126 }
00127 ddout("IPModem password accepted.\n");
00128
00129 m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start));
00130
00131
00132
00133 unsigned char pw_rsphdr[] = { 0x00, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0xc2, 1, 0 };
00134 memcpy(&m_session_key[0], pwdigest + 12, sizeof(m_session_key));
00135 memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr));
00136 memcpy(&pw_response[16], pwdigest + 12, 8);
00137
00138 memcpy(&pw_response[24], special_flag, sizeof(special_flag));
00139 m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response));
00140
00141
00142 memset(pwdigest, 0, sizeof(pwdigest));
00143 memset(prefixedhash, 0, sizeof(prefixedhash));
00144
00145
00146 return true;
00147 }
00148
00149
00150 ddout("IPModem Error unknown packet.\n" << data);
00151 }
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("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 Data data;
00211
00212 const Usb::EndpointPair &pair = m_con.GetProbeResult().m_epModem;
00213 if( !pair.IsComplete() ) {
00214 std::ostringstream oss;
00215 oss << "IP Modem not supported by this device: "
00216 << "read: " << std::hex << (unsigned int) pair.read
00217 << " write: " << std::hex << (unsigned int) pair.write
00218 << " type: " << std::hex << (unsigned int) pair.type;
00219 eout(oss.str());
00220 throw Barry::Error(oss.str());
00221 }
00222
00223
00224 m_dev.ClearHalt(pair.read);
00225 m_dev.ClearHalt(pair.write);
00226
00227 if( !password || strlen(password) == 0 ) {
00228 Data block(start, sizeof(start));
00229 Write(block);
00230 }
00231 else {
00232 if( !SendPassword(password) ) {
00233 throw Barry::Error("IpModem:: Error sending password.");
00234 }
00235 }
00236
00237
00238 const char modem_command[] = { "AT\r" };
00239 m_dev.BulkWrite(write_ep, modem_command, strlen(modem_command));
00240 m_dev.BulkRead(read_ep, data);
00241 ddout("IPModem:: AT command response.\n" << data);
00242 if( data.GetSize() >= 1 ) {
00243 switch(data.GetData()[0])
00244 {
00245 case 0x02:
00246 throw BadPassword("This device requested a password.",
00247 data.GetSize() >= 9 ? data.GetData()[8] : 0, false);
00248
00249 case 0x04:
00250 break;
00251
00252 case 0x07:
00253 throw BadPassword("This device requires a password.", 0, false);
00254
00255 default:
00256 ddout("IPModem:: unknown AT command response.\n");
00257 break;
00258 }
00259 }
00260
00261
00262 m_continue_reading = true;
00263 int ret = pthread_create(&m_modem_read_thread, NULL, &IpModem::DataReadThread, this);
00264 if( ret ) {
00265 m_continue_reading = false;
00266 throw Barry::ErrnoError("IpModem:: Error creating USB read thread.", ret);
00267 }
00268 }
00269
00270 void IpModem::Write(const Data &data, int timeout)
00271 {
00272 if( data.GetSize() == 0 )
00273 return;
00274
00275
00276
00277
00278
00279 m_dev.BulkWrite(m_con.GetProbeResult().m_epModem.write,
00280 m_filter.Write(data), timeout);
00281 }
00282
00283 void IpModem::Close()
00284 {
00285
00286
00287
00288
00289
00290 unsigned char end[28];
00291 int read_ep = m_con.GetProbeResult().m_epModem.read;
00292 int write_ep = m_con.GetProbeResult().m_epModem.write;
00293 Data data;
00294
00295
00296 ddout("IpModem:: Closing connection.");
00297 memset(end, 0, sizeof(end));
00298 end[4] = 0xb0;
00299 end[13] = 0xc2;
00300 end[14] = 0x01;
00301 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00302 memcpy(&end[24], special_flag, sizeof(special_flag));
00303 m_dev.BulkWrite(write_ep, end, sizeof(end));
00304
00305
00306 memset(end, 0, sizeof(end));
00307 end[4] = 0x20;
00308 end[8] = 0x03;
00309 end[13] = 0xc2;
00310 end[14] = 0x01;
00311 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00312 memcpy(&end[24], special_flag, sizeof(special_flag));
00313 m_dev.BulkWrite(write_ep, end, sizeof(end));
00314
00315
00316
00317 memset(end, 0, sizeof(end));
00318 end[4] = 0x30;
00319 end[13] = 0xc2;
00320 end[14] = 0x01;
00321 memcpy(&end[16], m_session_key, sizeof(m_session_key));
00322 memcpy(&end[24], special_flag, sizeof(special_flag));
00323 m_dev.BulkWrite(write_ep, end, sizeof(end));
00324 m_dev.BulkWrite(write_ep, stop, sizeof(stop));
00325 try {
00326 m_dev.BulkRead(read_ep, data, 5000);
00327 ddout("IPModem:: Close read packet:\n" << data);
00328 }
00329 catch( Usb::Timeout &to ) {
00330
00331 ddout("IPModem:: Close Read Timeout");
00332 }
00333
00334 if( m_continue_reading ) {
00335 m_continue_reading = false;
00336 pthread_join(m_modem_read_thread, NULL);
00337 }
00338 ddout("IPmodem:: Closed!");
00339
00340 }
00341
00342 }}
00343