]> Cypherpunks repositories - gostls13.git/commitdiff
net: add ParseMAC function
authorPaul Borman <borman@google.com>
Wed, 24 Aug 2011 02:38:43 +0000 (22:38 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 24 Aug 2011 02:38:43 +0000 (22:38 -0400)
ParseMAC parses a string representing MAC-48, EUI-48, or EUI-64 into
a HardwareAddr.

R=rsc, fshahriar
CC=golang-dev
https://golang.org/cl/4922048

src/pkg/net/interface.go
src/pkg/net/interface_test.go

index 8a14cb2320299c04eef2f6c6b21a016a017219ac..c69e6251b408945953051d73cdfaca2fcaf78725 100644 (file)
@@ -26,6 +26,75 @@ func (a HardwareAddr) String() string {
        return buf.String()
 }
 
+// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
+// following formats:
+//   01:23:45:67:89:ab
+//   01:23:45:67:89:ab:cd:ef
+//   01-23-45-67-89-ab
+//   01-23-45-67-89-ab-cd-ef
+//   0123.4567.89ab
+//   0123.4567.89ab.cdef
+func ParseMAC(s string) (hw HardwareAddr, err os.Error) {
+       if len(s) < 14 {
+               goto error
+       }
+
+       if s[2] == ':' || s[2] == '-' {
+               if (len(s)+1)%3 != 0 {
+                       goto error
+               }
+               n := (len(s) + 1) / 3
+               if n != 6 && n != 8 {
+                       goto error
+               }
+               hw = make(HardwareAddr, n)
+               for x, i := 0, 0; i < n; i++ {
+                       var ok bool
+                       if hw[i], ok = xtoi2(s[x:], s[2]); !ok {
+                               goto error
+                       }
+                       x += 3
+               }
+       } else if s[4] == '.' {
+               if (len(s)+1)%5 != 0 {
+                       goto error
+               }
+               n := 2 * (len(s) + 1) / 5
+               if n != 6 && n != 8 {
+                       goto error
+               }
+               hw = make(HardwareAddr, n)
+               for x, i := 0, 0; i < n; i += 2 {
+                       var ok bool
+                       if hw[i], ok = xtoi2(s[x:x+2], 0); !ok {
+                               goto error
+                       }
+                       if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok {
+                               goto error
+                       }
+                       x += 5
+               }
+       } else {
+               goto error
+       }
+       return hw, nil
+
+error:
+       return nil, os.NewError("invalid MAC address: " + s)
+}
+
+// xtoi2 converts the next two hex digits of s into a byte.
+// If s is longer than 2 bytes then the third byte must be e.
+// If the first two bytes of s are not hex digits or the third byte
+// does not match e, false is returned.
+func xtoi2(s string, e byte) (byte, bool) {
+       if len(s) > 2 && s[2] != e {
+               return 0, false
+       }
+       n, ei, ok := xtoi(s[:2], 0)
+       return byte(n), ok && ei == 2
+}
+
 // Interface represents a mapping between network interface name
 // and index.  It also represents network interface facility
 // information.
index 0e4089abf8affeada09a49d0c35dc8b3e5100587..c918f247f96599beac05f83b37efabbd8ebb2a65 100644 (file)
@@ -6,6 +6,9 @@ package net
 
 import (
        "bytes"
+       "os"
+       "reflect"
+       "strings"
        "testing"
 )
 
@@ -71,3 +74,46 @@ func TestInterfaceAddrs(t *testing.T) {
                t.Logf("interface address %q\n", ifa.String())
        }
 }
+
+var mactests = []struct {
+       in  string
+       out HardwareAddr
+       err string
+}{
+       {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+       {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+       {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+       {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""},
+       {"01.02.03.04.05.06", nil, "invalid MAC address"},
+       {"01:02:03:04:05:06:", nil, "invalid MAC address"},
+       {"x1:02:03:04:05:06", nil, "invalid MAC address"},
+       {"01002:03:04:05:06", nil, "invalid MAC address"},
+       {"01:02003:04:05:06", nil, "invalid MAC address"},
+       {"01:02:03004:05:06", nil, "invalid MAC address"},
+       {"01:02:03:04005:06", nil, "invalid MAC address"},
+       {"01:02:03:04:05006", nil, "invalid MAC address"},
+       {"01-02:03:04:05:06", nil, "invalid MAC address"},
+       {"01:02-03-04-05-06", nil, "invalid MAC address"},
+       {"0123:4567:89AF", nil, "invalid MAC address"},
+       {"0123-4567-89AF", nil, "invalid MAC address"},
+       {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+       {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+       {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+}
+
+func match(err os.Error, s string) bool {
+       if s == "" {
+               return err == nil
+       }
+       return err != nil && strings.Contains(err.String(), s)
+}
+
+func TestParseMAC(t *testing.T) {
+       for _, tt := range mactests {
+               out, err := ParseMAC(tt.in)
+               if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
+                       t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
+                               tt.err)
+               }
+       }
+}