예제 #1
0
struct os_eventq bleprph_evq;
struct os_task bleprph_task;
bssnz_t os_stack_t bleprph_stack[BLEPRPH_STACK_SIZE];

/** Our global device address (public) */
uint8_t g_dev_addr[BLE_DEV_ADDR_LEN] = {0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a};

/** Our random address (in case we need it) */
uint8_t g_random_addr[BLE_DEV_ADDR_LEN];

/** Device name - included in advertisements and exposed by GAP service. */
const char *bleprph_device_name = "nimble-bleprph";

/** Device properties - exposed by GAP service. */
const uint16_t bleprph_appearance = BSWAP16(BLE_GAP_APPEARANCE_GEN_COMPUTER);
const uint8_t bleprph_privacy_flag = 0;
uint8_t bleprph_reconnect_addr[6];
uint8_t bleprph_pref_conn_params[8];
uint8_t bleprph_gatt_service_changed[4];

static int bleprph_gap_event(int event, int status,
                             struct ble_gap_conn_ctxt *ctxt, void *arg);

/**
 * Utility function to log an array of bytes.
 */
static void
bleprph_print_bytes(uint8_t *bytes, int len)
{
    int i;
예제 #2
0
/* XXX - return -1 on I/O error and actually do something with 'err'. */
int csids_open(wtap *wth, int *err, gchar **err_info)
{
  /* There is no file header. There is only a header for each packet
   * so we read a packet header and compare the caplen with iplen. They
   * should always be equal except with the wierd byteswap version.
   *
   * THIS IS BROKEN-- anytime the caplen is 0x0101 or 0x0202 up to 0x0505
   * this will byteswap it. I need to fix this. XXX --mlh
   */

  int tmp,iplen,bytesRead;

  gboolean byteswap = FALSE;
  struct csids_header hdr;
  csids_t *csids;

  /* check the file to make sure it is a csids file. */
  bytesRead = file_read( &hdr, sizeof( struct csids_header), wth->fh );
  if( bytesRead != sizeof( struct csids_header) ) {
    *err = file_error( wth->fh, err_info );
    if( *err != 0 ) {
      return -1;
    } else {
      return 0;
    }
  }
  if( hdr.zeropad != 0 || hdr.caplen == 0 ) {
	return 0;
  }
  hdr.seconds = pntohl( &hdr.seconds );
  hdr.caplen = pntohs( &hdr.caplen );
  bytesRead = file_read( &tmp, 2, wth->fh );
  if( bytesRead != 2 ) {
    *err = file_error( wth->fh, err_info );
    if( *err != 0 ) {
      return -1;
    } else {
      return 0;
    }
  }
  bytesRead = file_read( &iplen, 2, wth->fh );
  if( bytesRead != 2 ) {
    *err = file_error( wth->fh, err_info );
    if( *err != 0 ) {
      return -1;
    } else {
      return 0;
    }
  }
  iplen = pntohs(&iplen);

  if ( iplen == 0 )
    return(0);

  /* if iplen and hdr.caplen are equal, default to no byteswap. */
  if( iplen > hdr.caplen ) {
    /* maybe this is just a byteswapped version. the iplen ipflags */
    /* and ipid are swapped. We cannot use the normal swaps because */
    /* we don't know the host */
    iplen = BSWAP16(iplen);
    if( iplen <= hdr.caplen ) {
      /* we know this format */
      byteswap = TRUE;
    } else {
      /* don't know this one */
      return 0;
    }
  } else {
    byteswap = FALSE;
  }

  /* no file header. So reset the fh to 0 so we can read the first packet */
  if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
    return -1;

  wth->data_offset = 0;
  csids = (csids_t *)g_malloc(sizeof(csids_t));
  wth->priv = (void *)csids;
  csids->byteswapped = byteswap;
  wth->file_encap = WTAP_ENCAP_RAW_IP;
  wth->file_type = WTAP_FILE_CSIDS;
  wth->snapshot_length = 0; /* not known */
  wth->subtype_read = csids_read;
  wth->subtype_seek_read = csids_seek_read;
  wth->tsprecision = WTAP_FILE_TSPREC_SEC;

  return 1;
}
예제 #3
0
파일: util.c 프로젝트: dterweij/opennap
/* writes `val' as a two-byte value in little-endian format */
void
set_val (char *d, unsigned short val)
{
    val = BSWAP16 (val);
    memcpy (d, &val, 2);
}
예제 #4
0
static void console_process_loop_message(vantage_console_context_t *vantage_console_priv)
{
  vantage_loop_packets_t* packet_buffer = (vantage_loop_packets_t*) vantage_console_priv->decoder_message_buffer;
  weather_data_t          weather_data = {0};

  time_t t = time(NULL);
  weather_data.tm = *localtime(&t);

  /* First, check the packet type byte to know if it's a LOOP or LOOP2 message
   * As the first message fields are in the same layout, we use the LOOP message
   * definition to access the packet type information
   */

  /* LOOP message */
  if (packet_buffer->loop_packet.packet_type == 0)
  {
    if (loglevel > 0)
    {
      LOG_printf(LOG_LVL_INFO, "Received LOOP packet\n");
    }

    /* Outisde temperature is in 10th of Fahrenheit. Convert it to Celcius */
    weather_data.outside_temperature_F = (float) BSWAP16(packet_buffer->loop_packet.OutsideTemp) / 10.0;
    weather_data.outside_temperature_C = (weather_data.outside_temperature_F - 32.0) / 1.8;

    /* Outside Humidity is in percent */
    weather_data.outside_humidity = packet_buffer->loop_packet.OutsideHumidity;

    /* Wind speed is in Miles per hour */
    weather_data.wind_speed_MPH = packet_buffer->loop_packet.WindSpeed;
    weather_data.wind_speed_KPH = 1.609344 * weather_data.wind_speed_MPH;

    /* Wind chill is in fahrenheit. Convert it to Celcius */
    weather_data.outside_chill_F = compute_wind_chill(weather_data.outside_temperature_F, weather_data.wind_speed_MPH);
    weather_data.outside_chill_C = ((float) weather_data.outside_chill_F - 32.0) / 1.8;
    
    /* Dew point is in fahrenheit. Convert it to Celcius */
    weather_data.dew_point_F = compute_dew_point(weather_data.outside_temperature_F, weather_data.outside_humidity);
    weather_data.dew_point_C = (weather_data.dew_point_F - 32.0) / 1.8;

    /* Inside temperature is in 10th of Fahrenheit. Convert it to Celcius */
    weather_data.inside_temperature_F = (float) BSWAP16(packet_buffer->loop_packet.InsideTemp) / 10.0;
    weather_data.inside_temperature_C = (weather_data.inside_temperature_F - 32.0) / 1.8;

    /* Inside Humidity is in percent */
    weather_data.inside_humidity = packet_buffer->loop_packet.InsideHumidity;

    /* Barometric pressure is in inches. Convert to mBar */
    weather_data.barometric_pressure_I = BSWAP16(packet_buffer->loop_packet.Barometer);
    weather_data.barometric_pressure_Hpa = (33.8639 * weather_data.barometric_pressure_I) / 1000.0;

    /* Rain rate is in rain clicks (TODO : retrieve customized rain sensor value ?) */
    weather_data.rain_rate_I = 0.01 * BSWAP16(packet_buffer->loop_packet.RainRate);
    weather_data.rain_rate_MM = 0.2 * BSWAP16(packet_buffer->loop_packet.RainRate);

    /* Day rain is in rain clicks */
    weather_data.rain_day_I = 0.01 * BSWAP16(packet_buffer->loop_packet.DayRain);
    weather_data.rain_day_MM = 0.2 * BSWAP16(packet_buffer->loop_packet.DayRain);

    /* Wind speed average is in 0.1mph */
    weather_data.wind_speed_avg_2m_MPH = 0.1 * packet_buffer->loop_packet.TenMinuteAvgWindSpeed;
    weather_data.wind_speed_avg_2m_KPH = 1.609344 * weather_data.wind_speed_avg_2m_MPH;

    weather_data.wind_direction = BSWAP16(packet_buffer->loop_packet.WindDir);

    /* Wind gust is in 0.1mph */
    weather_data.wind_gust = FLT_MIN;
    weather_data.wind_gust_10m = FLT_MIN;

    weather_data.wind_direction_gust_10m = FLT_MIN;
  }
  /* LOOP2 message */
  else if (packet_buffer->loop_packet.packet_type == 1)
  {
    if (loglevel > 0)
    {
      LOG_printf(LOG_LVL_INFO, "Received LOOP2 packet\n");
    }

    /* Outisde temperature is in 10th of Fahrenheit. Convert it to Celcius */
    weather_data.outside_temperature_F = (float) BSWAP16(packet_buffer->loop2_packet.OutsideTemp) / 10.0;
    weather_data.outside_temperature_C = (weather_data.outside_temperature_F - 32.0) / 1.8;

    /* Outside Humidity is in percent */
    weather_data.outside_humidity = packet_buffer->loop2_packet.OutsideHumidity;

    /* Wind chill is in fahrenheit. Convert it to Celcius */
    weather_data.outside_chill_F = BSWAP16(packet_buffer->loop2_packet.WindChill);
    weather_data.outside_chill_C = ((float) BSWAP16(packet_buffer->loop2_packet.WindChill) - 32.0) / 1.8;
    
    /* Dew point is in fahrenheit. Convert it to Celcius */
    weather_data.dew_point_F = BSWAP16(packet_buffer->loop2_packet.DewPoint);
    weather_data.dew_point_C = ((float) BSWAP16(packet_buffer->loop2_packet.DewPoint) - 32.0) / 1.8;

    /* Inside temperature is in 10th of Fahrenheit. Convert it to Celcius */
    weather_data.inside_temperature_F = (float) BSWAP16(packet_buffer->loop2_packet.InsideTemp) / 10.0;
    weather_data.inside_temperature_C = (weather_data.inside_temperature_F - 32.0) / 1.8;

    /* Inside Humidity is in percent */
    weather_data.inside_humidity = packet_buffer->loop2_packet.InsideHumidity;

    /* Barometric pressure is in inches. Convert to mBar */
    weather_data.barometric_pressure_I = BSWAP16(packet_buffer->loop2_packet.Barometer);
    weather_data.barometric_pressure_Hpa = (33.8639 * weather_data.barometric_pressure_I) / 1000.0;

    /* Rain rate is in rain clicks (TODO : retrieve customized rain sensor value ?) */
    weather_data.rain_rate_I = 0.01 * BSWAP16(packet_buffer->loop2_packet.RainRate);
    weather_data.rain_rate_MM = 0.2 * BSWAP16(packet_buffer->loop2_packet.RainRate);

    /* Day rain is in rain clicks */
    weather_data.rain_day_I = 0.01 * BSWAP16(packet_buffer->loop2_packet.DayRain);
    weather_data.rain_day_MM = 0.2 * BSWAP16(packet_buffer->loop2_packet.DayRain);

    /* Wind speed is in Miles per hour */
    weather_data.wind_speed_MPH = packet_buffer->loop2_packet.WindSpeed;
    weather_data.wind_speed_KPH = 1.609344 * weather_data.wind_speed_MPH;

    /* Wind speed average is in 0.1mph */
    weather_data.wind_speed_avg_2m_MPH = 0.1 * BSWAP16(packet_buffer->loop2_packet.TwoMinuteAvgWindSpeed);
    weather_data.wind_speed_avg_2m_KPH = 1.609344 * weather_data.wind_speed_avg_2m_MPH;

    weather_data.wind_direction = BSWAP16(packet_buffer->loop2_packet.WindDir);

    /* Wind gust is in 0.1mph */
    weather_data.wind_gust = 0.1 * BSWAP16(packet_buffer->loop2_packet.TenMinuteWindGust);
    weather_data.wind_gust_10m = 0.1 * BSWAP16(packet_buffer->loop2_packet.TenMinuteWindGust);

    weather_data.wind_direction_gust_10m = BSWAP16(packet_buffer->loop2_packet.WindDirForTenMinuteWindGust);
  }
  else
  {
    LOG_printf(LOG_LVL_ERROR, "Unknown packet type %d\n", packet_buffer->loop_packet.packet_type);
    return;
  }

  if (vantage_console_priv->DataReadyIndicateCb != NULL)
  {
    vantage_console_priv->DataReadyIndicateCb(&weather_data);
  }
  
}
예제 #5
0
int libpcap_open(wtap *wth, int *err, gchar **err_info)
{
	int bytes_read;
	guint32 magic;
	struct pcap_hdr hdr;
	gboolean byte_swapped;
	gboolean modified;
	gboolean aix;
	int file_encap;
	gint64 first_packet_offset;
	libpcap_t *libpcap;

	/* Read in the number that should be at the start of a "libpcap" file */
	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(&magic, sizeof magic, wth->fh);
	if (bytes_read != sizeof magic) {
		*err = file_error(wth->fh, err_info);
		if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
			return -1;
		return 0;
	}

	switch (magic) {

	case PCAP_MAGIC:
		/* Host that wrote it has our byte order, and was running
		   a program using either standard or ss990417 libpcap. */
		byte_swapped = FALSE;
		modified = FALSE;
		wth->tsprecision = WTAP_FILE_TSPREC_USEC;
		break;

	case PCAP_MODIFIED_MAGIC:
		/* Host that wrote it has our byte order, and was running
		   a program using either ss990915 or ss991029 libpcap. */
		byte_swapped = FALSE;
		modified = TRUE;
		wth->tsprecision = WTAP_FILE_TSPREC_USEC;
		break;

	case PCAP_SWAPPED_MAGIC:
		/* Host that wrote it has a byte order opposite to ours,
		   and was running a program using either standard or
		   ss990417 libpcap. */
		byte_swapped = TRUE;
		modified = FALSE;
		wth->tsprecision = WTAP_FILE_TSPREC_USEC;
		break;

	case PCAP_SWAPPED_MODIFIED_MAGIC:
		/* Host that wrote it out has a byte order opposite to
		   ours, and was running a program using either ss990915
		   or ss991029 libpcap. */
		byte_swapped = TRUE;
		modified = TRUE;
		wth->tsprecision = WTAP_FILE_TSPREC_USEC;
		break;

	case PCAP_NSEC_MAGIC:
		/* Host that wrote it has our byte order, and was writing
		   the file in a format similar to standard libpcap
		   except that the time stamps have nanosecond resolution. */
		byte_swapped = FALSE;
		modified = FALSE;
		wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
		break;

	case PCAP_SWAPPED_NSEC_MAGIC:
		/* Host that wrote it out has a byte order opposite to
		   ours, and was writing the file in a format similar to
		   standard libpcap except that the time stamps have
		   nanosecond resolution. */
		byte_swapped = TRUE;
		modified = FALSE;
		wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
		break;

	default:
		/* Not a "libpcap" type we know about. */
		return 0;
	}

	/* Read the rest of the header. */
	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
	if (bytes_read != sizeof hdr) {
		*err = file_error(wth->fh, err_info);
		if (*err == 0)
			*err = WTAP_ERR_SHORT_READ;
		return -1;
	}

	if (byte_swapped) {
		/* Byte-swap the header fields about which we care. */
		hdr.version_major = BSWAP16(hdr.version_major);
		hdr.version_minor = BSWAP16(hdr.version_minor);
		hdr.snaplen = BSWAP32(hdr.snaplen);
		hdr.network = BSWAP32(hdr.network);
	}
	if (hdr.version_major < 2) {
		/* We only support version 2.0 and later. */
		*err = WTAP_ERR_UNSUPPORTED;
		*err_info = g_strdup_printf("pcap: major version %u unsupported",
		    hdr.version_major);
		return -1;
	}

	/*
	 * AIX's non-standard tcpdump uses a minor version number of 2.
	 * Unfortunately, older versions of libpcap might have used
	 * that as well.
	 *
	 * The AIX libpcap uses RFC 1573 ifType values rather than
	 * DLT_ values in the header; the ifType values for LAN devices
	 * are:
	 *
	 *	Ethernet	6
	 *	Token Ring	9
	 *	FDDI		15
	 *
	 * which correspond to DLT_IEEE802 (used for Token Ring),
	 * DLT_PPP, and DLT_SLIP_BSDOS, respectively.  The ifType value
	 * for a loopback interface is 24, which currently isn't
	 * used by any version of libpcap I know about (and, as
	 * tcpdump.org are assigning DLT_ values above 100, and
	 * NetBSD started assigning values starting at 50, and
	 * the values chosen by other libpcaps appear to stop at
	 * 19, it's probably not going to be used by any libpcap
	 * in the future).
	 *
	 * We shall assume that if the minor version number is 2, and
	 * the network type is 6, 9, 15, or 24, that it's AIX libpcap.
	 *
	 * I'm assuming those older versions of libpcap didn't
	 * use DLT_IEEE802 for Token Ring, and didn't use DLT_SLIP_BSDOS
	 * as that came later.  It may have used DLT_PPP, however, in
	 * which case we're out of luck; we assume it's Token Ring
	 * in AIX libpcap rather than PPP in standard libpcap, as
	 * you're probably more likely to be handing an AIX libpcap
	 * token-ring capture than an old (pre-libpcap 0.4) PPP capture
	 * to Wireshark.
	 */
	aix = FALSE;	/* assume it's not AIX */
	if (hdr.version_major == 2 && hdr.version_minor == 2) {
		switch (hdr.network) {

		case 6:
			hdr.network = 1;	/* DLT_EN10MB, Ethernet */
			aix = TRUE;
			break;

		case 9:
			hdr.network = 6;	/* DLT_IEEE802, Token Ring */
			aix = TRUE;
			break;

		case 15:
			hdr.network = 10;	/* DLT_FDDI, FDDI */
			aix = TRUE;
			break;

		case 24:
			hdr.network = 0;	/* DLT_NULL, loopback */
			aix = TRUE;
			break;
		}
	}

	file_encap = wtap_pcap_encap_to_wtap_encap(hdr.network);
	if (file_encap == WTAP_ENCAP_UNKNOWN) {
		*err = WTAP_ERR_UNSUPPORTED_ENCAP;
		*err_info = g_strdup_printf("pcap: network type %u unknown or unsupported",
		    hdr.network);
		return -1;
	}

	/* This is a libpcap file */
	libpcap = (libpcap_t *)g_malloc(sizeof(libpcap_t));
	libpcap->byte_swapped = byte_swapped;
	libpcap->version_major = hdr.version_major;
	libpcap->version_minor = hdr.version_minor;
	wth->priv = (void *)libpcap;
	wth->subtype_read = libpcap_read;
	wth->subtype_seek_read = libpcap_seek_read;
	wth->file_encap = file_encap;
	wth->snapshot_length = hdr.snaplen;

	/* In file format version 2.3, the order of the "incl_len" and
	   "orig_len" fields in the per-packet header was reversed,
	   in order to match the BPF header layout.

	   Therefore, in files with versions prior to that, we must swap
	   those two fields.

	   Unfortunately, some files were, according to a comment in the
	   "libpcap" source, written with version 2.3 in their headers
	   but without the interchanged fields, so if "incl_len" is
	   greater than "orig_len" - which would make no sense - we
	   assume that we need to swap them in version 2.3 files
	   as well.

	   In addition, DG/UX's tcpdump uses version 543.0, and writes
	   the two fields in the pre-2.3 order. */
	switch (hdr.version_major) {

	case 2:
		if (hdr.version_minor < 3)
			libpcap->lengths_swapped = SWAPPED;
		else if (hdr.version_minor == 3)
			libpcap->lengths_swapped = MAYBE_SWAPPED;
		else
			libpcap->lengths_swapped = NOT_SWAPPED;
		break;

	case 543:
		libpcap->lengths_swapped = SWAPPED;
		break;

	default:
		libpcap->lengths_swapped = NOT_SWAPPED;
		break;
	}

	/*
	 * Is this AIX format?
	 */
	if (aix) {
		/*
		 * Yes.  Skip all the tests for other mutant formats,
		 * and for the ERF link-layer header type, and set the
		 * precision to nanosecond precision.
		 */
		wth->file_type = WTAP_FILE_PCAP_AIX;
		wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
		return 1;
	}

	/*
	 * No.  Let's look at the header for the first record,
	 * and see if, interpreting it as a standard header (if the
	 * magic number was standard) or a modified header (if the
	 * magic number was modified), the position where it says the
	 * header for the *second* record is contains a corrupted header.
	 *
	 * If so, then:
	 *
	 *	If this file had the standard magic number, it may be
	 *	an ss990417 capture file - in that version of Alexey's
	 *	patch, the packet header format was changed but the
	 *	magic number wasn't, and, alas, Red Hat appear to have
	 *	picked up that version of the patch for RH 6.1, meaning
	 *	RH 6.1 has a tcpdump that writes out files that can't
	 *	be read by any software that expects non-modified headers
	 *	if the magic number isn't the modified magic number (e.g.,
	 *	any normal version of tcpdump, and Wireshark if we don't
	 *	do this gross heuristic).
	 *
	 *	If this file had the modified magic number, it may be
	 *	an ss990915 capture file - in that version of Alexey's
	 *	patch, the magic number was changed, but the record
	 *	header had some extra fields, and, alas, SuSE appear
	 *	to have picked up that version of the patch for SuSE
	 *	6.3, meaning that programs expecting the standard per-
	 *	packet header in captures with the modified magic number
	 *	can't read dumps from its tcpdump.
	 *
	 * Oh, and if it has the standard magic number, it might, instead,
	 * be a Nokia libpcap file, so we may need to try that if
	 * neither normal nor ss990417 headers work.
	 */
	if (modified) {
		/*
		 * Well, we have the magic number from Alexey's
		 * later two patches.
		 *
		 * Try ss991029, the last of his patches, first.
		 */
		wth->file_type = WTAP_FILE_PCAP_SS991029;
		first_packet_offset = file_tell(wth->fh);
		switch (libpcap_try(wth, err)) {

		case BAD_READ:
			/*
			 * Well, we couldn't even read it.
			 * Give up.
			 */
			return -1;

		case THIS_FORMAT:
			/*
			 * Well, it looks as if it might be 991029.
			 * Put the seek pointer back, and finish.
			 */
			if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
				return -1;
			}
			goto done;

		case OTHER_FORMAT:
			/*
			 * Try the next format.
			 */
			break;
		}

		/*
		 * Well, it's not completely unreadable,
		 * but it's not ss991029.  Try ss990915;
		 * there are no other types to try after that,
		 * so we put the seek pointer back and treat
		 * it as 990915.
		 */
		wth->file_type = WTAP_FILE_PCAP_SS990915;
		if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
			return -1;
		}
	} else {
		/*
		 * Well, we have the standard magic number.
		 *
		 * Try the standard format first.
		 */
		if(wth->tsprecision == WTAP_FILE_TSPREC_NSEC) {
			wth->file_type = WTAP_FILE_PCAP_NSEC;
		} else {
			wth->file_type = WTAP_FILE_PCAP;
		}
		first_packet_offset = file_tell(wth->fh);
		switch (libpcap_try(wth, err)) {

		case BAD_READ:
			/*
			 * Well, we couldn't even read it.
			 * Give up.
			 */
			return -1;

		case THIS_FORMAT:
			/*
			 * Well, it looks as if it might be a standard
			 * libpcap file.
			 * Put the seek pointer back, and finish.
			 */
			if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
				return -1;
			}
			goto done;

		case OTHER_FORMAT:
			/*
			 * Try the next format.
			 */
			break;
		}

		/*
		 * Well, it's not completely unreadable, but it's not
		 * a standard file.  Put the seek pointer back and try
		 * ss990417.
		 */
		wth->file_type = WTAP_FILE_PCAP_SS990417;
		if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
			return -1;
		}
		switch (libpcap_try(wth, err)) {

		case BAD_READ:
			/*
			 * Well, we couldn't even read it.
			 * Give up.
			 */
			return -1;

		case THIS_FORMAT:
			/*
			 * Well, it looks as if it might be ss990417.
			 * Put the seek pointer back, and finish.
			 */
			if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
				return -1;
			}
			goto done;

		case OTHER_FORMAT:
			/*
			 * Try the next format.
			 */
			break;
		}

		/*
		 * Well, it's not completely unreadable,
		 * but it's not a standard file *nor* is it ss990417.
		 * Try it as a Nokia file; there are no other types
		 * to try after that, so we put the seek pointer back
		 * and treat it as a Nokia file.
		 */
		wth->file_type = WTAP_FILE_PCAP_NOKIA;
		if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
			return -1;
		}
	}

