probe.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       probe.cc
00003 ///             USB Blackberry detection routines
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "common.h"
00023 #include "probe.h"
00024 #include "usbwrap.h"
00025 #include "data.h"
00026 #include "endian.h"
00027 #include "error.h"
00028 #include "debug.h"
00029 #include "packet.h"
00030 #include "socket.h"
00031 #include "protocol.h"
00032 #include "record-internal.h"
00033 #include "strnlen.h"
00034 #include <iomanip>
00035 #include <errno.h>
00036 #include <string.h>
00037 
00038 using namespace Usb;
00039 
00040 namespace Barry {
00041 
00042 unsigned char Intro_Sends[][32] = {
00043         // packet #1
00044         { 0x00, 0x00, 0x10, 0x00, 0x01, 0xff, 0x00, 0x00,
00045           0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
00046 };
00047 
00048 
00049 unsigned char Intro_Receives[][32] = {
00050         // response to packet #1
00051         { 0x00, 0x00, 0x10, 0x00, 0x02, 0xff, 0x00, 0x00,
00052           0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
00053 };
00054 
00055 namespace {
00056 
00057         unsigned int GetSize(const unsigned char *packet)
00058         {
00059                 uint16_t size = *((uint16_t *)&packet[2]);
00060                 return btohs(size);
00061         }
00062 
00063         bool Intro(int IntroIndex, const EndpointPair &ep, Device &dev, Data &response)
00064         {
00065                 dev.BulkWrite(ep.write, Intro_Sends[IntroIndex],
00066                         GetSize(Intro_Sends[IntroIndex]));
00067                 try {
00068                         dev.BulkRead(ep.read, response, 500);
00069                 }
00070                 catch( Usb::Timeout &to ) {
00071                         ddout("BulkRead: " << to.what());
00072                         return false;
00073                 }
00074                 ddout("BulkRead (" << (unsigned int)ep.read << "):\n" << response);
00075                 return true;
00076         }
00077 
00078 } // anonymous namespace
00079 
00080 
00081 bool Probe::CheckSize(const Data &data, unsigned int required)
00082 {
00083         const unsigned char *pd = data.GetData();
00084 
00085         if( GetSize(pd) != (unsigned int) data.GetSize() ||
00086             data.GetSize() < required ||
00087             pd[4] != SB_COMMAND_FETCHED_ATTRIBUTE )
00088         {
00089                 dout("Probe: Parse data failure: GetSize(pd): " << GetSize(pd)
00090                         << ", data.GetSize(): " << data.GetSize()
00091                         << ", pd[4]: " << (unsigned int) pd[4]);
00092                 return false;
00093         }
00094 
00095         return true;
00096 }
00097 
00098 bool Probe::ParsePIN(const Data &data, uint32_t &pin)
00099 {
00100         // validate response data
00101         const unsigned char *pd = data.GetData();
00102 
00103         if( !CheckSize(data, 0x14) )
00104                 return false;
00105 
00106         // capture the PIN
00107         pin = btohl(*((uint32_t *) &pd[16]));
00108 
00109         return true;
00110 }
00111 
00112 bool Probe::ParseDesc(const Data &data, std::string &desc)
00113 {
00114         if( !CheckSize(data, 29) )
00115                 return false;
00116 
00117         // capture the description
00118         const char *d = (const char*) &data.GetData()[28];
00119         int maxlen = data.GetSize() - 28;
00120         desc.assign(d, strnlen(d, maxlen));
00121 
00122         return true;
00123 }
00124 
00125 Probe::Probe(const char *busname, const char *devname,
00126                 const Usb::EndpointPair *epp)
00127         : m_fail_count(0)
00128         , m_epp_override(epp)
00129 {
00130         if( m_epp_override ) {
00131                 m_epp = *epp;
00132         }
00133 
00134         // let the programmer pass in "" as well as 0
00135         if( busname && !strlen(busname) )
00136                 busname = 0;
00137         if( devname && !strlen(devname) )
00138                 devname = 0;
00139 
00140         // Search for standard product ID first
00141         ProbeMatching(VENDOR_RIM, PRODUCT_RIM_BLACKBERRY, busname, devname);
00142 
00143         // Search for Pearl devices second
00144         //
00145         // productID 6 devices (PRODUCT_RIM_PEARL) do not expose
00146         // the USB class 255 interface we need, but only the
00147         // Mass Storage one.  Here we search for PRODUCT_RIM_PEARL_DUAL,
00148         // (ID 4) which has both enabled.
00149         ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_DUAL, busname, devname);
00150         // And a special case, which behaves similar to the PEARL_DUAL,
00151         // but with a unique Product ID.
00152         ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_8120, busname, devname);
00153         // And one more!  The Pearl Flip
00154         ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_FLIP, busname, devname);
00155 
00156         // And one more time, for the Blackberry Storm
00157         ProbeMatching(VENDOR_RIM, PRODUCT_RIM_STORM, busname, devname);
00158 }
00159 
00160 void Probe::ProbeMatching(int vendor, int product,
00161                         const char *busname, const char *devname)
00162 {
00163         Usb::DeviceIDType devid;
00164 
00165         Match match(vendor, product, busname, devname);
00166         while( match.next_device(&devid) ) try {
00167                 ProbeDevice(devid);
00168         }
00169         catch( Usb::Error &e ) {
00170                 dout("Usb::Error exception caught: " << e.what());
00171                 if( e.libusb_errcode() == -EBUSY ) {
00172                         m_fail_count++;
00173                         m_fail_msgs.push_back(e.what());
00174                 }
00175                 else {
00176                         throw;
00177                 }
00178         }
00179 }
00180 
00181 void Probe::ProbeDevice(Usb::DeviceIDType devid)
00182 {
00183         // skip if we can't properly discover device config
00184         DeviceDiscovery discover(devid);
00185         ConfigDesc &config = discover.configs[BLACKBERRY_CONFIGURATION];
00186 
00187         // search for interface class
00188         InterfaceDiscovery::base_type::iterator idi = config.interfaces.begin();
00189         for( ; idi != config.interfaces.end(); idi++ ) {
00190                 if( idi->second.desc.bInterfaceClass == BLACKBERRY_DB_CLASS )
00191                         break;
00192         }
00193         if( idi == config.interfaces.end() ) {
00194                 dout("Probe: Interface with BLACKBERRY_DB_CLASS ("
00195                         << BLACKBERRY_DB_CLASS << ") not found.");
00196                 return; // not found
00197         }
00198 
00199         unsigned char InterfaceNumber = idi->second.desc.bInterfaceNumber;
00200         dout("Probe: using InterfaceNumber: " << (unsigned int) InterfaceNumber);
00201 
00202         // check endpoint validity
00203         EndpointDiscovery &ed = config.interfaces[InterfaceNumber].endpoints;
00204         if( !ed.IsValid() || ed.GetEndpointPairs().size() == 0 ) {
00205                 dout("Probe: endpoint invalid.   ed.IsValud() == "
00206                         << (ed.IsValid() ? "true" : "false")
00207                         << ", ed.GetEndpointPairs().size() == "
00208                         << ed.GetEndpointPairs().size());
00209                 return;
00210         }
00211 
00212         ProbeResult result;
00213         result.m_dev = devid;
00214         result.m_interface = InterfaceNumber;
00215         result.m_zeroSocketSequence = 0;
00216 
00217         // open device
00218         Device dev(devid);
00219 //      dev.Reset();
00220 //      sleep(5);
00221 
00222         //  make sure we're talking to the right config
00223         unsigned char cfg;
00224         if( !dev.GetConfiguration(cfg) )
00225                 throw Usb::Error(dev.GetLastError(),
00226                         "Probe: GetConfiguration failed");
00227         if( cfg != BLACKBERRY_CONFIGURATION ) {
00228                 if( !dev.SetConfiguration(BLACKBERRY_CONFIGURATION) )
00229                         throw Usb::Error(dev.GetLastError(),
00230                                 "Probe: SetConfiguration failed");
00231         }
00232 
00233         // open interface
00234         Interface iface(dev, InterfaceNumber);
00235 
00236         if( m_epp_override ) {
00237                 // user has given us endpoints to try... so try them
00238                 uint32_t pin;
00239                 uint8_t zeroSocketSequence;
00240                 std::string desc;
00241                 if( ProbePair(dev, m_epp, pin, desc, zeroSocketSequence) ) {
00242                         // looks good, finish filling out the result
00243                         result.m_ep = m_epp;
00244                         result.m_pin = pin;
00245                         result.m_description = desc;
00246                         result.m_zeroSocketSequence = zeroSocketSequence;
00247                 }
00248         }
00249         else {
00250                 // find the first bulk read/write endpoint pair that answers
00251                 // to our probe commands
00252                 // Start with second pair, since evidence indicates the later pairs
00253                 // are the ones we need.
00254                 size_t i;
00255                 for(i = ed.GetEndpointPairs().size() > 1 ? 1 : 0;
00256                     i < ed.GetEndpointPairs().size();
00257                     i++ )
00258                 {
00259                         const EndpointPair &ep = ed.GetEndpointPairs()[i];
00260                         if( ep.type == USB_ENDPOINT_TYPE_BULK ) {
00261 
00262                                 uint32_t pin;
00263                                 uint8_t zeroSocketSequence;
00264                                 std::string desc;
00265                                 if( ProbePair(dev, ep, pin, desc, zeroSocketSequence) ) {
00266                                         result.m_ep = ep;
00267                                         result.m_pin = pin;
00268                                         result.m_description = desc;
00269                                         result.m_zeroSocketSequence = zeroSocketSequence;
00270                                         break;
00271                                 }
00272                         }
00273                         else {
00274                                 dout("Probe: Skipping non-bulk endpoint pair (offset: "
00275                                         << i-1 << ") ");
00276                         }
00277                 }
00278 
00279                 // check for ip modem endpoints
00280                 i++;
00281                 if( i < ed.GetEndpointPairs().size() ) {
00282                         const EndpointPair &ep = ed.GetEndpointPairs()[i];
00283                         if( ProbeModem(dev, ep) ) {
00284                                 result.m_epModem = ep;
00285                         }
00286                 }
00287         }
00288 
00289         // add to list
00290         if( result.m_ep.IsComplete() ) {
00291                 m_results.push_back(result);
00292                 ddout("Using ReadEndpoint: " << (unsigned int)result.m_ep.read);
00293                 ddout("      WriteEndpoint: " << (unsigned int)result.m_ep.write);
00294         }
00295         else {
00296                 ddout("Unable to discover endpoint pair for one device.");
00297         }
00298 }
00299 
00300 bool Probe::ProbePair(Usb::Device &dev,
00301                         const Usb::EndpointPair &ep,
00302                         uint32_t &pin,
00303                         std::string &desc,
00304                         uint8_t &zeroSocketSequence)
00305 {
00306         dev.ClearHalt(ep.read);
00307         dev.ClearHalt(ep.write);
00308 
00309         Data data;
00310         dev.BulkDrain(ep.read);
00311         if( !Intro(0, ep, dev, data) ) {
00312                 dout("Probe: Intro(0) failed");
00313                 return false;
00314         }
00315 
00316         SocketZero socket(dev, ep.write, ep.read);
00317 
00318         Data send, receive;
00319         ZeroPacket packet(send, receive);
00320 
00321         // unknown attribute: 0x14 / 0x01
00322         packet.GetAttribute(SB_OBJECT_INITIAL_UNKNOWN,
00323                 SB_ATTR_INITIAL_UNKNOWN);
00324         socket.Send(packet);
00325 
00326         // fetch PIN
00327         packet.GetAttribute(SB_OBJECT_PROFILE, SB_ATTR_PROFILE_PIN);
00328         socket.Send(packet);
00329         if( packet.ObjectID() != SB_OBJECT_PROFILE ||
00330             packet.AttributeID() != SB_ATTR_PROFILE_PIN ||
00331             !ParsePIN(receive, pin) )
00332         {
00333                 dout("Probe: unable to fetch PIN");
00334                 return false;
00335         }
00336 
00337         // fetch Description
00338         packet.GetAttribute(SB_OBJECT_PROFILE, SB_ATTR_PROFILE_DESC);
00339         socket.Send(packet);
00340         // response ObjectID does not match request... :-/
00341         if( // packet.ObjectID() != SB_OBJECT_PROFILE ||
00342             packet.AttributeID() != SB_ATTR_PROFILE_DESC ||
00343             !ParseDesc(receive, desc) )
00344         {
00345                 dout("Probe: unable to fetch description");
00346         }
00347 
00348         // more unknowns:
00349         for( uint16_t attr = 5; attr < 9; attr++ ) {
00350                 packet.GetAttribute(SB_OBJECT_SOCKET_UNKNOWN, attr);
00351                 socket.Send(packet);
00352                 // FIXME parse these responses, if they turn
00353                 // out to be important
00354         }
00355 
00356         // all info obtained!
00357         zeroSocketSequence = socket.GetZeroSocketSequence();
00358         return true;
00359 }
00360 
00361 bool Probe::ProbeModem(Usb::Device &dev, const Usb::EndpointPair &ep)
00362 {
00363         //
00364         // This check is not needed for all devices.  Some devices,
00365         // like the 8700 have both the RIM_UsbSerData mode and IpModem mode.
00366         //
00367         // If this function is called, then we have extra endpoints,
00368         // so might as well try them.
00369         //
00370         // FIXME - someday, we might wish to confirm that the endpoints
00371         // work as a modem, and return true/false based on that test.
00372         //
00373         return true;
00374 
00375 
00376 // Thanks to Rick Scott (XmBlackBerry:bb_usb.c) for reverse engineering this
00377 //      int num_read;
00378 //      char data[255];
00379 //      int local_errno;
00380 //
00381 //      num_read = usb_control_msg(dev.GetHandle(),
00382 //              /* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
00383 //              /* bRequest */ 0xa5,
00384 //              /* wValue */ 0,
00385 //              /* wIndex */ 1,
00386 //              /* data */ data,
00387 //              /* wLength */ sizeof(data),
00388 //              /* timeout */ 2000);
00389 //      local_errno = errno;
00390 //      if( num_read > 1 ) {
00391 //              if( data[0] == 0x02 ) {
00392 //                      return true;
00393 //              }
00394 //      }
00395 //      return false;
00396 }
00397 
00398 int Probe::FindActive(uint32_t pin) const
00399 {
00400         for( int i = 0; i < GetCount(); i++ ) {
00401                 if( Get(i).m_pin == pin )
00402                         return i;
00403         }
00404         if( pin == 0 ) {
00405                 // can we default to a single device?
00406                 if( GetCount() == 1 )
00407                         return 0;       // yes!
00408         }
00409 
00410         // PIN not found
00411         return -1;
00412 }
00413 
00414 void ProbeResult::DumpAll(std::ostream &os) const
00415 {
00416         os << *this
00417            << ", Interface: 0x" << std::hex << (unsigned int) m_interface
00418            << ", Endpoints: (read: 0x" << std::hex << (unsigned int) m_ep.read
00419                 << ", write: 0x" << std::hex << (unsigned int) m_ep.write
00420                 << ", type: 0x" << std::hex << (unsigned int) m_ep.type
00421            << ", ZeroSocketSequence: 0x" << std::hex << (unsigned int) m_zeroSocketSequence;
00422 }
00423 
00424 std::ostream& operator<< (std::ostream &os, const ProbeResult &pr)
00425 {
00426         os << "Device ID: " << pr.m_dev
00427            << std::hex << ". PIN: " << pr.m_pin
00428            << ", Description: " << pr.m_description;
00429         return os;
00430 }
00431 
00432 } // namespace Barry
00433 

Generated on Tue Jun 30 16:08:14 2009 for Barry by  doxygen 1.5.8