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                 } else {
  79                         value = up;
  80                 }
  81 
  82                 /* Single byte unknow option */
  83                 if (option_type >= 3 && option_type <=31) {
  84                         if (mandatory) {
  85                                 error = DCCP_RESET_MANDATORY_ERROR;
  86                         } else {
  87                                 error = DCCP_RESET_OPTION_ERROR;
  88                         }
  89 
  90                         dccp->dccp_reset_code = error;
  91                         /*
  92                          * this should be correct:
  93                          * dccp->dccp_reset_data[0] = option_type;
  94                          * dccp->dccp_reset_data[1] = value[0];
  95                          *
  96                          * error in the test suit?
  97                          */
  98                         dccp->dccp_reset_data[0] = value[0];
  99                         dccp->dccp_reset_data[1] = 0;
 100                         dccp->dccp_reset_data[2] = 0;
 101 
 102                         return (-1);
 103                 }
 104 
 105                 if (option_type >= 45 && option_type <=127)
 106                         break;
 107 
 108 
 109                 switch (option_type) {
 110                 case DCCP_OPTION_PADDING:
 111                         cmn_err(CE_NOTE, "PADDING");
 112                         break;
 113                 case DCCP_OPTION_MANDATORY:
 114                         cmn_err(CE_NOTE, "MANDATORY");
 115                         if (mandatory)
 116                                 goto option_error;
 117 
 118                         if (dccp_type != DCCP_PKT_DATA)
 119                                 mandatory = B_TRUE;
 120                         break;
 121                 case DCCP_OPTION_SLOW_RECEIVER:
 122                         cmn_err(CE_NOTE, "SLOW RECEIVER");
 123                         break;
 124                 case DCCP_OPTION_CHANGE_L:
 125                 case DCCP_OPTION_CONFIRM_L:
 126                 case DCCP_OPTION_CHANGE_R:
 127                 case DCCP_OPTION_CONFIRM_R:
 128                         if (dccp_type == DCCP_PACKET_DATA)
 129                                 break;
 130 
 131                         if (option_length == 0)
 132                                 goto option_error;
 133 
 134                         error = dccp_parse_feature(dccp, option_type, option_length,
 135                             value, mandatory);
 136                         if (error != 0)
 137                                 goto feature_error;
 138 
 139                         break;
 140                 case DCCP_OPTION_INIT_COOKIE:
 141                         cmn_err(CE_NOTE, "INIT COOKIE");
 142                         break;
 143                 case DCCP_OPTION_NDP_COUNT:
 144                         cmn_err(CE_NOTE, "NDP COUNT");
 145                         if (option_length > 6)
 146                                 goto option_error;
 147                         break;
 148                 case DCCP_OPTION_ACK_VECTOR_1:
 149                         cmn_err(CE_NOTE, "ACK VECTOR 1");
 150                         break;
 151                 case DCCP_OPTION_ACK_VECTOR_2:
 152                         cmn_err(CE_NOTE, "ACK VECTOR 2");
 153                         break;
 154                 case DCCP_OPTION_DATA_DROPPED:
 155                         cmn_err(CE_NOTE, "DATA DROPPED");
 156                         break;
 157                 case DCCP_OPTION_TIMESTAMP:
 158                         cmn_err(CE_NOTE, "TIMESTAMP");
 159                         if (option_length != 4)
 160                                 goto option_error;
 161 
 162                         option_value = BE32_TO_U32(value);
 163                         if (option_value == 0) {
 164                                 cmn_err(CE_NOTE, "Zero timestamp");
 165                                 break;
 166                         }
 167 
 168                         dccp->dccp_timestamp_echo = ntohs(option_value);
 169                         dccp->dccp_timestamp = TICK_TO_MSEC(LBOLT_FASTPATH);
 170                         break;
 171                 case DCCP_OPTION_TIMESTAMP_ECHO:
 172                         cmn_err(CE_NOTE, "TIMESTAMP ECHO");
 173                         if (option_length != 4 && option_length != 6 &&
 174                             option_length != 8) {
 175                                 goto option_error;
 176                         }
 177 
 178                         option_value = BE32_TO_U32(value);
 179 
 180                         option_length -= 4;
 181                         break;
 182                 case DCCP_OPTION_ELAPSED_TIME:
 183                         cmn_err(CE_NOTE, "ELAPSES TIME");
 184                         switch (option_length) {
 185                         case 2:
 186                                 break;
 187                         case 4:
 188                                 break;
 189                         default:
 190                                 goto option_error;
 191                         }
 192                         break;
 193                 case DCCP_OPTION_DATA_CHECKSUM:
 194                         cmn_err(CE_NOTE, "DATA CHECKSUM");
 195                         break;
 196 
 197                 default:
 198                         cmn_err(CE_NOTE, "unknow option");
 199                         break;
 200                 }
 201 
 202                 if (option_type != DCCP_OPTION_MANDATORY) {
 203                         mandatory = B_FALSE;
 204                 }
 205         }
 206 
 207         if (mandatory)
 208                 goto option_error;
 209 
 210 length_error:
 211         return (0);
 212 
 213 option_error:
 214         if (mandatory) {
 215                 error = DCCP_RESET_MANDATORY_ERROR;
 216         } else {
 217                 error = DCCP_RESET_OPTION_ERROR;
 218         }
 219 
 220         cmn_err(CE_NOTE, "setting error code");
 221 
 222 feature_error:
 223         dccp->dccp_reset_code = error;
 224         dccp->dccp_reset_data[0] = option_type;
 225         dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0;
 226         dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0;
 227 
 228         return (-1);
 229 }
 230 
 231 int
 232 dccp_process_options(dccp_t *dccp, dccpha_t *dccpha)
 233 {
 234         int     error;
 235 
 236         cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features");
 237 
 238         error = dccp_parse_options(dccp, dccpha);
 239 
 240         return (error);
 241 }
 242 
 243 int
 244 dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len)
 245 {
 246         dccp_feature_t  *feature = NULL;
 247         uint8_t         buf[1024];      /* XXX */
 248         uint8_t         option_type;
 249         uint_t          len = 0;
 250         uint_t          total_len = 0;
 251         void            *options = NULL;
 252         int             rest;
 253 
 254         cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options");
 255 
 256         for (feature = list_head(&dccp->dccp_features); feature;
 257             feature = list_next(&dccp->dccp_features, feature)) {
 258                 if (feature->df_option == DCCP_OPTION_CHANGE_L) {
 259                         option_type = DCCP_OPTION_CONFIRM_R;
 260                 } else {
 261                         option_type = DCCP_OPTION_CONFIRM_L;
 262                 }
 263 /*
 264                 if (feature->df_mandatory == B_TRUE) {
 265                         buf[len] = DCCP_OPTION_MANDATORY;
 266                         len++;
 267                 }
 268 */
 269                 if (feature->df_type == DCCP_FEATURE_CCID) {
 270                         cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID");
 271 
 272                         buf[len] = option_type;
 273                         len++;
 274                         buf[len] = 4;
 275                         len++;
 276                         buf[len] = DCCP_FEATURE_CCID;
 277                         len++;
 278                         buf[len] = 2;
 279                         len++;
 280                 }
 281 
 282                 if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) {
 283                         buf[len] = option_type;
 284                         len++;
 285                         buf[len] = 4;
 286                         len++;
 287                         buf[len] = feature->df_type;
 288                         len++;
 289                         buf[len] = 0;
 290                         len++;
 291                 }
 292 
 293                 if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) {
 294                         buf[len] = option_type;
 295                         len++;
 296                         buf[len] = 4;
 297                         len++;
 298                         buf[len] = feature->df_type;
 299                         len++;
 300                         buf[len] = 1;
 301                         len++;
 302                 }
 303         }
 304 
 305         if (dccp->dccp_timestamp_echo != 0) {
 306                 uint32_t        elapsed;
 307                 int             elapsed_length;
 308                 clock_t         now;
 309 
 310                 buf[len] = DCCP_OPTION_TIMESTAMP_ECHO;
 311                 len++;
 312                 buf[len] = 10;
 313                 len++;
 314 
 315                 now = TICK_TO_MSEC(LBOLT_FASTPATH);
 316                 elapsed =  now - dccp->dccp_timestamp;
 317 
 318 
 319                 dccp->dccp_timestamp_echo = 0;
 320         }
 321 
 322         if (len != 0) {
 323                 total_len = ((len + (4 - 1)) / 4) * 4;
 324                 options = kmem_zalloc(total_len, KM_SLEEP);
 325                 if (options == NULL) {
 326                         cmn_err(CE_NOTE, "kmem_zalloc failed");
 327                         return (ENOMEM);
 328                 }
 329                 memcpy(options, buf, len);
 330         }
 331 
 332         *opt = options;
 333         *opt_len = len;
 334 
 335         return (0);
 336 }