done:
	/*
	 * We treat a DLT_ value of 13 specially - it appears that in
	 * Nokia libpcap format, it's some form of ATM with what I
	 * suspect is a pseudo-header (even though Nokia's IPSO is
	 * based on FreeBSD, which #defines DLT_SLIP_BSDOS as 13).
	 *
	 * If this is a Nokia capture, treat 13 as WTAP_ENCAP_ATM_PDUS,
	 * rather than as what we normally treat it.
	 */
	if (wth->file_type == WTAP_FILE_PCAP_NOKIA && hdr.network == 13)
		wth->file_encap = WTAP_ENCAP_ATM_PDUS;

	if (wth->file_encap == WTAP_ENCAP_ERF) {
		/*
		 * Populate set of interface IDs for ERF format.
		 * Currently, this *has* to be done at open time.
		 */
		erf_populate_interfaces(wth);
	}
	return 1;
}
예제 #6
0
/* use a binary search to find the table in the entry */
static int find_handler(unsigned int tag)
{
    int     min = 0, max = Protocol_Size - 1, try;

    while (!global.sigCaught)
    {
        try = (max + min) / 2;
        if(tag == Protocol[try].message)
            return try;
        else if(min == max)
            return -1;      /* not found */
        else if(tag < Protocol[try].message)
        {
            if(try == min)
                return -1;
            max = try - 1;
        }
        else
        {
            if(try == max)
                return -1;
            min = try + 1;
        }
        ASSERT(min <= max);
    }
    return -1;
}

