diff --git a/CMakeLists.txt b/CMakeLists.txt index bba8b88b146..026990d264e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ set(CORE_SRCS cores/esp32/IPAddress.cpp cores/esp32/libb64/cdecode.c cores/esp32/libb64/cencode.c + cores/esp32/MacAddress.cpp cores/esp32/main.cpp cores/esp32/MD5Builder.cpp cores/esp32/Print.cpp diff --git a/cores/esp32/MacAddress.cpp b/cores/esp32/MacAddress.cpp new file mode 100644 index 00000000000..991fdd5e178 --- /dev/null +++ b/cores/esp32/MacAddress.cpp @@ -0,0 +1,229 @@ +#include +#include +#include + +//Default constructor, blank mac address. +MacAddress::MacAddress() : MacAddress(MAC6){} + +MacAddress::MacAddress(MACType mac_type){ + _type = mac_type; + memset(_mac.bytes, 0, sizeof(_mac.bytes)); +} +MacAddress::MacAddress(MACType mac_type, uint64_t mac) { + _type = mac_type; + _mac.val = mac; +} + +MacAddress::MacAddress(MACType mac_type, const uint8_t *macbytearray) { + _type = mac_type; + memset(_mac.bytes, 0, sizeof(_mac.bytes)); + if(_type == MAC6) { + memcpy(_mac.bytes, macbytearray, 6); + } else { + memcpy(_mac.bytes, macbytearray, 8); + } +} + +MacAddress::MacAddress(const char *macstr){ + fromString(macstr); +} + +MacAddress::MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6) { + _type = MAC6; + memset(_mac.bytes, 0, sizeof(_mac.bytes)); + _mac.bytes[0] = b1; + _mac.bytes[1] = b2; + _mac.bytes[2] = b3; + _mac.bytes[3] = b4; + _mac.bytes[4] = b5; + _mac.bytes[5] = b6; +} + +MacAddress::MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) { + _type = MAC8; + _mac.bytes[0] = b1; + _mac.bytes[1] = b2; + _mac.bytes[2] = b3; + _mac.bytes[3] = b4; + _mac.bytes[4] = b5; + _mac.bytes[5] = b6; + _mac.bytes[6] = b7; + _mac.bytes[7] = b8; +} + +//Parse user entered string into MAC address +bool MacAddress::fromString(const char *buf) { + if(strlen(buf) == 17) { + return fromString6(buf); + } else if(strlen(buf) == 23) { + return fromString8(buf); + } + return false; +} + +//Parse user entered string into MAC address +bool MacAddress::fromString6(const char *buf) { + char cs[18]; + char *token; + char *next; //Unused but required + int i; + + strncpy(cs, buf, sizeof(cs)); //strtok modifies the buffer: copy to working buffer. + + for(i = 0; i < 6; i++) { + token = strtok((i==0) ? cs : NULL, ":"); //Find first or next token + if(!token) { //No more tokens found + return false; + } + _mac.bytes[i] = strtol(token, &next, 16); + } + _type = MAC6; + return true; +} + +bool MacAddress::fromString8(const char *buf) { + char cs[24]; + char *token; + char *next; //Unused but required + int i; + + strncpy(cs, buf, sizeof(cs)); //strtok modifies the buffer: copy to working buffer. + + for(i = 0; i < 8; i++) { + token = strtok((i==0) ? cs : NULL, ":"); //Find first or next token + if(!token) { //No more tokens found + return false; + } + _mac.bytes[i] = strtol(token, &next, 16); + } + _type = MAC8; + return true; +} + +//Copy MAC into byte array +void MacAddress::toBytes(uint8_t *buf) { + if(_type == MAC6) { + memcpy(buf, _mac.bytes, 6); + } else { + memcpy(buf, _mac.bytes, sizeof(_mac.bytes)); + } +} + +//Print MAC address into a C string. +//MAC: Buffer must be at least 18 chars +int MacAddress::toString(char *buf) { + if(_type == MAC6) { + return sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], + _mac.bytes[3], _mac.bytes[4], _mac.bytes[5]); + } else { + return sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", + _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], + _mac.bytes[3], _mac.bytes[4], _mac.bytes[5], + _mac.bytes[6], _mac.bytes[7]); + } +} + +String MacAddress::toString() const { + uint8_t bytes = (_type == MAC6) ? 18 : 24; + char buf[bytes]; + if(_type == MAC6) { + snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", + _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], + _mac.bytes[3], _mac.bytes[4], _mac.bytes[5]); + } else { + snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", + _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], + _mac.bytes[3], _mac.bytes[4], _mac.bytes[5], + _mac.bytes[6], _mac.bytes[7]); + } + return String(buf); +} + +uint64_t MacAddress::Value() { + return _mac.val; +} + +//Allow getting individual octets of the address. e.g. uint8_t b0 = ma[0]; +uint8_t MacAddress::operator[](int index) const { + index = EnforceIndexBounds(index); + return _mac.bytes[index]; +} + +//Allow setting individual octets of the address. e.g. ma[2] = 255; +uint8_t& MacAddress::operator[](int index) { + index = EnforceIndexBounds(index); + return _mac.bytes[index]; +} + +//Overloaded copy operator: init MacAddress object from byte array +MacAddress& MacAddress::operator=(const uint8_t *macbytearray) { + // 6-bytes MacAddress only + _type = MAC6; + memset(_mac.bytes, 0, sizeof(_mac.bytes)); + memcpy(_mac.bytes, macbytearray, 6); + return *this; +} + +//Overloaded copy operator: init MacAddress object from uint64_t +MacAddress& MacAddress::operator=(uint64_t macval) { + // 6-bytes MacAddress only + _type = MAC6; + _mac.val = macval; + return *this; +} + +//Compare class to byte array +bool MacAddress::operator==(const uint8_t *macbytearray) const { + return !memcmp(_mac.bytes, macbytearray, 6); +} + +//Allow comparing value of two classes +bool MacAddress::operator==(const MacAddress& mac2) const { + return _mac.val == mac2._mac.val; +} + +//Type converter object to uint64_t [same as .Value()] +MacAddress::operator uint64_t() const { + return _mac.val; +} + +//Type converter object to read only pointer to mac bytes. e.g. const uint8_t *ip_8 = ma; +MacAddress::operator const uint8_t*() const { + return _mac.bytes; +} + +//Type converter object to read only pointer to mac value. e.g. const uint32_t *ip_64 = ma; +MacAddress::operator const uint64_t*() const { + return &_mac.val; +} + +size_t MacAddress::printTo(Print& p) const +{ + uint8_t bytes = (_type == MAC6) ? 6 : 8; + size_t n = 0; + for(int i = 0; i < bytes; i++) { + if(i){ + n += p.print(':'); + } + n += p.printf("%02X", _mac.bytes[i]); + } + return n; +} + +//Bounds checking +int MacAddress::EnforceIndexBounds(int i) const { + if(i < 0) { + return 0; + } + if(_type == MAC6) { + if(i >= 6) { + return 5; + } + } else { + if(i >= 8) { + return 7; + } + } + return i; +} diff --git a/cores/esp32/MacAddress.h b/cores/esp32/MacAddress.h new file mode 100644 index 00000000000..83ce362a495 --- /dev/null +++ b/cores/esp32/MacAddress.h @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------------- +// MacAddress.h - class to make it easier to handle BSSID and MAC addresses. +// +// Copyright 2022 David McCurley +// Modified by Espressif Systems 2024 +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//----------------------------------------------------------------------------- + +#ifndef MacAddress_h +#define MacAddress_h + +#include +#include +#include + +enum MACType { + MAC6, + MAC8 +}; + +// A class to make it easier to handle and pass around MAC addresses, supporting both 6-byte and 8-byte MAC addresses. +class MacAddress : public Printable { +private: + union { + uint8_t bytes[8]; + uint64_t val; + } _mac; + MACType _type; + +public: + //Default MAC6 + MacAddress(); + + MacAddress(MACType mac_type); + MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6); + MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8); + + MacAddress(MACType mac_type, uint64_t mac); + MacAddress(MACType mac_type, const uint8_t *macbytearray); + + //Default MAC6 + MacAddress(uint64_t mac) : MacAddress(MAC6, mac) {} + MacAddress(const uint8_t *macbytearray) : MacAddress(MAC6, macbytearray) {} + + MacAddress(const char *macstr); + + virtual ~MacAddress() {} + + bool fromString(const char *buf); + bool fromString(const String &macstr) { return fromString(macstr.c_str()); } + + void toBytes(uint8_t *buf); + int toString(char *buf); + String toString() const; + uint64_t Value(); + + uint8_t operator[](int index) const; + uint8_t& operator[](int index); + + //MAC6 only + MacAddress& operator=(const uint8_t *macbytearray); + MacAddress& operator=(uint64_t macval); + + bool operator==(const uint8_t *macbytearray) const; + bool operator==(const MacAddress& mac2) const; + operator uint64_t() const; + operator const uint8_t*() const; + operator const uint64_t*() const; + + virtual size_t printTo(Print& p) const; + + // future use in Arduino Networking + /* + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; + */ + +protected: + bool fromString6(const char *buf); + bool fromString8(const char *buf); + +private: + int EnforceIndexBounds(int i) const; +}; + +#endif