/* * Copyright 2011, 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #define LOG_GROUP LogGroup::GPRS // Can set Log.Level.GPRS for debugging #include "Defines.h" #include "GPRSInternal.h" // For GPRSLOG() #include "GSMConfig.h" #include "Threads.h" #include "BSSGMessages.h" #include "BSSG.h" #include "Utils.h" #include "errno.h" #include #include #if INTERNAL_SGSN == 0 namespace BSSG { BSSGMain gBSSG; const unsigned rbufSize = 3000; // Much bigger than any PDU message. #if _UNUSED_ static int BSTLVParse(ByteType *data, int &rp, IEIType::type expected_ieitype, int expected_length) { int received_ieitype = data[rp++]; int received_length = data[rp++]; if (received_ieitype != expected_ieitype || received_length != expected_length) { int bstype = data[NSMsg::UnitDataHeaderLen]; LOG(ERR) << "Error in BSSG msg type="<BSS request reset everything. // Dont know what we should do about reset. BSSGWriteLowSide(BVCFactory(BSPDUType::BVC_RESET_ACK,0)); break; case BSSG::BSPDUType::BVC_RESET_ACK: // BSS->network and network->BSS? break; case BSSG::BSPDUType::BVC_UNBLOCK: BSSGWriteLowSide(BVCFactory(BSPDUType::BVC_UNBLOCK_ACK,0)); break; case BSSG::BSPDUType::BVC_UNBLOCK_ACK: break; // We ignore all these: case BSSG::BSPDUType::SUSPEND_ACK: // network->MS ACK case BSSG::BSPDUType::SUSPEND_NACK: // network->MS NACK case BSSG::BSPDUType::RESUME_ACK: // network->MS ACK case BSSG::BSPDUType::RESUME_NACK: // network->MS NACK case BSSG::BSPDUType::FLUSH_LL: // newtork->BSS forget this MS (it moved to another cell.) case BSSG::BSPDUType::SGSN_INVOKE_TRACE: // network->BSS request trace an MS LOG(WARNING) << "Unimplemented BSSG message:" << BSPDUType::name(bstype); return; case BSSG::BSPDUType::SUSPEND: // MS->network request to suspend GPRS service. case BSSG::BSPDUType::RESUME: // MS->network request to resume GPRS service. case BSSG::BSPDUType::FLUSH_LL_ACK: // BSS->network case BSSG::BSPDUType::LLC_DISCARDED: // BSS->network notification of lost PDUs (probably expired) LOG(ERR) << "Invalid BSSG message:" << BSPDUType::name(bstype); return; } } void NsRecvMsg(unsigned char *data, int nsize) { NSPDUType::type nstype = (NSPDUType::type) data[0]; // We dont need to see all the keep alive messages. if (nstype != NSPDUType::NS_UNITDATA) { GPRSLOG(4) << "BSSG NsRecvMsg "<str() <mbsIsOpen = true; int failures = 0; while (bssgp->mbsIsOpen && ++failures < 10) { ssize_t rsize = recv(bssgp->mbsSGSockfd,buf,rbufSize,0); if (rsize > 0) { failures = 0; NsRecvMsg(buf,rsize); } else if (rsize == -1) { LOG(ERR) << "Received -1 from BSSG recv(), error:"<mbsIsOpen = false; // Send a message to the sendServiceLoop so that it will notice // we have died and die also. BSSGWriteLowSide(NsFactory(NSPDUType::NS_BLOCK)); return NULL; } // The send probably does not need to be in a separate thread. // We could also have used a select or poll system call. // But it was easier to use two threads. // OLD: Send this loop an NS_BLOCK message to kill this thread off; // and we dont normally use that NS message. // There is a BSSG-level BVC_BLOCK message that we would use to do a temporary data block. void *sendServiceLoop(void *arg) { BSSGMain *bssgp = (BSSGMain*)arg; NSPDUType::type nstype = NSPDUType::NS_RESET; // init to anything. do { NSMsg *ulmsg = bssgp->mbsTxQ.read(); // It is already wrapped up in an NS protocol. int msgsize = ulmsg->size(); ssize_t result = send(bssgp->mbsSGSockfd,ulmsg->begin(),msgsize,0); nstype = ulmsg->getNSPDUType(); int debug_level = 1; //(nstype == NSPDUType::NS_UNITDATA) ? 1 : 4; if (GPRS::GPRSDebug & debug_level) { GPRSLOG(debug_level) << "BSSG ===> sendServiceLoop sent " <str()<mbsIsOpen /*&& nstype != NSPDUType::NS_BLOCK*/); return NULL; } static int opensock(uint32_t sgsnIp, int sgsnPort /*,int bssgPort*/ ) { //int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sockfd < 0) { LOG(ERR) << "Could not create socket for BSSGP"; return -1; } /****** { // We dont want to bind here. connect will pick a port for us. int32_t bssgIp = INADDR_ANY; struct sockaddr_in myAddr; memset(&myAddr,0,sizeof(myAddr)); // be safe. myAddr.sin_family = AF_INET; myAddr.sin_addr.s_addr = htonl(bssgIp); myAddr.sin_port = htons(bssgPort); if (0 != bind(sockfd,(sockaddr*)&myAddr,sizeof(myAddr))) { LOG(ERR) << "Could not bind NS socket to" << LOGVAR(bssgIp) << LOGVAR(bssgPort) << LOGVAR(errno); close(sockfd); return -1; } } ****/ struct sockaddr_in sgsnAddr; memset(&sgsnAddr,0,sizeof(sgsnAddr)); sgsnAddr.sin_family = AF_INET; sgsnAddr.sin_addr.s_addr = sgsnIp; // This is already in network order. sgsnAddr.sin_port = htons(sgsnPort); if (0 != connect(sockfd,(sockaddr*)&sgsnAddr,sizeof(sgsnAddr))) { LOG(ERR) << "Could not connect NS socket to" << LOGVAR(sgsnIp) << LOGVAR(sgsnPort) << LOGVAR(errno); close(sockfd); return -1; } else { GPRSLOG(1) << "connected to SGSN at "<< inet_ntoa(sgsnAddr.sin_addr) <<" port "<= 40) { // wait 4 seconds GPRSLOG(1) << LOGVAR(mbsResetReceived) <write(ulmsg); } else { GPRSLOG(1) << "BSSG ===> writelowside " <str()<