/* this is not a real handler, but takes the same arguments as one */
HANDLER(dispatch_command)
{
    int     l;
    tag_count_t *tagcount = 0;
    int     tagDelta;
    u_char  byte;

    ASSERT(validate_connection(con));
    ASSERT(pkt != 0);

    /* HACK ALERT
    the handler routines all assume that the `pkt' argument is nul (\0)
    terminated, so we have to replace the byte after the last byte in
    this packet with a \0 to make sure we dont read overflow in the
    handlers.  the handle_connection() function should always allocate 1
    byte more than necessary for this purpose */
    ASSERT(VALID_LEN(con->recvbuf->data, con->recvbuf->consumed + 4 + len + 1));
    stats.tags++;
    byte = *(pkt + len);
    *(pkt + len) = 0;
    l = find_handler(tag);
    if(l != -1)
    {
        ASSERT(Protocol[l].handler != 0);
        if(ISUSER(con))
        {
            tagcount = hash_lookup(con->user->tagCountHash, (void *) tag);
            if(!tagcount)
            {
                tagcount = CALLOC(1, sizeof(tag_count_t));
                tagcount->count = 0;
                tagcount->lastInterval = global.current_time;
                hash_add(con->user->tagCountHash, (void *) tag, tagcount );
            }
            tagcount->count++;
            if(tagcount->count % 1000 == 0)
            {
                tagDelta =  global.current_time - tagcount->lastInterval;
                if(tagDelta == 0)
                    tagDelta = 1;
                if((1000 / tagDelta) >= 100)
                    log_message_level(LOG_LEVEL_ERROR, "dispatch_command: %s has done \"%s\"(%hu) %lu times (%d/sec)", con->user->nick, tag2hrf(tag), tag, tagcount->count, 1000/tagDelta);
                tagcount->lastInterval = global.current_time;
            }
        }
        else if(ISSERVER(con))
        {
            tagcount = hash_lookup(con->sopt->tagCountHash, (void *) tag);
            if(!tagcount)
            {
                tagcount = CALLOC(1, sizeof(tag_count_t));
                tagcount->count = 0;
                tagcount->lastInterval = global.current_time;
                hash_add(con->sopt->tagCountHash, (void *) tag, tagcount );
            }
            tagcount->count++;
            if(tagcount->count % 1000 == 0)
            {
                tagcount->flag = 0;
                tagDelta =  global.current_time - tagcount->lastInterval;
                if(tagDelta == 0)
                    tagDelta = 1;
                if((1000 / tagDelta) >= 200)
                {
                    log_message_level(LOG_LEVEL_ERROR, "dispatch_command: %s has done \"%s\"(%hu) %lu times (%d/sec)", con->host, tag2hrf(tag), tag, tagcount->count, 1000/tagDelta);
                    tagcount->flag = 1;
                }
                tagcount->lastInterval = global.current_time;
            }
        }
        /*
        if(tag == 10018 || (tag != 2 && (tagcount && tagcount->flag)))
        {
        int     i;
        char    message[4096];

        i=0;
        while (i<=len-1) 
        {
        message[i] = isprint(pkt[i]) ? pkt[i] : '.';
        i++;
        }
        message[i]=0;
        log_message_level(LOG_LEVEL_ERROR, "dispatch_command: tag: %d, pkt: %s", tag, message);
        }
        */
        /* do flood control if enabled */
        if(global.floodTime > 0 && !(Protocol[l].flags & F_EXEMPT) && ISUSER(con))
        {
            /* this command is subject to flood control. */
            if(con->flood_start + global.floodTime < global.current_time)
            {
                /* flood expired, reset counters */
                con->flood_start = global.current_time;
                con->flood_commands = 0;
            }
            else if(++con->flood_commands >= global.floodCommands)
            {
                LIST   *list;

                log_message_level( LOG_LEVEL_CLIENT, "dispatch_command: flooding from %s %s(%hu)", get_user(con, 2), tag2hrf(tag), tag);
                notify_mods(FLOODLOG_MODE, "Flooding from %s!%s %s(%hu)", con->user->nick, con->host, tag2hrf(tag), tag );
                /* stop reading from the descriptor until the flood counter
                * expires.
                */
                clear_read(con->fd);

                /* add to the list of flooders that is check in the main
                * loop.  Since we don't traverse the entire client list we
                * have to keep track of which ones to check for expiration
                */
                list = CALLOC(1, sizeof(LIST));
                list->data = con;
                global.flooderList = list_push(global.flooderList, list);
            }
        }

        /* This is to get some info where e.g. pop_user is called from...  */
        global.current_tag = tag;
        /*
        i=0;
        while (i<=len-1) 
		{
        message[i] = isprint(pkt[i]) ? pkt[i] : '.';
        i++;
        }
        message[i]=0;
        log_message("%hu:R:%hu(%s)\t:%hu:\t%s", con->fd, tag, tag2hrf(tag), len+4, message);
        */
        /* note that we pass only the data part of the packet */
        Protocol[l].handler(con, tag, len, pkt);
        Protocol[l].count++;
        Protocol[l].bytes += len+4;
    }
    else
    {
        log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "dispatch_command: unknown message: tag=%hu, length=%hu, data=%s", tag, len, pkt);
        unknown_numeric.message = tag;
        unknown_numeric.count++;
        unknown_numeric.bytes += len+4;

        send_cmd(con, MSG_SERVER_NOSUCH, "Unknown command code %hu", tag);
#if ONAP_DEBUG
        /* if this is a server connection, shut it down to avoid flooding the
        other server with these messages */
        if(ISSERVER(con))
        {
            u_char  ch;
            int     bytes;

            /* dump some bytes from the input buffer to see if it helps aid
            debugging */
            bytes = con->recvbuf->datasize - con->recvbuf->consumed;
            /* print at most 128 bytes */
            if(bytes > 128)
                bytes = 128;
            fprintf(stdout, "Dump(%d): ", con->recvbuf->datasize - con->recvbuf->consumed);
            for (l = con->recvbuf->consumed; bytes > 0; bytes--, l++)
            {
                ch = *(con->recvbuf->data + l);
                fputc(isprint(ch) ? ch : '.', stdout);
            }
            fputc('\n', stdout);
        }
#endif /* ONAP_DEBUG */
    }
    /* restore the byte we overwrite at the beginning of this function */
    *(pkt + len) = byte;
}

