I originally submitted this as a patch for openssh-unix-dev as:

https://bugzilla.mindrot.org/show_bug.cgi?id=1733

about 8 months ago, but figured it would be quicker to get it in upstream.

The patch has 4 main changes:

(1) add new options to define the DSCP/Class-Selector values;

(2) add name-to-value mappings for the DSCP/Class-Selector values;

(3) add a parameter to keywords[] to specify whether an option can be
    user-specified (QoS bits usually should be set site-wide only by the
    site's network administrator);

(4) rather than passing in the interactive/non-interactive to
    packet_set_tos(), just pass in the desired QoS marking instead.

We've been using the patch in the astlinux project and it works fine.

Revised with man page updates as per Han's comment.

Signed-off-by: Philip Prindeville <[email protected]>
----
Index: ipclass.h
===================================================================
RCS file: ipclass.h
diff -N -u -p ipclass.h
--- /dev/null   21 Jun 2010 01:27:58 -0000
+++ ipclass.h   21 Jun 2010 07:27:56 -0000
@@ -0,0 +1,20 @@
+/*
+ * Temporarily needed file until glibc 2.12 becomes ubiquitous.
+ */
+#ifndef __IPCLASS_H__
+#define __IPCLASS_H__
+
+/* in glibc 2.12 */
+#ifndef IPTOS_CLASS_CS0
+#define IPTOS_CLASS_CS0                0x00
+#define IPTOS_CLASS_CS1                0x20
+#define IPTOS_CLASS_CS2                0x40
+#define IPTOS_CLASS_CS3                0x60
+#define IPTOS_CLASS_CS4                0x80
+#define IPTOS_CLASS_CS5                0xa0
+#define IPTOS_CLASS_CS6                0xc0
+#define IPTOS_CLASS_CS7                0xe0
+#endif
+
+#endif /* __IPCLASS_H__ */
+
Index: packet.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/packet.c,v
retrieving revision 1.166
diff -N -u -p packet.c
--- packet.c    27 Jun 2009 09:29:06 -0000      1.166
+++ packet.c    21 Jun 2010 07:27:56 -0000
@@ -74,6 +74,7 @@
 #include "misc.h"
 #include "ssh.h"
 #include "roaming.h"
+#include "readconf.h"

 #ifdef PACKET_DEBUG
 #define DBG(x) x
@@ -1716,10 +1717,8 @@ packet_not_very_much_data_to_write(void)
 }

 static void
