def datagramReceived(self, rawdata, addr, altport=False):

        ad = Ad().setAddrTuple(addr)

        if not ad.port:
            return

        # This will remap a router's internal IP to its external IP,
        # if the remapping is known.
        if self.remap_ip and ad.ip == self.remap_ip[0]:
            ad.orig_ip = ad.ip
            ad.ip = self.remap_ip[1]

        # Special handler for search results directly from DC
        if rawdata[:4] == '$SR ':
            dch = self.main.getOnlineDCH()
            if dch and ad.auth('sb', self.main):
                dch.pushSearchResult(rawdata)
            return

        try:
            try:
                data = self.main.pk_enc.decrypt(rawdata)
            except ValueError, e:
                raise BadPacketError("Decrypt Failed: " + str(e))

            if len(data) < 2:
                raise BadPacketError("Too Short")

            kind = data[:2]

            if not kind.isalpha():
                raise BadPacketError("Kind not alphabetical")

            if altport:
                kind += "_alt"

            self.main.logPacket("%s <- %s:%d" % (kind, addr[0], addr[1]))

            # Make sure the sender's IP is permitted, but delay the check if
            # it's an initialize packet.
            if kind not in ('IQ', 'EC', 'IR', 'IC_alt'):
                if not ad.auth('sbx', self.main):
                    raise BadPacketError("Invalid source IP")

            try:
                method = getattr(self, 'handlePacket_%s' % kind)
            except AttributeError:
                raise BadPacketError("Unknown kind: %s" % kind)

            # arg1: Address the packet came from
            # arg2: The unencrypted packet
            method(ad, data)

        except (BadPacketError, BadTimingError), e:
            self.main.logPacket("Bad Packet/Timing: %s" % str(e))