1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2012 David Hoeppner. All rights reserved.
  14  */
  15 
  16 #include <sys/types.h> 
  17 #include <sys/stream.h> 
  18 #include <sys/debug.h> 
  19 #include <sys/cmn_err.h>
  20 
  21 #include <inet/dccp_impl.h>
  22 #include <inet/dccp_stack.h>
  23 
  24 /*
  25  * This file contains functions to parse and process DCCP options.
  26  */
  27 
  28 
  29 /*
  30  * Parse the options in a DCCP header.
  31  */
  32 int
  33 dccp_parse_options(dccp_t *dccp, dccpha_t *dccpha)
  34 {
  35         uchar_t         *end;
  36         uchar_t         *up;
  37         uint8_t         dccp_type;
  38         uint32_t        option_value;
  39         uint8_t         option_type;
  40         uint8_t         option_length;
  41         int             len;
  42         int             i;
  43         uchar_t         *value;
  44         boolean_t       mandatory = B_FALSE;
  45         int             error;
  46 
  47         cmn_err(CE_NOTE, "dccp_features.c: dccp_parse_options");
  48 
  49         dccp_type = dccpha->dha_type;
  50 
  51         up = (uchar_t *)dccpha;
  52         end = up + DCCP_HDR_LENGTH(dccpha);
  53         up += 20;
  54 
  55         while (up != end) {
  56                 option_length = 0;
  57                 option_type = *up++;
  58 
  59                 if (option_type > 31) {
  60                         if (up == end) {
  61                                 goto length_error;
  62                         }
  63 
  64                         option_length = *up++;
  65                         if (option_length < 2) {
  66                                 goto length_error;
  67                         }
  68 
  69                         option_length -= 2;
  70                         value = up;
  71 
  72                         up += option_length;
  73 
  74                         /* Ignore options with greater length then header */
  75                         if (up > end) {
  76                                 goto length_error;
  77                         }
  78                 }
  79 
  80                 switch (option_type) {
  81                 case DCCP_OPTION_PADDING:
  82                         cmn_err(CE_NOTE, "PADDING");
  83                         break;
  84                 case DCCP_OPTION_MANDATORY:
  85                         cmn_err(CE_NOTE, "MANDATORY");
  86                         if (mandatory)
  87                                 goto option_error;
  88 
  89                         if (dccp_type != DCCP_PKT_DATA)
  90                                 mandatory = B_TRUE;
  91                         break;
  92                 case DCCP_OPTION_SLOW_RECEIVER:
  93                         cmn_err(CE_NOTE, "SLOW RECEIVER");
  94                         break;
  95                 case DCCP_OPTION_CHANGE_L:
  96                 case DCCP_OPTION_CONFIRM_L:
  97                 case DCCP_OPTION_CHANGE_R:
  98                 case DCCP_OPTION_CONFIRM_R:
  99                         if (dccp_type == DCCP_PKT_DATA)
 100                                 break;
 101 
 102                         if (option_length == 0)
 103                                 goto option_error;
 104 
 105                         dccp_parse_feature(dccp, option_type, option_length,
 106                             value, mandatory);
 107                         break;
 108                 case DCCP_OPTION_INIT_COOKIE:
 109                         cmn_err(CE_NOTE, "INIT COOKIE");
 110                         break;
 111                 case DCCP_OPTION_NDP_COUNT:
 112                         cmn_err(CE_NOTE, "NDP COUNT");
 113                         if (option_length > 6)
 114                                 goto option_error;
 115                         break;
 116                 case DCCP_OPTION_ACK_VECTOR_1:
 117                         cmn_err(CE_NOTE, "ACK VECTOR 1");
 118                         break;
 119                 case DCCP_OPTION_ACK_VECTOR_2:
 120                         cmn_err(CE_NOTE, "ACK VECTOR 2");
 121                         break;
 122                 case DCCP_OPTION_DATA_DROPPED:
 123                         cmn_err(CE_NOTE, "DATA DROPPED");
 124                         break;
 125                 case DCCP_OPTION_TIMESTAMP:
 126                         cmn_err(CE_NOTE, "TIMESTAMP");
 127                         if (option_length != 4)
 128                                 goto option_error;
 129 
 130                         /* XXX read unaligned big endian */
 131                         option_value = ((uint8_t)value[0] << 24);
 132                         option_value += ((uint8_t)value[1] << 16);
 133                         option_value += ((uint8_t)value[2] << 8);
 134                         option_value += (uint8_t)value[3];
 135                         if (option_value) {
 136                                 cmn_err(CE_NOTE, "Zero timestamp");
 137                                 break;
 138                         }
 139 
 140                         dccp->dccp_timestamp_echo = ntohs(option_value);
 141                         dccp->dccp_timestamp = TICK_TO_MSEC(LBOLT_FASTPATH);
 142                         break;
 143                 case DCCP_OPTION_TIMESTAMP_ECHO:
 144                         cmn_err(CE_NOTE, "TIMESTAMP ECHO");
 145                         if (option_length != 4 &&
 146                             option_length != 6 &&
 147                             option_length != 8) {
 148                                 goto option_error;
 149                         }
 150 
 151                         break;
 152                 case DCCP_OPTION_ELAPSED_TIME:
 153                         cmn_err(CE_NOTE, "ELAPSES TIME");
 154                         switch (option_length) {
 155                         case 2:
 156                                 break;
 157                         case 4:
 158                                 break;
 159                         default:
 160                                 goto option_error;
 161                         }
 162                         break;
 163                 case DCCP_OPTION_DATA_CHECKSUM:
 164                         cmn_err(CE_NOTE, "DATA CHECKSUM");
 165                         break;
 166 
 167                 default:
 168                         cmn_err(CE_NOTE, "DEFAULT");
 169                         break;
 170                 }
 171 
 172                 if (option_type != DCCP_OPTION_MANDATORY) {
 173                         mandatory = B_FALSE;
 174                 }
 175         }
 176 
 177         if (mandatory)
 178                 goto option_error;
 179 
 180 length_error:
 181         return (0);
 182 
 183 option_error:
 184         error = DCCP_RESET_OPTION_ERROR;
 185 
 186         cmn_err(CE_NOTE, "setting error code");
 187 
 188         dccp->dccp_reset_code = error;
 189         dccp->dccp_reset_data[0] = option_type;
 190         dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0;
 191         dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0;
 192 
 193         return (-1);
 194 }
 195 
 196 void
 197 dccp_process_options(dccp_t *dccp, dccpha_t *dccpha)
 198 {
 199         cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features");
 200 
 201         dccp_parse_options(dccp, dccpha);
 202 }
 203 
 204 int
 205 dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len)
 206 {
 207         dccp_feature_t  *feature = NULL;
 208         uint8_t         buf[1024];      /* XXX */
 209         uint8_t         option_type;
 210         uint_t          len = 0;
 211         uint_t          total_len;
 212         void            *options;
 213         int             rest;
 214 
 215         cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options");
 216 
 217         for (feature = list_head(&dccp->dccp_features); feature;
 218             feature = list_next(&dccp->dccp_features, feature)) {
 219                 if (feature->df_option == DCCP_OPTION_CHANGE_L) {
 220                         option_type = DCCP_OPTION_CONFIRM_R;
 221                 } else {
 222                         option_type = DCCP_OPTION_CONFIRM_L;
 223                 }
 224 /*
 225                 if (feature->df_mandatory == B_TRUE) {
 226                         buf[len] = DCCP_OPTION_MANDATORY;
 227                         len++;
 228                 }
 229 */
 230                 if (feature->df_type == DCCP_FEATURE_CCID) {
 231                         cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID");
 232 
 233                         buf[len] = option_type;
 234                         len++;
 235                         buf[len] = 4;
 236                         len++;
 237                         buf[len] = DCCP_FEATURE_CCID;
 238                         len++;
 239                         buf[len] = 2;
 240                         len++;
 241                 }
 242 
 243                 if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) {
 244                         buf[len] = option_type;
 245                         len++;
 246                         buf[len] = 4;
 247                         len++;
 248                         buf[len] = feature->df_type;
 249                         len++;
 250                         buf[len] = 0;
 251                         len++;
 252                 }
 253 
 254                 if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) {
 255                         buf[len] = option_type;
 256                         len++;
 257                         buf[len] = 4;
 258                         len++;
 259                         buf[len] = feature->df_type;
 260                         len++;
 261                         buf[len] = 1;
 262                         len++;
 263                 }
 264         }
 265 
 266         if (dccp->dccp_timestamp_echo != 0) {
 267                 uint32_t        elapsed;
 268                 int             elapsed_length;
 269                 clock_t         now;
 270 
 271                 buf[len] = DCCP_OPTION_TIMESTAMP_ECHO;
 272                 len++;
 273                 buf[len] = 10;
 274                 len++;
 275 
 276                 now = TICK_TO_MSEC(LBOLT_FASTPATH);
 277                 elapsed =  now - dccp->dccp_timestamp;
 278 
 279 
 280                 dccp->dccp_timestamp_echo = 0;
 281         }
 282 
 283         total_len = ((len + (4 - 1)) / 4) * 4;
 284         options = kmem_zalloc(total_len, KM_SLEEP);
 285         if (options == NULL) {
 286                 cmn_err(CE_NOTE, "kmem_zalloc failed");
 287                 return (ENOMEM);
 288         }
 289         memcpy(options, buf, len);
 290 
 291         *opt = options;
 292         *opt_len = len;
 293 
 294         return (0);
 295 }