void handle_connection(CONNECTION * con)
{
    int     n;
    u_short tag, len;
    /* char*   msg[4096]; */

    ASSERT(validate_connection(con));

#ifdef CSC
    if(ISUSER(con)) 
	{
        if(con->uopt->csc) 
		{
            do 
			{
                n = READ(con->fd, Buf, sizeof(Buf));
                if(n <= 0) 
				{
                    if(n == -1) 
					{
                        if(N_ERRNO == EWOULDBLOCK)
                            break;
                        log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: read: %s (errno %d) for host %s (fd %d)", strerror(N_ERRNO), N_ERRNO, con->host, con->fd);
                    } 
					else 
					{
                        log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: EOF from %s", con->user->nick);
                    }
                    destroy_connection(con);
                    return;
                }
                global.bytes_in += n;
                if(global.min_read > 0 && n < global.min_read) 
				{
                    log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: %d bytes from %s", n, con->host);
                }
                if(buffer_decompress(con->recvbuf, con->uopt->zin, Buf, n)) 
				{
                    destroy_connection(con);
                    return;
                }
            } while (n == sizeof(Buf));
            goto dcomp_ok;
        }
    }
#endif

    if(ISSERVER(con)) 
    {
        /* server data is compressed.  read as much as we can and pass it
        to the decompressor.  we attempt to read all data from the socket
        in this loop, which will prevent unnecessary passes through the
        main loop (since select would return immediately) */
        do
        {
            n = READ(con->fd, Buf, sizeof(Buf));
            if(n <= 0)
            {
                if(n == -1)
                {
                    /* try to empty the socket each time, so we read until
                    *  we hit this error (queue empty).  this should only
                    *  happen in the rare event that the data in the queue
                    *  is a multiple of sizeof(Buf)
                    */
                    if(N_ERRNO == EWOULDBLOCK)
                        break;  /* not an error */
                    log_message_level(LOG_LEVEL_ERROR, "handle_connection: read: %s (errno %d) for host %s (fd %d)", strerror(N_ERRNO), N_ERRNO, con->host, con->fd);
                }
                else
                    log_message_level(LOG_LEVEL_SERVER | LOG_LEVEL_ERROR , "handle_connection: EOF from %s", con->host);
                destroy_connection(con);
                return;
            }
            global.bytes_in += n;

            if(global.min_read > 0 && n < global.min_read)
            {
                log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: %d bytes from %s", n, con->host);
            }

            /* this can safely be called multiple times in this loop.  the
            * decompressor will realloc the output buffer if there is not
            * enough room to store everything
            */
            if(buffer_decompress(con->recvbuf, con->sopt->zin, Buf, n))
            {
                destroy_connection(con);
                return;
            }
            /* if what we read was equal to sizeof(Buf) it's very likely
            * that more data exists in the queue
            */
        } while (n == sizeof(Buf));
    }
    else
    {
        /* create the input buffer if it doesn't yet exist */
        if(!con->recvbuf)
        {
            con->recvbuf = CALLOC(1, sizeof(BUFFER));
            if(!con->recvbuf)
            {
                OUTOFMEMORY("handle_connection");
                destroy_connection(con);
                return;
            }
#if ONAP_DEBUG
            con->recvbuf->magic = MAGIC_BUFFER;
#endif
            con->recvbuf->data = MALLOC(RECVBUF_INITAL_SIZE + 1);
            if(!con->recvbuf->data)
            {
                OUTOFMEMORY("handle_connection");
                destroy_connection(con);
                return;
            }
            con->recvbuf->datamax = RECVBUF_INITAL_SIZE;
        }
        /* read the packet header if we haven't seen it already */
        while (con->recvbuf->datasize < 4)
        {
            n = READ(con->fd, con->recvbuf->data + con->recvbuf->datasize, 4 - con->recvbuf->datasize);
            if(n == -1)
            {
                if(N_ERRNO != EWOULDBLOCK)
                {
                    log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: read: %s (errno %d) for host %s", strerror(N_ERRNO), N_ERRNO, con->host);
                    destroy_connection(con);
                }
                return;
            }
            else if(n == 0)
            {
                destroy_connection(con);
                return;
            }
            global.bytes_in += n;
            con->recvbuf->datasize += n;
        }
        /* read the packet body */
        memcpy(&len, con->recvbuf->data, 2);
        len = BSWAP16(len);
        if(len > 0)
        {
            if(global.maxCommandLen && len > global.maxCommandLen)
            {
                log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: %hu byte message from %s", len, con->host);
                destroy_connection(con);
                return;
            }

            /* if there isn't enough space to read the entire body, resize the input buffer */
            if(con->recvbuf->datamax < 4 + len)
            {
                /* allocate 1 extra byte for the \0 that dispatch_command() requires */
                if(safe_realloc((void **) &con->recvbuf->data, 4 + len + 1))
                {
                    OUTOFMEMORY("handle_connection");
                    destroy_connection(con);
                    return;
                }
                con->recvbuf->datamax = 4 + len;
            }
            n = READ(con->fd, con->recvbuf->data + con->recvbuf->datasize, len + 4 - con->recvbuf->datasize);
            if(n == -1)
            {
                /* since the header and body could arrive in separate packets, we have to check for this here so we don't close the
                *  connection on this nonfatal error.  we just wait for the next packet to arrive 
                */
                if(N_ERRNO != EWOULDBLOCK)
                {
                    log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: read: %s (errno %d) for host %s", strerror(N_ERRNO), N_ERRNO, con->host);
                    destroy_connection(con);
                }
                return;
            }
            else if(n == 0)
            {
                log_message_level(LOG_LEVEL_ERROR, "handle_connection: EOF from %s", con->host);
                destroy_connection(con);
                return;
            }
            con->recvbuf->datasize += n;
            global.bytes_in += n;
        }
    }
    /* process as many complete commands as possible.  for a client this
    will be exactly one, but a server link may have sent multiple commands
    in one compressed packet */
#ifdef CSC
dcomp_ok:
#endif
    while (con->recvbuf->consumed < con->recvbuf->datasize)
    {
        /* if we don't have the complete packet header, wait until we
        read more data */
        if(con->recvbuf->datasize - con->recvbuf->consumed < 4)
            break;
        /* read the packet header */
        memcpy(&len, con->recvbuf->data + con->recvbuf->consumed, 2);
        memcpy(&tag, con->recvbuf->data + con->recvbuf->consumed + 2, 2);
        len = BSWAP16(len);
        tag = BSWAP16(tag);
        /* check if the entire packet body has arrived */
        if(con->recvbuf->consumed + 4 + len > con->recvbuf->datasize)
            break;
        /*
        bzero( msg, 4096 );
        memcpy(&msg, con->recvbuf->data + con->recvbuf->consumed + 4, len);
        log_message_level( LOG_LEVEL_DEBUG, "recv: [%u] %s (%u)", tag, msg, len);
        */
        /* require that the client register before doing anything else */
        if(con->class == CLASS_UNKNOWN &&
            (tag != MSG_CLIENT_LOGIN && tag != MSG_CLIENT_LOGIN_REGISTER &&
            tag != MSG_CLIENT_REGISTER && tag != MSG_SERVER_LOGIN &&
            tag != MSG_SERVER_LOGIN_ACK && tag != MSG_SERVER_ERROR &&
            tag != 4 && /* unknown: v2.0 beta 5a sends this? */
            tag != 300 && tag != 11 && tag != 920))
        {
            log_message_level(LOG_LEVEL_ERROR, "handle_connection: %s is not registered", con->host);
            *(con->recvbuf->data + con->recvbuf->consumed + 4 + len) = 0;
            log_message_level(LOG_LEVEL_ERROR, "handle_connection: tag=%hu, len=%hu, data=%s", tag, len, con->recvbuf->data + con->recvbuf->consumed + 4);
            send_cmd(con, MSG_SERVER_ERROR, "invalid command");
            destroy_connection(con);
            return;
        }

        if(ISUSER(con))
        {
            /* check for end of share/unshare sequence.  in order to avoid
            having to send a single message for each shared file,
            the add_file and remove_file commands set a flag noting the
            start of a possible series of commands.  this routine checks
            to see if the end of the sequence has been reached (a command
            other than share/unshare has been issued) and then relays
            the final result to the peer servers.
            NOTE: the only issue with this is that if the user doesn't
            issue any commands after sharing files, the information will
            never get passed to the peer servers.  This is probably ok
            since this case will seldom happen */
            if(con->user->sharing)
            {
                if(tag != MSG_CLIENT_ADD_FILE
                    && tag != MSG_CLIENT_SHARE_FILE
                    && tag != MSG_CLIENT_ADD_DIRECTORY)
                {
                    pass_message_args(con, MSG_SERVER_USER_SHARING, "%s %hu %u", con->user->nick, con->user->shared, con->user->libsize);
                    con->user->sharing = 0;
                }
            }
            else if(con->user->unsharing)
            {
                if(tag != MSG_CLIENT_REMOVE_FILE)
                {
                    pass_message_args(con, MSG_SERVER_USER_SHARING, "%s %hu %u", con->user->nick, con->user->shared, con->user->libsize);
                    con->user->unsharing = 0;
                }
            }
        }
        /* call the protocol handler */
        dispatch_command(con, tag, len, con->recvbuf->data + con->recvbuf->consumed + 4);
        /* mark data as processed */
        con->recvbuf->consumed += 4 + len;
    }
    if(con->recvbuf->consumed)
    {
        n = con->recvbuf->datasize - con->recvbuf->consumed;
        if(n > 0)
        {
            /* shift down unprocessed data */
            memmove(con->recvbuf->data, con->recvbuf->data + con->recvbuf->consumed, n);
        }
        con->recvbuf->datasize = n;
        con->recvbuf->consumed = 0; /* reset */
    }
}

