diff --git a/client/packhand.c b/client/packhand.c
index ea53718..b1b38b2 100644
--- a/client/packhand.c
+++ b/client/packhand.c
@@ -308,6 +308,7 @@ void handle_server_join_reply(bool you_can_join, const char *message,
     log_verbose("join game accept:%s", message);
     client.conn.established = TRUE;
     client.conn.id = conn_id;
+    client.conn.header_size = packet_header_checked();
 
     agents_game_joined();
     set_server_busy(FALSE);
diff --git a/common/connection.c b/common/connection.c
index 8664c37..045d54c 100644
--- a/common/connection.c
+++ b/common/connection.c
@@ -584,6 +584,7 @@ void connection_common_init(struct connection *pconn)
 {
   pconn->established = FALSE;
   pconn->used = TRUE;
+  pconn->header_size = packet_header_initial();
   pconn->closing_reason = NULL;
   pconn->last_write = NULL;
   pconn->buffer = new_socket_packet_buffer();
diff --git a/common/connection.h b/common/connection.h
index 7109403..c859ccf 100644
--- a/common/connection.h
+++ b/common/connection.h
@@ -115,6 +115,11 @@ struct socket_packet_buffer {
   unsigned char *data;
 };
 
+struct packet_header {
+  unsigned int len : 4;         /* Actually 'enum data_size' */
+  unsigned int type : 4;        /* Actually 'enum data_size' */
+};
+
 #define SPECVEC_TAG byte
 #define SPECVEC_TYPE unsigned char
 #include "specvec.h"
@@ -128,6 +133,7 @@ struct connection {
   int sock;
   bool used;
   bool established;		/* have negotiated initial packets */
+  struct packet_header header_size;
   char *closing_reason;
 
   /* connection is "observer", not controller; may be observing
diff --git a/common/generate_packets.py b/common/generate_packets.py
index bb737a5..3e340d6 100755
--- a/common/generate_packets.py
+++ b/common/generate_packets.py
@@ -653,7 +653,7 @@ class Variant:
             self.extra_send_args2=self.extra_send_args2+', force_to_send'
             self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
 
-        self.receive_prototype='static struct %(packet_name)s *receive_%(name)s(struct connection *pc, enum packet_type type)'%self.__dict__
+        self.receive_prototype='static struct %(packet_name)s *receive_%(name)s(struct connection *pc)'%self.__dict__
         self.send_prototype='static int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
 
     # See Field.get_dict
@@ -763,7 +763,7 @@ static char *stats_%(name)s_names[] = {%(names)s};
         temp='''%(send_prototype)s
 {
 <real_packet1><delta_header>  SEND_PACKET_START(%(type)s);
-<log><report><pre1><body><pre2>  <post>SEND_PACKET_END;
+<log><report><pre1><body><pre2>  <post>SEND_PACKET_END(%(type)s);
 }
 
 '''
@@ -919,7 +919,7 @@ static char *stats_%(name)s_names[] = {%(names)s};
         if self.delta:
             delta_header='''  %(name)s_fields fields;
   struct %(packet_name)s *old;
-  struct genhash **hash = pc->phs.received + type;
+  struct genhash **hash = pc->phs.received + %(type)s;
 '''
             delta_body1="\n  DIO_BV_GET(&din, fields);\n"
             body1=""
@@ -1138,7 +1138,7 @@ class Packet:
             self.extra_send_args2=self.extra_send_args2+', force_to_send'
             self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
 
-        self.receive_prototype='struct %(name)s *receive_%(name)s(struct connection *pc, enum packet_type type)'%self.__dict__
+        self.receive_prototype='struct %(name)s *receive_%(name)s(struct connection *pc)'%self.__dict__
         self.send_prototype='int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
         if self.want_lsend:
             self.lsend_prototype='void lsend_%(name)s(struct conn_list *dest%(extra_send_args)s)'%self.__dict__
@@ -1273,7 +1273,7 @@ class Packet:
             no=v.no
             result=result+'''
   case %(no)s:
-    return receive_%(name2)s(pc, type);'''%self.get_dict(vars())
+    return receive_%(name2)s(pc);'''%self.get_dict(vars())
         result=result+'''
   default:
     log_debug("Unknown %(type)s variant for connection %%s", conn_description(pc));
@@ -1434,7 +1434,7 @@ def get_get_packet_helper(packets):
 '''
     body=""
     for p in packets:
-        body=body+"  case %(type)s:\n    return receive_%(name)s(pc, type);\n\n"%p.__dict__
+        body=body+"  case %(type)s:\n    return receive_%(name)s(pc);\n\n"%p.__dict__
     extro='''  default:
     log_packet("unknown packet type %d received from %s",
                type, conn_description(pc));
diff --git a/common/packets.c b/common/packets.c
index 309713f..d86ab35 100644
--- a/common/packets.c
+++ b/common/packets.c
@@ -172,11 +172,12 @@ bool conn_compression_thaw(struct connection *pconn)
 /**************************************************************************
   It returns the request id of the outgoing packet (or 0 if is_server()).
 **************************************************************************/
-int send_packet_data(struct connection *pc, unsigned char *data, int len)
+int send_packet_data(struct connection *pc, unsigned char *data, int len,
+                     enum packet_type packet_type)
 {
   /* default for the server */
   int result = 0;
-  int packet_type = ntohs((data[3] << 8) + data[2]);
+
 
   log_packet("sending packet type=%s(%d) len=%d to %s",
              packet_name(packet_type), packet_type, len,
@@ -329,12 +330,11 @@ void *get_packet_from_connection(struct connection *pc,
     enum packet_type type;
     int itype;
   } utype;
-  int typeb1, typeb2;
   struct data_in din;
 #ifdef USE_COMPRESSION
   bool compressed_packet = FALSE;
+  int header_size = 0;
 #endif
-  int header_size = 4;
   void *data;
 
   if (!pc->used) {
@@ -347,7 +347,7 @@ void *get_packet_from_connection(struct connection *pc,
   }
 
   dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
-  dio_get_uint16(&din, &len_read);
+  dio_get_uintx(&din, pc->header_size.len, &len_read);
 
   /* The non-compressed case */
   whole_packet_len = len_read;
@@ -377,6 +377,7 @@ void *get_packet_from_connection(struct connection *pc,
     return NULL;		/* not all data has been read */
   }
 
+#ifdef USE_COMPRESSION
   if (whole_packet_len < header_size) {
     log_verbose("The packet size is reported to be less than header alone. "
                 "The connection will be closed now.");
@@ -385,7 +386,6 @@ void *get_packet_from_connection(struct connection *pc,
     return NULL;
   }
 
-#ifdef USE_COMPRESSION
   if (compressed_packet) {
     uLong compressed_size = whole_packet_len - header_size;
     /* 
@@ -444,27 +444,17 @@ void *get_packet_from_connection(struct connection *pc,
 
   /*
    * At this point the packet is a plain uncompressed one. These have
-   * to have to be at least 4 bytes in size.
+   * to have to be at least the header bytes in size.
    */
-  if (whole_packet_len < 2+2) {
+  if (whole_packet_len < (data_size(pc->header_size.len)
+                          + data_size(pc->header_size.type))) {
     log_verbose("The packet stream is corrupt. The connection "
                 "will be closed now.");
     connection_close(pc, _("decoding error"));
     return NULL;
   }
 
-  /* Instead of one dio_get_uint16() we do twice dio_get_uint8().
-   * Older (<= 2.4) versions had 8bit type field, and we detect
-   * here if this is initial PACKET_SERVER_JOIN_REQ from such a client. */
-  dio_get_uint8(&din, &typeb1);
-
-  if (typeb1 == PACKET_SERVER_JOIN_REQ) {
-    utype.itype = typeb1;
-  } else {
-    dio_get_uint8(&din, &typeb2);
-    utype.itype = ntohs((typeb2 << 8) + typeb1);
-  }
-
+  dio_get_uintx(&din, pc->header_size.type, &utype.itype);
   utype.type = utype.itype;
 
   log_packet("got packet type=(%s)%d len=%d from %s",
@@ -547,6 +537,46 @@ void remove_packet_from_buffer(struct socket_packet_buffer *buffer)
 }
 
 /**************************************************************************
+  Returns the packet header field lengths used for the login protocol,
+  before the capability of the connection could be checked.
+
+  NB: These values cannot be changed for backward compatibility reasons.
+**************************************************************************/
+struct packet_header packet_header_initial(void)
+{
+  static const struct packet_header initial = {
+    .len = DATA_SIZE_16,
+    .type = DATA_SIZE_8
+  };
+
+  return initial;
+}
+
+/**************************************************************************
+  Returns the packet header field lengths used after the login protocol,
+  after the capability of the connection could be checked.
+**************************************************************************/
+struct packet_header packet_header_checked(void)
+{
+  static const struct packet_header checked = {
+    .len = DATA_SIZE_16,
+    .type = DATA_SIZE_16
+  };
+
+  return checked;
+}
+
+/**************************************************************************
+  Returns TRUE iff capabilities have been checked.
+**************************************************************************/
+bool packet_header_is_checked(struct packet_header header_size)
+{
+  struct packet_header checked = packet_header_checked();
+
+  return 0 == memcpy(&header_size, &checked, sizeof(header_size));
+}
+
+/**************************************************************************
   Sanity check packet
 **************************************************************************/
 bool packet_check(struct data_in *din, struct connection *pc)
@@ -557,8 +587,8 @@ bool packet_check(struct data_in *din, struct connection *pc)
     int type, len;
 
     dio_input_rewind(din);
-    dio_get_uint16(din, &len);
-    dio_get_uint16(din, &type);
+    dio_get_uintx(din, pc->header_size.len, &len);
+    dio_get_uintx(din, pc->header_size.type, &type);
 
     log_packet("received long packet (type %d, len %d, rem %lu) from %s",
                type,
diff --git a/common/packets.def b/common/packets.def
index 4b2353a..2ef32e6 100644
--- a/common/packets.def
+++ b/common/packets.def
@@ -62,8 +62,8 @@ Syntax:
     PACKET_SERVER_JOIN_REPLY are excluded here. These packets should
     never change their number. The packet number can be freely chosen
     as long as it is below 65536 and unique. For backward compatibility  
-    reasons using values from range 1024-1279 ((4x256)-(5*256-1))        
-    should be avoided. 
+    reasons, packets used for the initial protocol (notably before
+    checking the capabilities) must be in range 0-255.
 
    Packet flags:
    -------------
diff --git a/common/packets.h b/common/packets.h
index bd312dd..2d0d989 100644
--- a/common/packets.h
+++ b/common/packets.h
@@ -92,51 +92,45 @@ void generic_handle_player_attribute_chunk(struct player *pplayer,
 const char *packet_name(enum packet_type type);
 bool packet_has_game_info_flag(enum packet_type type);
 
+struct packet_header packet_header_initial(void);
+struct packet_header packet_header_checked(void);
+bool packet_header_is_checked(struct packet_header header_size);
+
 void pre_send_packet_player_attribute_chunk(struct connection *pc,
 					    struct packet_player_attribute_chunk
 					    *packet);
 
-#ifdef DEBUG
-#define PACKET_TYPE_SANITY(_type_) \
-  if (((_type_ & 0xff00) >> 8) == PACKET_SERVER_JOIN_REQ) { \
-    log_error("Packet type %s (%d) has upper byte matching old PACKET_SERVER_JOIN_REQ.", \
-              packet_name(_type_), _type_); \
-  }
-#else  /* DEBUG */
-#define PACKET_TYPE_SANITY(_type_)
-#endif /* DEBUG */
-
-#define SEND_PACKET_START(type) \
+#define SEND_PACKET_START(packet_type) \
   unsigned char buffer[MAX_LEN_PACKET]; \
   struct data_out dout; \
   \
   dio_output_init(&dout, buffer, sizeof(buffer)); \
-  dio_put_uint16(&dout, 0); \
-  dio_put_uint16(&dout, type); \
-  PACKET_TYPE_SANITY(type)
+  dio_put_uintx(&dout, pc->header_size.len, 0); \
+  dio_put_uintx(&dout, pc->header_size.type, packet_type);
 
-#define SEND_PACKET_END \
+#define SEND_PACKET_END(packet_type) \
   { \
     size_t size = dio_output_used(&dout); \
     \
     dio_output_rewind(&dout); \
-    dio_put_uint16(&dout, size); \
+    dio_put_uintx(&dout, pc->header_size.len, size); \
     fc_assert(!dout.too_short); \
-    return send_packet_data(pc, buffer, size); \
+    return send_packet_data(pc, buffer, size, packet_type); \
   }
 
-#define RECEIVE_PACKET_START(type, result) \
+#define RECEIVE_PACKET_START(packet_type, result) \
   struct data_in din; \
-  struct type packet_buf, *result = &packet_buf; \
+  struct packet_type packet_buf, *result = &packet_buf; \
   \
-  dio_input_init(&din, pc->buffer->data, 2); \
+  dio_input_init(&din, pc->buffer->data, data_size(pc->header_size.len)); \
   { \
     int size; \
   \
-    dio_get_uint16(&din, &size); \
+    dio_get_uintx(&din, pc->header_size.len, &size); \
     dio_input_init(&din, pc->buffer->data, MIN(size, pc->buffer->ndata)); \
   } \
-  dio_input_skip(&din, 4);
+  dio_input_skip(&din, (data_size(pc->header_size.len) \
+                        + data_size(pc->header_size.type)));
 
 #define RECEIVE_PACKET_END(result) \
   if (!packet_check(&din, pc)) { \
@@ -151,7 +145,8 @@ void pre_send_packet_player_attribute_chunk(struct connection *pc,
   log_packet("Error on field '" #field "'" __VA_ARGS__); \
   return NULL
 
-int send_packet_data(struct connection *pc, unsigned char *data, int len);
+int send_packet_data(struct connection *pc, unsigned char *data, int len,
+                     enum packet_type packet_type);
 bool packet_check(struct data_in *din, struct connection *pc);
 
 /* Utilities to exchange strings and string vectors. */
diff --git a/server/connecthand.c b/server/connecthand.c
index 91516aa..f3587a8 100644
--- a/server/connecthand.c
+++ b/server/connecthand.c
@@ -145,6 +145,7 @@ void establish_new_connection(struct connection *pconn)
   /* "establish" the connection */
   pconn->established = TRUE;
   pconn->server.status = AS_ESTABLISHED;
+  pconn->header_size = packet_header_checked();
 
   pconn->server.delegation.status = FALSE;
   pconn->server.delegation.playing = NULL;
diff --git a/server/sernet.c b/server/sernet.c
index a1acb50..6a97d9c 100644
--- a/server/sernet.c
+++ b/server/sernet.c
@@ -593,7 +593,7 @@ enum server_events server_sniff_all_input(void)
                         conn_description(pconn));
             connection_close_server(pconn, _("ping timeout"));
           }
-        } else {
+        } else if (packet_header_is_checked(pconn->header_size)) {
           connection_ping(pconn);
         }
       } conn_list_iterate_end;
@@ -1023,7 +1023,6 @@ int server_make_connection(int new_sock, const char *client_addr, const char *cl
 
       log_verbose("connection (%s) from %s (%s)", 
                   pconn->username, pconn->addr, pconn->server.ipaddr);
-      connection_ping(pconn);
       return 0;
     }
   }
