// (pat 9-2014) Print out peering messages. We triage the messages depending on the log level. // INFO level - Handover messages only. // DEBUG level - all messages. static void logMessage(const char*sendOrRecv, const struct sockaddr_in* peer, const char *message) { const char *arg1 = getPeeringMsgArg1(message); if (0 == strncmp(arg1,"HANDOVER",8)) { LOG(INFO) << "Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message); // We used to watch everything except REQ NEI messages: if (strncmp(message,"REQ NEI",7)) const char *eol = strchr(message,'\n'); WATCHLEVEL(INFO," Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR2("message",string(message,eol?eol-message:strlen(message)))); // first line of message; they used to be long. } else { // At DEBUG level log all messages. LOG(DEBUG) << "Peering "<<sendOrRecv<<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message); } }
PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(IPv4Address ipAddr) { LOG_DEBUG("Searching all live devices..."); for(std::vector<PcapLiveDevice*>::iterator devIter = m_LiveDeviceList.begin(); devIter != m_LiveDeviceList.end(); devIter++) { LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_Name); for(std::vector<pcap_addr_t>::iterator addrIter = (*devIter)->m_Addresses.begin(); addrIter != (*devIter)->m_Addresses.end(); addrIter++) { if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) { char addrAsString[INET6_ADDRSTRLEN]; sockaddr2string(addrIter->addr, addrAsString); LOG_DEBUG("Searching address %s", addrAsString); } in_addr* currAddr = sockaddr2in_addr(addrIter->addr); if (currAddr == NULL) { LOG_DEBUG("Address is NULL"); continue; } if (currAddr->s_addr == ipAddr.toInAddr()->s_addr) { LOG_DEBUG("Found matched address!"); return (*devIter); } } } return NULL; }
void PeerInterface::process(const struct sockaddr_in* peer, const char* message) { logMessage("receive",peer,message); // neighbor message? if (strncmp(message+3," NEIGHBOR_PARAMS",16)==0) return processNeighborParams(peer,message); // must be handover related string peerString = sockaddr2string(peer, true); LOG(INFO) << "received from"<<LOGVAR2("peer",peerString) <<LOGVAR(message); // Initial inbound handover request? if (strncmp(message,"REQ HANDOVER ",13)==0) return processHandoverRequest(peer,message); // Handover response? ("Handover Accept" in the ladder.) if (strncmp(message,"RSP HANDOVER ",13)==0) return processHandoverResponse(peer,message); // IND HANDOVER_COMPLETE if (strncmp(message,"IND HANDOVER_COMPLETE ", 22)==0) return processHandoverComplete(peer,message); // IND HANDOVER_FAILURE if (strncmp(message,"IND HANDOVER_FAILURE ", 21)==0) return processHandoverFailure(peer,message); // Other handover messages go into the FIFO map. // (pat) It is an ACK message, and we need to queue it because the 'senduntilack' is running in a different thread. // FIXME -- We need something here to spot malformed messages. unsigned transactionID; sscanf(message, "%*s %*s %u", &transactionID); mFIFOMap.writeFIFO(transactionID,message); }
IPv4Address PcapLiveDevice::getIPv4Address() { for(std::vector<pcap_addr_t>::iterator addrIter = m_Addresses.begin(); addrIter != m_Addresses.end(); addrIter++) { if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) { char addrAsString[INET6_ADDRSTRLEN]; sockaddr2string(addrIter->addr, addrAsString); LOG_DEBUG("Searching address %s", addrAsString); } in_addr* currAddr = sockaddr2in_addr(addrIter->addr); if (currAddr == NULL) { LOG_DEBUG("Address is NULL"); continue; } return IPv4Address(currAddr); } return IPv4Address::Zero; }
PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(IPv6Address ip6Addr) { LOG_DEBUG("Searching all live devices..."); for(std::vector<PcapLiveDevice*>::iterator devIter = m_LiveDeviceList.begin(); devIter != m_LiveDeviceList.end(); devIter++) { LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_Name); for(std::vector<pcap_addr_t>::iterator addrIter = (*devIter)->m_Addresses.begin(); addrIter != (*devIter)->m_Addresses.end(); addrIter++) { if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) { char addrAsString[INET6_ADDRSTRLEN]; sockaddr2string(addrIter->addr, addrAsString); LOG_DEBUG("Searching address %s", addrAsString); } in6_addr* currAddr = sockaddr2in6_addr(addrIter->addr); if (currAddr == NULL) { LOG_DEBUG("Address is NULL"); continue; } uint8_t* addrAsArr; size_t addrLen; ip6Addr.copyTo(&addrAsArr, addrLen); if (memcmp(currAddr, addrAsArr, sizeof(struct in6_addr)) == 0) { LOG_DEBUG("Found matched address!"); return (*devIter); } delete [] addrAsArr; } } return NULL; }
// pats TODO: We should check for conflicts when we start up. // pats TODO: Check for more than 31 ARFCNs and report. // pats TODO: We should check for ARFCN+BSIC conflicts among the neighbors. That implies sucking the whole neighbor table in, // but dont worry about now it because the whole thing should move to SR imho. void PeerInterface::processNeighborParams(const struct sockaddr_in* peer, const char* message) { try { // Create a unique id so we can tell if we send a message to ourself. static uint32_t btsid = 0; while (btsid == 0) { btsid = (uint32_t) random(); } // (pat) This is the original format, which I now call version 1. static const char rspFormatV1[] = "RSP NEIGHBOR_PARAMS %u %u"; // C0 BSIC // (pat) This is the 3-2014 format. Extra args are ignored by older versions of OpenBTS. //static const char rspFormat[] = "RSP NEIGHBOR_PARAMS %u %u %u %d %u %u %u"; // C0 BSIC uniqueID noise numArfcns tchavail tchtotal LOG(DEBUG) << "got message " << message; if (0 == strncmp(message,"REQ ",4)) { // REQ? Send a RSP. char rsp[150]; if (! strchr(message,'=')) { // Send version 1. snprintf(rsp, sizeof(rsp), rspFormatV1, gTRX.C0(), gBTS.BSIC()); } else { // Send version 2. int myNoise = gTRX.ARFCN(0)->getNoiseLevel(); unsigned tchTotal = gBTS.TCHTotal(); unsigned tchAvail = tchTotal - gBTS.TCHActive(); snprintf(rsp, sizeof(rsp), "RSP NEIGHBOR_PARAMS V=2 C0=%u BSIC=%u btsid=%u noise=%d arfcns=%d TchAvail=%u TchTotal=%u", gTRX.C0(), gBTS.BSIC(), btsid, myNoise, (int)gConfig.getNum("GSM.Radio.ARFCNs"), tchAvail, tchTotal); sendMessage(peer,rsp); } return; } if (0 == strncmp(message,"RSP ",4)) { // RSP? Digest it. NeighborEntry newentry; if (! strchr(message,'=')) { // Version 1 message. int r = sscanf(message, rspFormatV1, &newentry.mC0, &newentry.mBSIC); if (r != 2) { logAlert(format("badly formatted peering message: %s",message)); return; } } else { SimpleKeyValue keys; keys.addItems(message + sizeof("RSP NEIGHBOR_PARAMS")); // sizeof is +1 which is ok - we are skipping the initial space. { bool valid; unsigned neighborID = keys.getNum("btsid",valid); if (valid && neighborID == btsid) { LOG(ERR) << "BTS is in its own GSM.Neighbors list."; return; } } newentry.mC0 = keys.getNumOrBust("C0"); newentry.mBSIC = keys.getNumOrBust("BSIC"); newentry.mNoise = keys.getNumOrBust("noise"); newentry.mNumArfcns = keys.getNumOrBust("arfcns"); newentry.mTchAvail = keys.getNumOrBust("TchAvail"); newentry.mTchTotal = keys.getNumOrBust("TchTotal"); } newentry.mIPAddress = sockaddr2string(peer, false); if (newentry.mIPAddress.size() == 0) { LOG(ERR) << "cannot parse peer socket address for"<<LOGVAR2("C0",newentry.mC0)<<LOGVAR2("BSIC",newentry.mBSIC); return; } // Did the neighbor list change? bool change = gNeighborTable.ntAddInfo(newentry); // no change includes unsolicited RSP NEIGHBOR_PARAMS. drop it. if (!change) return; // It there a BCC conflict? int ourBSIC = gBTS.BSIC(); if (newentry.mC0 == (int)gTRX.C0()) { if (newentry.mBSIC == ourBSIC) { logAlert(format("neighbor with matching ARFCN.C0 + BSIC [Base Station Identifier] codes: C0=%d BSIC=%u",newentry.mC0,newentry.mBSIC)); } else { // Two BTS on the same ARFCN close enough to be neighbors, which is probably a bad idea, but legal. // Is it worth an ALERT? LOG(WARNING) << format("neighbor with matching ARFCN.C0 but different BSIC [Base Station Identifier] code: C0=%d, BSIC=%u, my BSIC=%u", newentry.mC0,newentry.mBSIC,gTRX.C0()); } } // 3-2014: Warn for overlapping ARFCN use. Fixes ticket #857 int myC0 = gTRX.C0(); int myCEnd = myC0 + gConfig.getNum("GSM.Radio.ARFCNs") - 1; int neighborCEnd = newentry.mC0 + newentry.mNumArfcns - 1; bool overlap = myC0 <= neighborCEnd && myCEnd >= (int) newentry.mC0; if (overlap) { LOG(WARNING) << format("neighbor IP=%s BSIC=%d ARFCNs=%u to %d overlaps with this BTS ARFCNs=%d to %d", newentry.mIPAddress.c_str(), newentry.mBSIC, newentry.mC0, neighborCEnd, myC0, myCEnd); } // Is there an NCC conflict? // (pat) ARFCN-C0 (the one carrying BCCH) and BSIC consisting of NCC (Network Color Code) and BCC. (Base station Color Code) int neighborNCC = newentry.mBSIC >> 3; int NCCMaskBit = 1 << neighborNCC; int ourNCCMask = gConfig.getNum("GSM.CellSelection.NCCsPermitted"); ourNCCMask |= 1 << gConfig.getNum("GSM.Identity.BSIC.NCC"); if ((NCCMaskBit & ourNCCMask) == 0) { //LOG(ALERT) << "neighbor with NCC " << neighborNCC << " not in NCCsPermitted"; logAlert(format("neighbor with NCC=%u not in NCCsPermitted",neighborNCC)); } // There was a change, so regenerate the beacon gBTS.regenerateBeacon(); return; } LOG(ALERT) << "unrecognized Peering message: " << message; } catch (SimpleKeyValueException &e) {
PcapLiveDevice::PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU, bool calculateMacAddress) : IPcapDevice(), m_MacAddress("") { m_Name = NULL; m_Description = NULL; m_DeviceMtu = 0; m_IsLoopback = (pInterface->flags & 0x1) == PCAP_IF_LOOPBACK; int strLength = strlen(pInterface->name)+1; m_Name = new char[strLength]; strncpy((char*)m_Name, pInterface->name, strLength); strLength = 1; if (pInterface->description != NULL) strLength += strlen(pInterface->description); m_Description = new char[strLength]; if (pInterface->description != NULL) strncpy((char*)m_Description, pInterface->description, strLength); else strncpy((char*)m_Description, "", strLength); LOG_DEBUG("Added live device: name=%s; desc=%s", m_Name, m_Description); LOG_DEBUG(" Addresses:"); while (pInterface->addresses != NULL) { m_Addresses.insert(m_Addresses.end(), *(pInterface->addresses)); pInterface->addresses = pInterface->addresses->next; if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && pInterface->addresses != NULL && pInterface->addresses->addr != NULL) { char addrAsString[INET6_ADDRSTRLEN]; sockaddr2string(pInterface->addresses->addr, addrAsString); LOG_DEBUG(" %s", addrAsString); } } if (calculateMTU) { setDeviceMtu(); LOG_DEBUG(" MTU: %d", m_DeviceMtu); } //init all other members m_CaptureThreadStarted = false; m_StatsThreadStarted = false; m_IsLoopback = false; m_StopThread = false; m_CaptureThread = new PcapThread(); m_StatsThread = new PcapThread(); memset(m_CaptureThread, 0, sizeof(PcapThread)); memset(m_StatsThread, 0, sizeof(PcapThread)); m_cbOnPacketArrives = NULL; m_cbOnStatsUpdate = NULL; m_IntervalToUpdateStats = 0; m_cbOnPacketArrivesUserCookie = NULL; m_cbOnStatsUpdateUserCookie = NULL; m_CaptureCallbackMode = true; m_CapturedPackets = NULL; if (calculateMacAddress) { setDeviceMacAddress(); if (m_MacAddress.isValid()) LOG_DEBUG(" MAC addr: %s", m_MacAddress.toString().c_str()); } }