char* tag2hrf(int tag) 
{
	switch (tag) 
	{
	case MSG_SERVER_ERROR:
		return "server error";       /* 0 */
	case MSG_CLIENT_LOGIN:
		return "login";          /* 2 */
	case MSG_SERVER_EMAIL:
		return "login ack";      /* 3 */
	case MSG_CLIENT_VERSION_CHECK:
		return "version_check";      /* 4 */
	case MSG_CLIENT_LOGIN_REGISTER:
		return "register login"; /* 6 */
	case MSG_CLIENT_REGISTER:
		return "register nick";      /* 7 */
	case MSG_SERVER_REGISTER_OK:
		return "register ok";        /* 8 */
	case MSG_SERVER_REGISTER_FAIL:
		return "register fail";      /* 9 */
	case MSG_SERVER_BAD_NICK:
		return "bad nick";       /* 10 */
	case MSG_CLIENT_CHECK_PASS:
		return "check_password"; /* 11 */
	case MSG_SERVER_PASS_OK:
		return "password ok";        /* 12 */
	case MSG_SERVER_ECHO:
		return "server echo";        /* 13 */
	case MSG_CLIENT_REGISTRATION_INFO:
		return "ignore_command"; /* 14 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_ADD_FILE:
		return "add_file";       /* 100 */
	case MSG_CLIENT_REMOVE_FILE:
		return "remove_file";        /* 102 */
#endif
	case MSG_CLIENT_UNSHARE_ALL:
		return "unshare_all";        /* 110 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_SEARCH:
		return "search";     /* 200 */
#endif
	case MSG_SERVER_SEARCH_RESULT:
		return "search result";      /* 201 */
	case MSG_SERVER_SEARCH_END:
		return "search end";     /* 202 */
	case MSG_CLIENT_DOWNLOAD:
		return "download";       /* 203 */
	case MSG_SERVER_FILE_READY:
		return "file ready";     /* 204 */
	case MSG_CLIENT_PRIVMSG:
		return "privmsg";        /* 205 */
	case MSG_SERVER_SEND_ERROR:
		return "send error";     /* 206 */
	case MSG_CLIENT_ADD_HOTLIST:
		return "add_hotlist";        /* 207 */
	case MSG_CLIENT_ADD_HOTLIST_SEQ:
		return "add_hotlist";        /* 208 */
	case MSG_SERVER_USER_SIGNON:
		return "user signon";        /* 209 */
	case MSG_SERVER_USER_SIGNOFF:
		return "user signoff";       /* 210 */
	case MSG_CLIENT_BROWSE:
		return "browse";     /* 211 */
	case MSG_SERVER_BROWSE_RESPONSE:
		return "browse response";    /* 212 */
	case MSG_SERVER_BROWSE_END:
		return "browse end";     /* 213 */
	case MSG_SERVER_STATS:
		return "server stats";       /* 214 */
	case MSG_CLIENT_RESUME_REQUEST:
		return "resume request"; /* 215 */
	case MSG_SERVER_RESUME_MATCH:
		return "resume match";       /* 216 */
	case MSG_SERVER_RESUME_MATCH_END:
		return "resume match end";   /* 217 */
	case MSG_CLIENT_DOWNLOAD_START:
		return "download start"; /* 218 */
	case MSG_CLIENT_DOWNLOAD_END:
		return "download end";       /* 219 */
	case MSG_CLIENT_UPLOAD_START:
		return "upload start";       /* 220 */
	case MSG_CLIENT_UPLOAD_END:
		return "upload end";     /* 221 */
	case MSG_CLIENT_CHECK_PORT:
		return "check port (ignored)";   /* 300 */
	case MSG_SERVER_HOTLIST_ACK:
		return "hotlist ack";        /* 301 */
	case MSG_SERVER_HOTLIST_ERROR:
		return "hotlist error";      /* 302 */
	case MSG_CLIENT_REMOVE_HOTLIST:
		return "remove_hotlist"; /* 303 */
	case MSG_SERVER_DISCONNECTING:
		return "disconnecting";      /* 316 */
	case MSG_CLIENT_IGNORE_LIST:
		return "ignore list";        /* 320 */
	case MSG_SERVER_IGNORE_ENTRY:
		return "ignore entry";       /* 321 */
	case MSG_CLIENT_IGNORE_USER:
		return "ignore user";        /* 322 */
	case MSG_CLIENT_UNIGNORE_USER:
		return "unignore user";      /* 323 */
	case MSG_SERVER_NOT_IGNORED:
		return "not ignored";        /* 324 */
	case MSG_SERVER_ALREADY_IGNORED:
		return "already ignored";    /* 325 */
	case MSG_CLIENT_CLEAR_IGNORE:
		return "clear ignore";       /* 326 */
	case MSG_CLIENT_JOIN:
		return "join";           /* 400 */
	case MSG_CLIENT_PART:
		return "part";           /* 401 */
	case MSG_CLIENT_PUBLIC:
		return "public";     /* 402 */
	case MSG_SERVER_PUBLIC:
		return "public";     /* 403 */
	case MSG_SERVER_NOSUCH:
		return "server error";       /* 404 */
	case MSG_SERVER_JOIN_ACK:
		return "chan join ack";      /* 405 */
	case MSG_SERVER_JOIN:
		return "chan join";      /* 406 */
	case MSG_SERVER_PART:
		return "chan part";      /* 407 */
	case MSG_SERVER_CHANNEL_USER_LIST:
		return "chan list";      /* 408 */
	case MSG_SERVER_CHANNEL_USER_LIST_END:
		return "chan list end";      /* 409 */
	case MSG_SERVER_TOPIC:
		return "chan topic";     /* 410 */
	case MSG_CLIENT_CHANNEL_BAN_LIST:
		return "chan banlist";       /* 420 */
	case MSG_SERVER_CHANNEL_BAN_LIST:
		return "chan banlist";       /* 421 */
	case MSG_CLIENT_CHANNEL_BAN:
		return "chan ban";       /* 422 */
	case MSG_CLIENT_CHANNEL_UNBAN:
		return "chan unban";     /* 423 */
	case MSG_CLIENT_CHANNEL_CLEAR_BANS:
		return "chan clear bans";    /* 424 */
	case MSG_CLIENT_DOWNLOAD_FIREWALL:
		return "download firewall";  /* 500 */
	case MSG_SERVER_UPLOAD_FIREWALL:
		return "upload firewall";    /* 501 */
	case MSG_CLIENT_USERSPEED:
		return "user speed";     /* 600 */
	case MSG_SERVER_USER_SPEED:
		return "user speed";     /* 601 */
	case MSG_CLIENT_WHOIS:
		return "whois";          /* 603 */
	case MSG_SERVER_WHOIS_RESPONSE:
		return "whois";          /* 604 */
	case MSG_SERVER_WHOWAS:
		return "whowas";     /* 605 */
	case MSG_CLIENT_SETUSERLEVEL:
		return "level";          /* 606 */
	case MSG_SERVER_UPLOAD_REQUEST:
		return "upload request"; /* 607 */
	case MSG_CLIENT_UPLOAD_OK:
		return "upload ok";      /* 608 */
	case MSG_CLIENT_ACCEPT_FAILED:
		return "accept failed";      /* 609 */
	case MSG_CLIENT_KILL:
		return "kill";           /* 610 */
	case MSG_CLIENT_NUKE:
		return "nuke";           /* 611 */
	case MSG_CLIENT_BAN:
		return "ban";            /* 612 */
	case MSG_CLIENT_ALTER_PORT:
		return "alter port";     /* 613 */
	case MSG_CLIENT_UNBAN:
		return "unban";          /* 614 */
	case MSG_CLIENT_BANLIST:
		return "banlist";        /* 615 */
	case MSG_SERVER_IP_BANLIST:
		return "ip banlist";     /* 616 */
	case MSG_SERVER_CHANNEL_LIST_END:
		return "chan list end";      /* 617 */
	case MSG_SERVER_CHANNEL_LIST:
		return "chan list";      /* 618 */
	case MSG_CLIENT_LIMIT:
		return "queue limit";        /* 619 */
	case MSG_SERVER_LIMIT:
		return "queue limit";        /* 620 */
	case MSG_CLIENT_MOTD:
		return "motd";           /* 621 */
	case MSG_CLIENT_MUZZLE:
		return "muzzle";     /* 622 */
	case MSG_CLIENT_UNMUZZLE:
		return "unmuzzle";       /* 623 */
	case MSG_CLIENT_UNNUKE:
		return "unnuke?";        /* 624 */
	case MSG_CLIENT_ALTER_SPEED:
		return "alter speed";        /* 625 */
	case MSG_CLIENT_DATA_PORT_ERROR:
		return "data port error";    /* 626 */
	case MSG_CLIENT_WALLOP:
		return "wallop";     /* 627 */
	case MSG_CLIENT_ANNOUNCE:
		return "announce";       /* 628 */
	case MSG_SERVER_NICK_BANLIST:
		return "nick banlist";       /* 629 */
	case MSG_CLIENT_BROWSE_DIRECT:
		return "browse direct";      /* 640 */
	case MSG_SERVER_BROWSE_DIRECT_OK:
		return "browse direct ok";   /* 641 */
	case MSG_SERVER_BROWSE_DIRECT_ERR:
		return "browse direct error";    /* 642 */
	case MSG_CLIENT_CLOAK:
		return "cloak";          /* 652 */
	case MSG_CLIENT_CHANGE_SPEED:
		return "change_speed";       /* 700 */
	case MSG_CLIENT_CHANGE_PASS:
		return "change_pass";        /* 701 */
	case MSG_CLIENT_CHANGE_EMAIL:
		return "change_email";       /* 702 */
	case MSG_CLIENT_CHANGE_DATA_PORT:
		return "change_data_port";   /* 703 */
	case MSG_SERVER_GHOST:
		return "ghost";          /* 748 */
	case MSG_CLIENT_PING_SERVER:
		return "ping server";        /* 750 */
	case MSG_CLIENT_PING:
		return "ping";           /* 751 */
	case MSG_CLIENT_PONG:
		return "pong";           /* 752 */
	case MSG_CLIENT_ALTER_PASS:
		return "alter pass";     /* 753 */
	case MSG_CLIENT_SERVER_RECONFIG:
		return "server reconfig";    /* 800 */
	case MSG_CLIENT_SERVER_VERSION:
		return "server version"; /* 801 */
	case MSG_CLIENT_SERVER_CONFIG:
		return "server config";      /* 810 */
	case MSG_CLIENT_CLEAR_CHANNEL:
		return "clear channel";      /* 820 */
	case MSG_CLIENT_REDIRECT:
		return "redirect client";    /* 821 */
	case MSG_CLIENT_CYCLE:
		return "cycle client";       /* 822 */
	case MSG_CLIENT_SET_CHAN_LEVEL:
		return "channel level";      /* 823 */
	case MSG_CLIENT_EMOTE:
		return "emote";          /* 824 */
	case MSG_SERVER_NAMES_LIST:
		return "names list";     /* 825 */
	case MSG_CLIENT_CHANNEL_LIMIT:
		return "channel limit";      /* 826 */
	case MSG_CLIENT_FULL_CHANNEL_LIST:
		return "full chan list"; /* 827 */
	case MSG_SERVER_FULL_CHANNEL_INFO:
		return "full chan info"; /* 828 */
	case MSG_CLIENT_KICK:
		return "kick";           /* 829 */
	case MSG_CLIENT_NAMES_LIST:
		return "list users";     /* 830 */
	case MSG_CLIENT_GLOBAL_USER_LIST:
		return "global user list";   /* 831 */
	case MSG_SERVER_GLOBAL_USER_LIST:
		return "global user list";   /* 832 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_ADD_DIRECTORY:
		return "add_directory";      /* 870 */
#endif
	case 920:
		return "ignore_command"; /* 920 */
	case MSG_CLIENT_ADD_SERVER:
		return "add server";     /* 9998 */
	case MSG_CLIENT_LIST_SERVER:
		return "list server";        /* 9999 */
	case MSG_CLIENT_QUIT:
		return "client quit";        /* 10000 */
	case MSG_SERVER_LOGIN:
		return "server login";       /* 10010 */
	case MSG_SERVER_LOGIN_ACK:
		return "server login ack";   /* 10011 */
	case MSG_SERVER_USER_SHARING:
		return "user sharing";       /* 10012 */
	case MSG_SERVER_USER_IP:
		return "user ip";        /* 10013 */
	case MSG_SERVER_REGINFO:
		return "reginfo";        /* 10014 */
	case MSG_SERVER_REMOTE_SEARCH:
		return "remote search";      /* 10015 */
	case MSG_SERVER_REMOTE_SEARCH_RESULT:
		return "remote search result";   /* 10016 */
	case MSG_SERVER_REMOTE_SEARCH_END:
		return "remote search end";  /* 10017 */
	case MSG_SERVER_ENCAPSULATED:
		return "encapsulated";       /* 10018 */
	case MSG_SERVER_LINK_INFO:
		return "link info";      /* 10019 */
	case MSG_SERVER_QUIT:
		return "server disconnect";  /* 10020 - deprecated by 10101 */
	case MSG_SERVER_NOTIFY_MODS:
		return "remote notify_mods"; /* 10021 */
	case MSG_SERVER_SERVER_PONG:
		return "server pong";        /* 10022 */
	case MSG_SERVER_TIME_CHECK:
		return "time check";     /* 10023 */
	case MSG_SERVER_WHOIS_NOTIFY:
		return "whois notify";       /* 10024 */
	case MSG_CLIENT_USERFLAGS:
		return "change userflags";   /* 10050 */
	case MSG_CLIENT_CONNECT:
		return "server connect"; /* 10100 */
	case MSG_CLIENT_DISCONNECT:
		return "server disconnect";  /* 10101 */
	case MSG_CLIENT_KILL_SERVER:
		return "kill server";        /* 10110 */
	case MSG_CLIENT_REMOVE_SERVER:
		return "remove server";      /* 10111 */
	case MSG_CLIENT_LINKS:
		return "server links";       /* 10112 */
	case MSG_CLIENT_USAGE_STATS:
		return "server usage";       /* 10115 */
	case MSG_SERVER_SEARCH_STATS:
		return "search cache stats"; /* 10116 */
	case MSG_CLIENT_REHASH:
		return "rehash";     /* 10117 */
	case MSG_CLIENT_VERSION_STATS:
		return "client version stats";   /* 10118 */
	case MSG_CLIENT_WHICH_SERVER:
		return "which server";       /* 10119 */
	case MSG_CLIENT_PING_ALL_SERVERS:
		return "ping all servers";   /* 10120 */
	case MSG_CLIENT_WHO_WAS:
		return "whowas";     /* 10121 */
	case MSG_CLIENT_MASS_KILL:
		return "mass kill";      /* 10122 */
	case MSG_CLIENT_HISTOGRAM:
		return "histogram recv"; /* 10123 */
	case MSG_SERVER_HISTOGRAM:
		return "histogram recv end"; /* 10124 */
	case MSG_CLIENT_SHISTOGRAM:
		return "histogram send"; /* 10125 */ 
	case MSG_SERVER_SHISTOGRAM:
		return "histogram send end"; /* 10126 */ 
	case MSG_CLIENT_REGISTER_USER:
		return "register user";      /* 10200 */
	case MSG_CLIENT_USER_MODE:
		return "user mode cmd";      /* 10203 */
	case MSG_CLIENT_OP:
		return "chan op";        /* 10204 */
	case MSG_CLIENT_DEOP:
		return "chan deop";      /* 10205 */
	case MSG_CLIENT_CHANNEL_WALLOP:
		return "chan wallop";        /* 10208 */
	case MSG_CLIENT_CHANNEL_MODE:
		return "chan mode";      /* 10209 */
	case MSG_CLIENT_CHANNEL_INVITE:
		return "chan invite";        /* 10210 */
	case MSG_CLIENT_CHANNEL_VOICE:
		return "chan voice";     /* 10211 */
	case MSG_CLIENT_CHANNEL_UNVOICE:
		return "chan unvoice";       /* 10212 */
	case MSG_CLIENT_CHANNEL_MUZZLE:
		return "chan muzzle";        /* 10213 */
	case MSG_CLIENT_CHANNEL_UNMUZZLE:
		return "chan unmuzzle";      /* 10214 */
	case MSG_CLIENT_CLASS_ADD:
		return "acl generic add";    /* 10250 */
	case MSG_CLIENT_CLASS_DEL:
		return "acl generic del";    /* 10251 */
	case MSG_CLIENT_CLASS_LIST:
		return "acl generic list";   /* 10252 */
	case MSG_CLIENT_DLINE_ADD:
		return "acl d-line add"; /* 10253 */
	case MSG_CLIENT_DLINE_DEL:
		return "acl d-line del"; /* 10254 */
	case MSG_CLIENT_DLINE_LIST:
		return "acl d-line list";    /* 10255 */
	case MSG_CLIENT_ILINE_ADD:
		return "acl i-line add"; /* 10256 */
	case MSG_CLIENT_ILINE_DEL:
		return "acl i-line del"; /* 10257 */
	case MSG_CLIENT_ILINE_LIST:
		return "acl i-line list";    /* 10258 */
	case MSG_CLIENT_ELINE_ADD:
		return "acl e-line add"; /* 10259 */
	case MSG_CLIENT_ELINE_DEL:
		return "acl e-line del"; /* 10260 */
	case MSG_CLIENT_ELINE_LIST:
		return "acl e-line list";    /* 10261 */
	case MSG_SERVER_SYNC_END:
		return "server sync end";    /* 10262 */
	case MSG_SERVER_SYNC_END_ACK:      
		return "server sync end ack";/* 10263 */
	case MSG_CLIENT_LOG_LEVEL:
		return "change log level";
	case MSG_CLIENT_SHARE_FILE:
		return "share generic file"; /* 10300 */
	case MSG_CLIENT_BROWSE_NEW:
		return "browse new";     /* 10301 */
	case MSG_SERVER_BROWSE_RESULT_NEW:
		return "browse result new";  /* 10302 */
#ifdef USE_PROTNET  
	case MSG_CLIENT_RESYNC_USER:
		return "resync user";        /* 10303 */
	case MSG_CLIENT_DESYNC_USER:
		return "desync user";        /* 10304 */
#endif
	}
	return "unknown";
}

void add_shist( unsigned int tag, unsigned int len ) 
{
    LIST        *list;
    histogram_t *h;

    for (list = global.histOutList; list; list = list->next) 
	{
        h = list->data;
        if(tag == h->tag) 
		{
            h->count++;
            h->len += len;
            return;
        }
    }

    /* tag not found add one */
    while (1) 
    {   
        h = CALLOC(1, sizeof(histogram_t));
        if(!h)
            break;
        h->tag = tag;
        h->count = 1;
        h->len = len;
        list = CALLOC(1, sizeof(LIST));
        if(!list)
            break;
        list->data = h;
        list->next = global.histOutList;
        global.histOutList = list;
        return;
    }

    OUTOFMEMORY("add_shist");
    if(h)
        FREE(h);
    if(list)
        FREE(list);
    return;
}