-packet_set_tos(int interactive)
+packet_set_tos(int tos)
 {
-       int tos = interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT;
-
        if (!packet_connection_is_on_socket() ||
            !packet_connection_is_ipv4())
                return;
@@ -1732,7 +1731,7 @@ packet_set_tos(int interactive)
 /* Informs that the current session is interactive.  Sets IP flags for that. */

 void
-packet_set_interactive(int interactive)
+packet_set_interactive(int interactive, int qos[2])
 {
        if (active_state->set_interactive_called)
                return;
@@ -1745,7 +1744,7 @@ packet_set_interactive(int interactive)
        if (!packet_connection_is_on_socket())
                return;
        set_nodelay(active_state->connection_in);
-       packet_set_tos(interactive);
+       packet_set_tos((u_char) (interactive ? qos[1] : qos[0]));
 }

 /* Returns true if the current connection is interactive. */
Index: packet.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/packet.h,v
retrieving revision 1.52
diff -N -u -p packet.h
--- packet.h    27 Jun 2009 09:29:06 -0000      1.52
+++ packet.h    21 Jun 2010 07:27:56 -0000
@@ -31,7 +31,7 @@ u_int  packet_get_encryption_key(u_char *);
 void     packet_set_protocol_flags(u_int);
 u_int   packet_get_protocol_flags(void);
 void     packet_start_compression(int);
-void     packet_set_interactive(int);
+void     packet_set_interactive(int, int [2]);
 int      packet_is_interactive(void);
 void     packet_set_server(void);
 void     packet_set_authenticated(void);
Index: readconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/readconf.c,v
retrieving revision 1.184
diff -N -u -p readconf.c
--- readconf.c  16 May 2010 12:55:51 -0000      1.184
+++ readconf.c  21 Jun 2010 07:27:56 -0000
@@ -40,6 +40,12 @@
 #include "kex.h"
 #include "mac.h"

+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifndef IPTOS_CLASS_CS0
+#include "ipclass.h"
+#endif
+
 /* Format of the configuration file:

    # Configuration data is parsed as follows:
@@ -128,6 +134,7 @@ typedef enum {
        oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
        oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
        oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
+       oUseQoS,
        oDeprecated, oUnsupported
 } OpCodes;

@@ -135,107 +142,109 @@ typedef enum {

 static struct {
        const char *name;
+       int restricted;
        OpCodes opcode;
 } keywords[] = {
-       { "forwardagent", oForwardAgent },
-       { "forwardx11", oForwardX11 },
-       { "forwardx11trusted", oForwardX11Trusted },
-       { "exitonforwardfailure", oExitOnForwardFailure },
-       { "xauthlocation", oXAuthLocation },
-       { "gatewayports", oGatewayPorts },
-       { "useprivilegedport", oUsePrivilegedPort },
-       { "rhostsauthentication", oDeprecated },
-       { "passwordauthentication", oPasswordAuthentication },
-       { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
-       { "kbdinteractivedevices", oKbdInteractiveDevices },
-       { "rsaauthentication", oRSAAuthentication },
-       { "pubkeyauthentication", oPubkeyAuthentication },
-       { "dsaauthentication", oPubkeyAuthentication },                   /* 
alias */
-       { "rhostsrsaauthentication", oRhostsRSAAuthentication },
-       { "hostbasedauthentication", oHostbasedAuthentication },
-       { "challengeresponseauthentication", oChallengeResponseAuthentication },
-       { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
-       { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
-       { "kerberosauthentication", oUnsupported },
-       { "kerberostgtpassing", oUnsupported },
-       { "afstokenpassing", oUnsupported },
+       { "forwardagent",             0, oForwardAgent },
+       { "forwardx11",                       0, oForwardX11 },
+       { "forwardx11trusted",                0, oForwardX11Trusted },
+       { "exitonforwardfailure",     0, oExitOnForwardFailure },
+       { "xauthlocation",            0, oXAuthLocation },
+       { "gatewayports",             0, oGatewayPorts },
+       { "useprivilegedport",                0, oUsePrivilegedPort },
+       { "rhostsauthentication",     0, oDeprecated },
+       { "passwordauthentication",   0, oPasswordAuthentication },
+       { "kbdinteractiveauthentication", 0, oKbdInteractiveAuthentication },
+       { "kbdinteractivedevices",    0, oKbdInteractiveDevices },
+       { "rsaauthentication",                0, oRSAAuthentication },
+       { "pubkeyauthentication",     0, oPubkeyAuthentication },
+       { "dsaauthentication",                0, oPubkeyAuthentication },       
          /* alias */
+       { "rhostsrsaauthentication",  0, oRhostsRSAAuthentication },
+       { "hostbasedauthentication",  0, oHostbasedAuthentication },
+       { "challengeresponseauthentication", 0, 
oChallengeResponseAuthentication },
+       { "skeyauthentication",               0, 
oChallengeResponseAuthentication }, /* alias */
+       { "tisauthentication",                0, 
oChallengeResponseAuthentication },  /* alias */
+       { "kerberosauthentication",   0, oUnsupported },
+       { "kerberostgtpassing",               0, oUnsupported },
+       { "afstokenpassing",          0, oUnsupported },
 #if defined(GSSAPI)
-       { "gssapiauthentication", oGssAuthentication },
-       { "gssapidelegatecredentials", oGssDelegateCreds },
+       { "gssapiauthentication",     0, oGssAuthentication },
+       { "gssapidelegatecredentials",        0, oGssDelegateCreds },
 #else
-       { "gssapiauthentication", oUnsupported },
-       { "gssapidelegatecredentials", oUnsupported },
+       { "gssapiauthentication",     0, oUnsupported },
+       { "gssapidelegatecredentials",        0, oUnsupported },
 #endif
-       { "fallbacktorsh", oDeprecated },
-       { "usersh", oDeprecated },
-       { "identityfile", oIdentityFile },
-       { "identityfile2", oIdentityFile },                   /* obsolete */
-       { "identitiesonly", oIdentitiesOnly },
-       { "hostname", oHostName },
-       { "hostkeyalias", oHostKeyAlias },
-       { "proxycommand", oProxyCommand },
-       { "port", oPort },
-       { "cipher", oCipher },
-       { "ciphers", oCiphers },
-       { "macs", oMacs },
-       { "protocol", oProtocol },
-       { "remoteforward", oRemoteForward },
-       { "localforward", oLocalForward },
-       { "user", oUser },
-       { "host", oHost },
-       { "escapechar", oEscapeChar },
-       { "globalknownhostsfile", oGlobalKnownHostsFile },
-       { "globalknownhostsfile2", oGlobalKnownHostsFile2 },  /* obsolete */
-       { "userknownhostsfile", oUserKnownHostsFile },
-       { "userknownhostsfile2", oUserKnownHostsFile2 },      /* obsolete */
-       { "connectionattempts", oConnectionAttempts },
-       { "batchmode", oBatchMode },
-       { "checkhostip", oCheckHostIP },
-       { "stricthostkeychecking", oStrictHostKeyChecking },
-       { "compression", oCompression },
-       { "compressionlevel", oCompressionLevel },
-       { "tcpkeepalive", oTCPKeepAlive },
-       { "keepalive", oTCPKeepAlive },                               /* 
obsolete */
-       { "numberofpasswordprompts", oNumberOfPasswordPrompts },
-       { "loglevel", oLogLevel },
-       { "dynamicforward", oDynamicForward },
-       { "preferredauthentications", oPreferredAuthentications },
-       { "hostkeyalgorithms", oHostKeyAlgorithms },
-       { "bindaddress", oBindAddress },
+       { "fallbacktorsh",            0, oDeprecated },
+       { "usersh",                   0, oDeprecated },
+       { "identityfile",             0, oIdentityFile },
+       { "identityfile2",            0, oIdentityFile },                     
/* obsolete */
+       { "identitiesonly",           0, oIdentitiesOnly },
+       { "hostname",                 0, oHostName },
+       { "hostkeyalias",             0, oHostKeyAlias },
+       { "proxycommand",             0, oProxyCommand },
+       { "port",                     0, oPort },
+       { "cipher",                   0, oCipher },
+       { "ciphers",                  0, oCiphers },
+       { "macs",                     0, oMacs },
+       { "protocol",                 0, oProtocol },
+       { "remoteforward",            0, oRemoteForward },
+       { "localforward",             0, oLocalForward },
+       { "user",                     0, oUser },
+       { "host",                     0, oHost },
+       { "escapechar",                       0, oEscapeChar },
+       { "globalknownhostsfile",     0, oGlobalKnownHostsFile },
+       { "globalknownhostsfile2",    0, oGlobalKnownHostsFile2 },    /* 
obsolete */
+       { "userknownhostsfile",               0, oUserKnownHostsFile },
+       { "userknownhostsfile2",      0, oUserKnownHostsFile2 },      /* 
obsolete */
+       { "connectionattempts",               0, oConnectionAttempts },
+       { "batchmode",                        0, oBatchMode },
+       { "checkhostip",              0, oCheckHostIP },
+       { "stricthostkeychecking",    0, oStrictHostKeyChecking },
+       { "compression",              0, oCompression },
+       { "compressionlevel",         0, oCompressionLevel },
+       { "tcpkeepalive",             0, oTCPKeepAlive },
+       { "keepalive",                        0, oTCPKeepAlive },               
              /* obsolete */
+       { "numberofpasswordprompts",  0, oNumberOfPasswordPrompts },
+       { "loglevel",                 0, oLogLevel },
+       { "dynamicforward",           0, oDynamicForward },
+       { "preferredauthentications", 0, oPreferredAuthentications },
+       { "hostkeyalgorithms",                0, oHostKeyAlgorithms },
+       { "bindaddress",              0, oBindAddress },
 #ifdef ENABLE_PKCS11
-       { "smartcarddevice", oPKCS11Provider },
-       { "pkcs11provider", oPKCS11Provider },
+       { "smartcarddevice",          0, oPKCS11Provider },
+       { "pkcs11provider",           0, oPKCS11Provider },
 #else
-       { "smartcarddevice", oUnsupported },
-       { "pkcs11provider", oUnsupported },
+       { "smartcarddevice",          0, oUnsupported },
+       { "pkcs11provider",           0, oUnsupported },
 #endif
-       { "clearallforwardings", oClearAllForwardings },
-       { "enablesshkeysign", oEnableSSHKeysign },
-       { "verifyhostkeydns", oVerifyHostKeyDNS },
-       { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost 
},
-       { "rekeylimit", oRekeyLimit },
-       { "connecttimeout", oConnectTimeout },
-       { "addressfamily", oAddressFamily },
-       { "serveraliveinterval", oServerAliveInterval },
-       { "serveralivecountmax", oServerAliveCountMax },
-       { "sendenv", oSendEnv },
-       { "controlpath", oControlPath },
-       { "controlmaster", oControlMaster },
-       { "hashknownhosts", oHashKnownHosts },
-       { "tunnel", oTunnel },
-       { "tunneldevice", oTunnelDevice },
-       { "localcommand", oLocalCommand },
-       { "permitlocalcommand", oPermitLocalCommand },
-       { "visualhostkey", oVisualHostKey },
-       { "useroaming", oUseRoaming },
+       { "clearallforwardings",      0, oClearAllForwardings },
+       { "enablesshkeysign",         0, oEnableSSHKeysign },
+       { "verifyhostkeydns",         0, oVerifyHostKeyDNS },
+       { "nohostauthenticationforlocalhost", 0, 
oNoHostAuthenticationForLocalhost },
+       { "rekeylimit",                       0, oRekeyLimit },
+       { "connecttimeout",           0, oConnectTimeout },
+       { "addressfamily",            0, oAddressFamily },
+       { "serveraliveinterval",      0, oServerAliveInterval },
+       { "serveralivecountmax",      0, oServerAliveCountMax },
+       { "sendenv",                  0, oSendEnv },
+       { "controlpath",              0, oControlPath },
+       { "controlmaster",            0, oControlMaster },
+       { "hashknownhosts",           0, oHashKnownHosts },
+       { "tunnel",                   0, oTunnel },
+       { "tunneldevice",             0, oTunnelDevice },
+       { "localcommand",             0, oLocalCommand },
+       { "permitlocalcommand",               0, oPermitLocalCommand },
+       { "visualhostkey",            0, oVisualHostKey },
+       { "useroaming",                       0, oUseRoaming },
+       { "useqos",                   1, oUseQoS},
 #ifdef JPAKE
-       { "zeroknowledgepasswordauthentication",
+       { "zeroknowledgepasswordauthentication", 0,
            oZeroKnowledgePasswordAuthentication },
 #else
-       { "zeroknowledgepasswordauthentication", oUnsupported },
+       { "zeroknowledgepasswordauthentication", 0, oUnsupported },
 #endif

-       { NULL, oBadOption }
+       { NULL,                         0, oBadOption }
 };

 /*
@@ -306,19 +315,69 @@ clear_forwardings(Options *options)
  */

 static OpCodes
-parse_token(const char *cp, const char *filename, int linenum)
+parse_token(const char *cp, const char *filename, int linenum, int *restricted)
 {
        u_int i;

        for (i = 0; keywords[i].name; i++)
-               if (strcasecmp(cp, keywords[i].name) == 0)
+               if (strcasecmp(cp, keywords[i].name) == 0) {
+                       *restricted= keywords[i].restricted;
                        return keywords[i].opcode;
+               }

        error("%s: line %d: Bad configuration option: %s",
            filename, linenum, cp);
        return oBadOption;
 }

+struct {
+       const char *name;
+       int value;
+} qos[] = {
+       { "cs0",      IPTOS_CLASS_CS0 },
+       { "cs1",      IPTOS_CLASS_CS1 },
+       { "cs2",      IPTOS_CLASS_CS2 },
+       { "cs3",      IPTOS_CLASS_CS3 },
+       { "cs4",      IPTOS_CLASS_CS4 },
+       { "cs5",      IPTOS_CLASS_CS5 },
+       { "cs6",      IPTOS_CLASS_CS6 },
+       { "cs7",      IPTOS_CLASS_CS7 },
+       { "af11",     IPTOS_DSCP_AF11 },
+       { "af12",     IPTOS_DSCP_AF12 },
+       { "af13",     IPTOS_DSCP_AF13 },
+       { "af21",     IPTOS_DSCP_AF21 },
+       { "af22",     IPTOS_DSCP_AF22 },
+       { "af23",     IPTOS_DSCP_AF23 },
+       { "af31",     IPTOS_DSCP_AF31 },
+       { "af32",     IPTOS_DSCP_AF32 },
+       { "af33",     IPTOS_DSCP_AF33 },
+       { "af41",     IPTOS_DSCP_AF41 },
+       { "af42",     IPTOS_DSCP_AF42 },
+       { "af43",     IPTOS_DSCP_AF43 },
+       { "ef",               IPTOS_DSCP_EF   },
+       { "lowdelay", IPTOS_LOWDELAY  },
+       { "throughput",       IPTOS_THROUGHPUT },
+       { "reliability", IPTOS_RELIABILITY },
+#ifdef IPTOS_LOWCOST
+       { "lowcost",  IPTOS_LOWCOST   },
+#endif
+#ifdef IPTOS_MINCOST
+       { "mincost",  IPTOS_MINCOST   },
+#endif
+       { "none",     IPTOS_CLASS_CS0 },
+       { NULL,         -1              },
+};
+
+static int parse_qos(const char *cp)
+{
+       u_int i;
+
+       for (i = 0; qos[i].name; i++)
+               if (strcasecmp(cp, qos[i].name) == 0)
+                       return qos[i].value;
+       return -1;
+}
+
 /*
  * Processes a single option line as used in the configuration files. This
  * only sets those values that have not already been set.
@@ -328,10 +387,10 @@ parse_token(const char *cp, const char *filename, int
 int
 process_config_line(Options *options, const char *host,
                    char *line, const char *filename, int linenum,
-                   int *activep)
+                   int *activep, int systemwide)
 {
        char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
-       int opcode, *intptr, value, value2, scale;
+       int opcode, *intptr, value, value2, scale, restricted;
        LogLevel *log_level_ptr;
        long long orig, val64;
        size_t len;
@@ -354,8 +413,12 @@ process_config_line(Options *options, const char *host
        if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
                return 0;

-       opcode = parse_token(keyword, filename, linenum);
+       opcode = parse_token(keyword, filename, linenum, &restricted);

+       if (restricted && !systemwide) {
+               fatal("%s line %d: not permitted in user profile.", filename, 
linenum);
+       }
+
        switch (opcode) {
        case oBadOption:
                /* don't panic, but count bad options */
@@ -917,6 +980,27 @@ parse_int:
                intptr = &options->use_roaming;
                goto parse_flag;

+       case oUseQoS:
+               arg = strdelim(&s);
+               if (arg == NULL || *arg == '\0')
+                       fatal("%.200s line %d: Missing non-interactive QoS 
argument.",
+                           filename, linenum);
+
+               arg2 = strdelim(&s);
+               if (arg2 == NULL || *arg2 == '\0')
+                       fatal("%.200s line %d: Missing interactive QoS 
argument.",
+                           filename, linenum);
+
+               value = parse_qos(arg);
+               value2 = parse_qos(arg2);
+               if (value == -1 || value2 == -1)
+                       fatal("%.200s line %d: Bad QoS argument.",
+                           filename, linenum);
+
+               options->use_qos[0] = value;
+               options->use_qos[1] = value2;
+               break;
+
        case oDeprecated:
                debug("%s line %d: Deprecated option \"%s\"",
                    filename, linenum, keyword);
@@ -948,7 +1032,7 @@ parse_int:

 int
 read_config_file(const char *filename, const char *host, Options *options,
-    int checkperm)
+    int checkperm, int systemwide)
 {
        FILE *f;
        char line[1024];
@@ -979,7 +1063,7 @@ read_config_file(const char *filename, const char *hos
        while (fgets(line, sizeof(line), f)) {
                /* Update line number counter. */
                linenum++;
-               if (process_config_line(options, host, line, filename, linenum, 
&active) != 0)
+               if (process_config_line(options, host, line, filename, linenum, 
&active, systemwide) != 0)
                        bad_options++;
        }
        fclose(f);
@@ -1067,6 +1151,8 @@ initialize_options(Options * options)
        options->local_command = NULL;
        options->permit_local_command = -1;
        options->use_roaming = -1;
+       options->use_qos[0] = -1;
+       options->use_qos[1] = -1;
        options->visual_host_key = -1;
        options->zero_knowledge_password_authentication = -1;
 }
@@ -1215,6 +1301,10 @@ fill_default_options(Options * options)
        /* options->hostname will be set in the main program if appropriate */
        /* options->host_key_alias should not be set by default */
        /* options->preferred_authentications will be set in ssh */
+       if (options->use_qos[0] == -1)
+               options->use_qos[0] = IPTOS_THROUGHPUT;
+       if (options->use_qos[1] == -1)
+               options->use_qos[1] = IPTOS_LOWDELAY;
 }

 /*
Index: readconf.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/readconf.h,v
retrieving revision 1.83
diff -N -u -p readconf.h
--- readconf.h  16 May 2010 12:55:51 -0000      1.83
+++ readconf.h  21 Jun 2010 07:27:56 -0000
@@ -126,6 +126,8 @@ typedef struct {

        int     use_roaming;

+       int     use_qos[2];
+
 }       Options;

 #define SSHCTL_MASTER_NO       0
@@ -136,11 +138,11 @@ typedef struct {

 void     initialize_options(Options *);
 void     fill_default_options(Options *);
-int     read_config_file(const char *, const char *, Options *, int);
+int     read_config_file(const char *, const char *, Options *, int, int);
 int     parse_forward(Forward *, const char *, int, int);

 int
-process_config_line(Options *, const char *, char *, const char *, int, int *);
+process_config_line(Options *, const char *, char *, const char *, int, int *, 
int);

 void    add_local_forward(Options *, const Forward *);
 void    add_remote_forward(Options *, const Forward *);
Index: servconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.c,v
retrieving revision 1.208
diff -N -u -p servconf.c
--- servconf.c  7 May 2010 11:30:29 -0000       1.208
+++ servconf.c  21 Jun 2010 07:27:56 -0000
@@ -40,6 +40,13 @@
 #include "channels.h"
 #include "groupaccess.h"

+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#ifndef IPTOS_CLASS_CS0
+#include "ipclass.h"
+#endif
+
 static void add_listen_addr(ServerOptions *, char *, int);
 static void add_one_listen_addr(ServerOptions *, char *, int);

@@ -125,6 +132,8 @@ initialize_server_options(ServerOptions *options)
        options->revoked_keys_file = NULL;
        options->trusted_user_ca_keys = NULL;
        options->authorized_principals_file = NULL;
+       options->use_qos[0] = -1;
+       options->use_qos[1] = -1;
 }

 void
@@ -254,6 +263,10 @@ fill_default_server_options(ServerOptions *options)
                options->permit_tun = SSH_TUNMODE_NO;
        if (options->zero_knowledge_password_authentication == -1)
                options->zero_knowledge_password_authentication = 0;
+       if (options->use_qos[0] == -1)
+               options->use_qos[0] = IPTOS_THROUGHPUT;
+       if (options->use_qos[1] == -1)
+               options->use_qos[1] = IPTOS_LOWDELAY;

        /* Turn privilege separation on by default */
        if (use_privsep == -1)
@@ -287,6 +300,7 @@ typedef enum {
        sUsePrivilegeSeparation, sAllowAgentForwarding,
        sZeroKnowledgePasswordAuthentication, sHostCertificate,
        sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+       sUseQoS,
        sDeprecated, sUnsupported
 } ServerOpCodes;

@@ -397,6 +411,7 @@ static struct {
        { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
        { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
        { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_GLOBAL 
},
+       { "useqos", sUseQoS, SSHCFG_ALL },
        { NULL, sBadOption, 0 }
 };

@@ -432,6 +447,54 @@ parse_token(const char *cp, const char *filename,
        return sBadOption;
 }

+struct {
+       const char *name;
+       int value;
+} qos[] = {
+       { "cs0",      IPTOS_CLASS_CS0 },
+       { "cs1",      IPTOS_CLASS_CS1 },
+       { "cs2",      IPTOS_CLASS_CS2 },
+       { "cs3",      IPTOS_CLASS_CS3 },
+       { "cs4",      IPTOS_CLASS_CS4 },
+       { "cs5",      IPTOS_CLASS_CS5 },
+       { "cs6",      IPTOS_CLASS_CS6 },
+       { "cs7",      IPTOS_CLASS_CS7 },
+       { "af11",     IPTOS_DSCP_AF11 },
+       { "af12",     IPTOS_DSCP_AF12 },
+       { "af13",     IPTOS_DSCP_AF13 },
+       { "af21",     IPTOS_DSCP_AF21 },
+       { "af22",     IPTOS_DSCP_AF22 },
+       { "af23",     IPTOS_DSCP_AF23 },
+       { "af31",     IPTOS_DSCP_AF31 },
+       { "af32",     IPTOS_DSCP_AF32 },
+       { "af33",     IPTOS_DSCP_AF33 },
+       { "af41",     IPTOS_DSCP_AF41 },
+       { "af42",     IPTOS_DSCP_AF42 },
+       { "af43",     IPTOS_DSCP_AF43 },
+       { "ef",               IPTOS_DSCP_EF   },
+       { "lowdelay", IPTOS_LOWDELAY  },
+       { "throughput",       IPTOS_THROUGHPUT },
+       { "reliability", IPTOS_RELIABILITY },
+#ifdef IPTOS_LOWCOST
+       { "lowcost",  IPTOS_LOWCOST   },
+#endif
+#ifdef IPTOS_MINCOST
+       { "mincost",  IPTOS_MINCOST   },
+#endif
+       { "none",     IPTOS_CLASS_CS0 },
+       { NULL,         -1              },
+};
+
+static int parse_qos(const char *cp)
+{
+       u_int i;
+
+       for (i = 0; qos[i].name; i++)
+               if (strcasecmp(cp, qos[i].name) == 0)
+                       return qos[i].value;
+       return -1;
+}
+
 char *
 derelativise_path(const char *path)
 {
@@ -625,8 +688,8 @@ process_server_config_line(ServerOptions *options, cha
     const char *filename, int linenum, int *activep, const char *user,
     const char *host, const char *address)
 {
-       char *cp, **charptr, *arg, *p;
-       int cmdline = 0, *intptr, value, n;
+       char *cp, **charptr, *arg, *arg2, *p;
+       int cmdline = 0, *intptr, value, value2, n;
        SyslogFacility *log_facility_ptr;
        LogLevel *log_level_ptr;
        ServerOpCodes opcode;
@@ -1307,6 +1370,27 @@ process_server_config_line(ServerOptions *options, cha
        case sRevokedKeys:
                charptr = &options->revoked_keys_file;
                goto parse_filename;
+
+       case sUseQoS:
+               arg = strdelim(&cp);
+               if (arg == NULL || *arg == '\0')
+                       fatal("%.200s line %d: Missing non-interactive QoS 
argument.",
+                           filename, linenum);
+
+               arg2 = strdelim(&cp);
+               if (arg2 == NULL || *arg2 == '\0')
+                       fatal("%.200s line %d: Missing interactive QoS 
argument.",
+                           filename, linenum);
+
+               value = parse_qos(arg);
+               value2 = parse_qos(arg2);
+               if (value == -1 || value2 == -1)
+                       fatal("%.200s line %d: Bad QoS argument.",
+                           filename, linenum);
+
+               options->use_qos[0] = value;
+               options->use_qos[1] = value2;
+               break;

        case sDeprecated:
                logit("%s line %d: Deprecated option %s",
Index: servconf.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.h,v
retrieving revision 1.93
diff -N -u -p servconf.h
--- servconf.h  7 May 2010 11:30:30 -0000       1.93
+++ servconf.h  21 Jun 2010 07:27:56 -0000
@@ -155,6 +155,8 @@ typedef struct {
        char   *revoked_keys_file;
        char   *trusted_user_ca_keys;
        char   *authorized_principals_file;
+
+       int     use_qos[2];
 }       ServerOptions;

 void    initialize_server_options(ServerOptions *);
Index: session.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/session.c,v
retrieving revision 1.254
diff -N -u -p session.c
--- session.c   18 Jun 2010 03:16:03 -0000      1.254
+++ session.c   21 Jun 2010 07:27:56 -0000
@@ -587,7 +587,7 @@ do_exec_no_pty(Session *s, const char *command)

        s->pid = pid;
        /* Set interactive/non-interactive mode. */
-       packet_set_interactive(s->display != NULL);
+       packet_set_interactive(s->display != NULL, options.use_qos);

 #ifdef USE_PIPES
        /* We are the parent.  Close the child sides of the pipes. */
@@ -715,7 +715,7 @@ do_exec_pty(Session *s, const char *command)

        /* Enter interactive session. */
        s->ptymaster = ptymaster;
-       packet_set_interactive(1);
+       packet_set_interactive(1, options.use_qos);
        if (compat20) {
                session_set_fds(s, ptyfd, fdout, -1, 1);
        } else {
Index: ssh-keysign.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/ssh-keysign.c,v
retrieving revision 1.30
diff -N -u -p ssh-keysign.c
--- ssh-keysign.c       13 Jan 2010 01:20:20 -0000      1.30
+++ ssh-keysign.c       21 Jun 2010 07:27:56 -0000
@@ -176,7 +176,7 @@ main(int argc, char **argv)

        /* verify that ssh-keysign is enabled by the admin */
        initialize_options(&options);
-       (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0);
+       (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0, 1);
        fill_default_options(&options);
        if (options.enable_ssh_keysign != 1)
                fatal("ssh-keysign not enabled in %s",
Index: ssh.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/ssh.c,v
retrieving revision 1.338
diff -N -u -p ssh.c
--- ssh.c       16 May 2010 12:55:51 -0000      1.338
+++ ssh.c       21 Jun 2010 07:27:56 -0000
@@ -522,7 +522,7 @@ main(int ac, char **av)
                        dummy = 1;
                        line = xstrdup(optarg);
                        if (process_config_line(&options, host ? host : "",
-                           line, "command-line", 0, &dummy) != 0)
+                           line, "command-line", 0, &dummy, 0) != 0)
                                exit(255);
                        xfree(line);
                        break;
@@ -632,18 +632,18 @@ main(int ac, char **av)
         * file if the user specifies a config file on the command line.
         */
        if (config != NULL) {
-               if (!read_config_file(config, host, &options, 0))
+               if (!read_config_file(config, host, &options, 0, 0))
                        fatal("Can't open user config file %.100s: "
                            "%.100s", config, strerror(errno));
        } else {
                r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
                    _PATH_SSH_USER_CONFFILE);
                if (r > 0 && (size_t)r < sizeof(buf))
-                       (void)read_config_file(buf, host, &options, 1);
+                       (void)read_config_file(buf, host, &options, 1, 0);

                /* Read systemwide configuration file after use config. */
                (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
-                   &options, 0);
+                   &options, 0, 1);
        }

        /* Fill configuration defaults. */
@@ -1095,7 +1095,7 @@ ssh_session(void)
                }
        }
        /* Tell the packet module whether this is an interactive session. */
-       packet_set_interactive(interactive);
+       packet_set_interactive(interactive, options.use_qos);

        /* Request authentication agent forwarding if appropriate. */
        check_agent_present();
@@ -1192,7 +1192,7 @@ ssh_session2_setup(int id, int success, void *arg)
        client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
            NULL, fileno(stdin), &command, environ);

-       packet_set_interactive(interactive);
+       packet_set_interactive(interactive, options.use_qos);
 }

 /* open new channel for a session */
Index: ssh_config
===================================================================
RCS file: /cvs/src/usr.bin/ssh/ssh_config,v
retrieving revision 1.26
diff -N -u -p ssh_config
--- ssh_config  11 Jan 2010 01:39:46 -0000      1.26
+++ ssh_config  21 Jun 2010 07:27:56 -0000
@@ -45,3 +45,4 @@
 #   PermitLocalCommand no
 #   VisualHostKey no
 #   ProxyCommand ssh -q -W %h:%p gateway.example.com
+#   UseQoS throughput lowdelay
Index: ssh_config.5
===================================================================
RCS file: /cvs/src/usr.bin/ssh/ssh_config.5,v
retrieving revision 1.133
diff -N -u -p ssh_config.5
--- ssh_config.5        16 Apr 2010 06:45:01 -0000      1.133
+++ ssh_config.5        21 Jun 2010 07:27:56 -0000
@@ -1050,6 +1050,38 @@ Specifies the user to log in as.
 This can be useful when a different user name is used on different machines.
 This saves the trouble of
 having to remember to give the user name on the command line.
+.It Cm UseQoS
+Specifies how
+.Xr ssh 1
+applies IP TOS (type of service) marking to traffic.  It takes two values,
+one for non-interactive traffic (\c
+.Xr scp 1
+or
+.Xr ssh 1
+being run with a command), and another for interactive traffic.
+Values may be
+.Dq cs0 ,
+.Dq cs1 ,
+\&...
+.Dq cs7 ,
+.Dq af11 ,
+.Dq af12 ,
+\&...
+.Dq af43 ,
+.Dq ef ,
+.Dq lowdelay ,
+.Dq throughput ,
+etc.  The default is
+.Dq cs0
+for both.  In an RFC-4594 environment,
+.Dq cs2
+and
+.Dq af41
+would be used, respectively.  Legacy behavior would
+.Dq throughput
+and
+.Dq lowdelay ,
+respectively.
 .It Cm UserKnownHostsFile
 Specifies a file to use for the user
 host key database instead of
Index: sshd_config
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd_config,v
retrieving revision 1.81
diff -N -u -p sshd_config
--- sshd_config 8 Oct 2009 14:03:41 -0000       1.81
+++ sshd_config 21 Jun 2010 07:27:56 -0000
@@ -97,6 +97,9 @@
 # override default of no subsystems
 Subsystem      sftp    /usr/libexec/sftp-server

+# traditional ToS (deprecated: consider using af12 and cs2)
+#UseQoS throughput lowdelay
+
 # Example of overriding settings on a per-user basis
 #Match User anoncvs
 #      X11Forwarding no
Index: sshd_config.5
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd_config.5,v
retrieving revision 1.122
diff -N -u -p sshd_config.5
--- sshd_config.5       7 May 2010 12:49:17 -0000       1.122
+++ sshd_config.5       21 Jun 2010 07:27:58 -0000
@@ -985,6 +985,38 @@ The goal of privilege separation is to prevent privile
 escalation by containing any corruption within the unprivileged processes.
 The default is
 .Dq yes .
+.It Cm UseQoS
+Specifies how
+.Xr sshd 8
+applies IP TOS (type of service) marking to traffic.  It takes two values,
+one for non-interactive traffic (\c
+.Xr scp 1
+or
+.Xr ssh 1
+being run with a command), and another for interactive traffic.
+Values may be
+.Dq cs0 ,
+.Dq cs1 ,
+\&...
+.Dq cs7 ,
+.Dq af11 ,
+.Dq af12 ,
+\&...
+.Dq af43 ,
+.Dq ef ,
+.Dq lowdelay ,
+.Dq throughput ,
+etc.  The default is
+.Dq cs0
+for both.  In an RFC-4594 environment,
+.Dq cs2
+and
+.Dq af41
+would be used, respectively.  Legacy behavior would
+.Dq throughput
+and
+.Dq lowdelay ,
+respectively.
 .It Cm X11DisplayOffset
 Specifies the first display number available for
 .Xr sshd 8 Ns 's

Reply via email to