root/net/ieee802154/header_ops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ieee802154_hdr_push_addr
  2. ieee802154_hdr_push_sechdr
  3. ieee802154_hdr_push
  4. ieee802154_hdr_get_addr
  5. ieee802154_hdr_addr_len
  6. ieee802154_hdr_get_sechdr
  7. ieee802154_hdr_sechdr_len
  8. ieee802154_hdr_minlen
  9. ieee802154_hdr_get_addrs
  10. ieee802154_hdr_pull
  11. ieee802154_hdr_peek_addrs
  12. ieee802154_hdr_peek
  13. ieee802154_max_payload

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2014 Fraunhofer ITWM
   4  *
   5  * Written by:
   6  * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
   7  */
   8 
   9 #include <linux/ieee802154.h>
  10 
  11 #include <net/mac802154.h>
  12 #include <net/ieee802154_netdev.h>
  13 
  14 static int
  15 ieee802154_hdr_push_addr(u8 *buf, const struct ieee802154_addr *addr,
  16                          bool omit_pan)
  17 {
  18         int pos = 0;
  19 
  20         if (addr->mode == IEEE802154_ADDR_NONE)
  21                 return 0;
  22 
  23         if (!omit_pan) {
  24                 memcpy(buf + pos, &addr->pan_id, 2);
  25                 pos += 2;
  26         }
  27 
  28         switch (addr->mode) {
  29         case IEEE802154_ADDR_SHORT:
  30                 memcpy(buf + pos, &addr->short_addr, 2);
  31                 pos += 2;
  32                 break;
  33 
  34         case IEEE802154_ADDR_LONG:
  35                 memcpy(buf + pos, &addr->extended_addr, IEEE802154_ADDR_LEN);
  36                 pos += IEEE802154_ADDR_LEN;
  37                 break;
  38 
  39         default:
  40                 return -EINVAL;
  41         }
  42 
  43         return pos;
  44 }
  45 
  46 static int
  47 ieee802154_hdr_push_sechdr(u8 *buf, const struct ieee802154_sechdr *hdr)
  48 {
  49         int pos = 5;
  50 
  51         memcpy(buf, hdr, 1);
  52         memcpy(buf + 1, &hdr->frame_counter, 4);
  53 
  54         switch (hdr->key_id_mode) {
  55         case IEEE802154_SCF_KEY_IMPLICIT:
  56                 return pos;
  57 
  58         case IEEE802154_SCF_KEY_INDEX:
  59                 break;
  60 
  61         case IEEE802154_SCF_KEY_SHORT_INDEX:
  62                 memcpy(buf + pos, &hdr->short_src, 4);
  63                 pos += 4;
  64                 break;
  65 
  66         case IEEE802154_SCF_KEY_HW_INDEX:
  67                 memcpy(buf + pos, &hdr->extended_src, IEEE802154_ADDR_LEN);
  68                 pos += IEEE802154_ADDR_LEN;
  69                 break;
  70         }
  71 
  72         buf[pos++] = hdr->key_id;
  73 
  74         return pos;
  75 }
  76 
  77 int
  78 ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr)
  79 {
  80         u8 buf[IEEE802154_MAX_HEADER_LEN];
  81         int pos = 2;
  82         int rc;
  83         struct ieee802154_hdr_fc *fc = &hdr->fc;
  84 
  85         buf[pos++] = hdr->seq;
  86 
  87         fc->dest_addr_mode = hdr->dest.mode;
  88 
  89         rc = ieee802154_hdr_push_addr(buf + pos, &hdr->dest, false);
  90         if (rc < 0)
  91                 return -EINVAL;
  92         pos += rc;
  93 
  94         fc->source_addr_mode = hdr->source.mode;
  95 
  96         if (hdr->source.pan_id == hdr->dest.pan_id &&
  97             hdr->dest.mode != IEEE802154_ADDR_NONE)
  98                 fc->intra_pan = true;
  99 
 100         rc = ieee802154_hdr_push_addr(buf + pos, &hdr->source, fc->intra_pan);
 101         if (rc < 0)
 102                 return -EINVAL;
 103         pos += rc;
 104 
 105         if (fc->security_enabled) {
 106                 fc->version = 1;
 107 
 108                 rc = ieee802154_hdr_push_sechdr(buf + pos, &hdr->sec);
 109                 if (rc < 0)
 110                         return -EINVAL;
 111 
 112                 pos += rc;
 113         }
 114 
 115         memcpy(buf, fc, 2);
 116 
 117         memcpy(skb_push(skb, pos), buf, pos);
 118 
 119         return pos;
 120 }
 121 EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
 122 
 123 static int
 124 ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan,
 125                         struct ieee802154_addr *addr)
 126 {
 127         int pos = 0;
 128 
 129         addr->mode = mode;
 130 
 131         if (mode == IEEE802154_ADDR_NONE)
 132                 return 0;
 133 
 134         if (!omit_pan) {
 135                 memcpy(&addr->pan_id, buf + pos, 2);
 136                 pos += 2;
 137         }
 138 
 139         if (mode == IEEE802154_ADDR_SHORT) {
 140                 memcpy(&addr->short_addr, buf + pos, 2);
 141                 return pos + 2;
 142         } else {
 143                 memcpy(&addr->extended_addr, buf + pos, IEEE802154_ADDR_LEN);
 144                 return pos + IEEE802154_ADDR_LEN;
 145         }
 146 }
 147 
 148 static int ieee802154_hdr_addr_len(int mode, bool omit_pan)
 149 {
 150         int pan_len = omit_pan ? 0 : 2;
 151 
 152         switch (mode) {
 153         case IEEE802154_ADDR_NONE: return 0;
 154         case IEEE802154_ADDR_SHORT: return 2 + pan_len;
 155         case IEEE802154_ADDR_LONG: return IEEE802154_ADDR_LEN + pan_len;
 156         default: return -EINVAL;
 157         }
 158 }
 159 
 160 static int
 161 ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
 162 {
 163         int pos = 5;
 164 
 165         memcpy(hdr, buf, 1);
 166         memcpy(&hdr->frame_counter, buf + 1, 4);
 167 
 168         switch (hdr->key_id_mode) {
 169         case IEEE802154_SCF_KEY_IMPLICIT:
 170                 return pos;
 171 
 172         case IEEE802154_SCF_KEY_INDEX:
 173                 break;
 174 
 175         case IEEE802154_SCF_KEY_SHORT_INDEX:
 176                 memcpy(&hdr->short_src, buf + pos, 4);
 177                 pos += 4;
 178                 break;
 179 
 180         case IEEE802154_SCF_KEY_HW_INDEX:
 181                 memcpy(&hdr->extended_src, buf + pos, IEEE802154_ADDR_LEN);
 182                 pos += IEEE802154_ADDR_LEN;
 183                 break;
 184         }
 185 
 186         hdr->key_id = buf[pos++];
 187 
 188         return pos;
 189 }
 190 
 191 static int ieee802154_sechdr_lengths[4] = {
 192         [IEEE802154_SCF_KEY_IMPLICIT] = 5,
 193         [IEEE802154_SCF_KEY_INDEX] = 6,
 194         [IEEE802154_SCF_KEY_SHORT_INDEX] = 10,
 195         [IEEE802154_SCF_KEY_HW_INDEX] = 14,
 196 };
 197 
 198 static int ieee802154_hdr_sechdr_len(u8 sc)
 199 {
 200         return ieee802154_sechdr_lengths[IEEE802154_SCF_KEY_ID_MODE(sc)];
 201 }
 202 
 203 static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr)
 204 {
 205         int dlen, slen;
 206 
 207         dlen = ieee802154_hdr_addr_len(hdr->fc.dest_addr_mode, false);
 208         slen = ieee802154_hdr_addr_len(hdr->fc.source_addr_mode,
 209                                        hdr->fc.intra_pan);
 210 
 211         if (slen < 0 || dlen < 0)
 212                 return -EINVAL;
 213 
 214         return 3 + dlen + slen + hdr->fc.security_enabled;
 215 }
 216 
 217 static int
 218 ieee802154_hdr_get_addrs(const u8 *buf, struct ieee802154_hdr *hdr)
 219 {
 220         int pos = 0;
 221 
 222         pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.dest_addr_mode,
 223                                        false, &hdr->dest);
 224         pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.source_addr_mode,
 225                                        hdr->fc.intra_pan, &hdr->source);
 226 
 227         if (hdr->fc.intra_pan)
 228                 hdr->source.pan_id = hdr->dest.pan_id;
 229 
 230         return pos;
 231 }
 232 
 233 int
 234 ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
 235 {
 236         int pos = 3, rc;
 237 
 238         if (!pskb_may_pull(skb, 3))
 239                 return -EINVAL;
 240 
 241         memcpy(hdr, skb->data, 3);
 242 
 243         rc = ieee802154_hdr_minlen(hdr);
 244         if (rc < 0 || !pskb_may_pull(skb, rc))
 245                 return -EINVAL;
 246 
 247         pos += ieee802154_hdr_get_addrs(skb->data + pos, hdr);
 248 
 249         if (hdr->fc.security_enabled) {
 250                 int want = pos + ieee802154_hdr_sechdr_len(skb->data[pos]);
 251 
 252                 if (!pskb_may_pull(skb, want))
 253                         return -EINVAL;
 254 
 255                 pos += ieee802154_hdr_get_sechdr(skb->data + pos, &hdr->sec);
 256         }
 257 
 258         skb_pull(skb, pos);
 259         return pos;
 260 }
 261 EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
 262 
 263 int
 264 ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
 265 {
 266         const u8 *buf = skb_mac_header(skb);
 267         int pos = 3, rc;
 268 
 269         if (buf + 3 > skb_tail_pointer(skb))
 270                 return -EINVAL;
 271 
 272         memcpy(hdr, buf, 3);
 273 
 274         rc = ieee802154_hdr_minlen(hdr);
 275         if (rc < 0 || buf + rc > skb_tail_pointer(skb))
 276                 return -EINVAL;
 277 
 278         pos += ieee802154_hdr_get_addrs(buf + pos, hdr);
 279         return pos;
 280 }
 281 EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs);
 282 
 283 int
 284 ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
 285 {
 286         const u8 *buf = skb_mac_header(skb);
 287         int pos;
 288 
 289         pos = ieee802154_hdr_peek_addrs(skb, hdr);
 290         if (pos < 0)
 291                 return -EINVAL;
 292 
 293         if (hdr->fc.security_enabled) {
 294                 u8 key_id_mode = IEEE802154_SCF_KEY_ID_MODE(*(buf + pos));
 295                 int want = pos + ieee802154_sechdr_lengths[key_id_mode];
 296 
 297                 if (buf + want > skb_tail_pointer(skb))
 298                         return -EINVAL;
 299 
 300                 pos += ieee802154_hdr_get_sechdr(buf + pos, &hdr->sec);
 301         }
 302 
 303         return pos;
 304 }
 305 EXPORT_SYMBOL_GPL(ieee802154_hdr_peek);
 306 
 307 int ieee802154_max_payload(const struct ieee802154_hdr *hdr)
 308 {
 309         int hlen = ieee802154_hdr_minlen(hdr);
 310 
 311         if (hdr->fc.security_enabled) {
 312                 hlen += ieee802154_sechdr_lengths[hdr->sec.key_id_mode] - 1;
 313                 hlen += ieee802154_sechdr_authtag_len(&hdr->sec);
 314         }
 315 
 316         return IEEE802154_MTU - hlen - IEEE802154_MFR_SIZE;
 317 }
 318 EXPORT_SYMBOL_GPL(ieee802154_max_payload);

/* [<][>][^][v][top][bottom][index][help] */