]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Allow to send LLDP-MED location.
authorVincent Bernat <bernat@luffy.cx>
Sat, 13 Dec 2008 17:14:22 +0000 (18:14 +0100)
committerVincent Bernat <bernat@luffy.cx>
Sat, 13 Dec 2008 17:15:21 +0000 (18:15 +0100)
man/lldpd.8
src/lldp.c
src/lldpctl.c
src/lldpd.c

index db8057fdaf40665a872f9e6174a1ce8259b66217..d2cad2a767db93622a0d40038a42b90745e86953 100644 (file)
@@ -25,6 +25,8 @@
 .Op Fl m Ar management
 .Op Fl p Ar probe time
 .Op Fl M Ar class
+.Op Fl L Ar location
+.Op Fl P Ar policy
 .Sh DESCRIPTION
 .Nm
 is a daemon able to receive and send
@@ -96,13 +98,13 @@ are enabled.
 Enable emission of LLDP-MED frame. The class should be one of the
 following value:
 .Bl -tag -width "0:XX" -compact
-.It Ar 1
+.It Sy 1
 Generic Endpoint (Class I)
-.It Ar 2
+.It Sy 2
 Media Endpoint (Class II)
-.It Ar 3
+.It Sy 3
 Communication Device Endpoints (Class III)
-.It Ar 4
+.It Sy 4
 Network Connectivity Device
 .El
 .It Fl i
@@ -111,6 +113,102 @@ Disable LLDP-MED inventory TLV transmission.
 will still receive (and publish using SNMP if enabled) those LLDP-MED
 TLV but will not send them. Use this option if you don't want to
 transmit sensible information like serial numbers.
+.It Fl L Ar location
+Enable the transmission of LLDP-MED location TLV. This option can be
+repeated several times to enable the transmission of the location in
+several formats. Several formats are accepted:
+.Bl -tag -width "XX"
+.It Em Coordinate based location
+The format of
+.Ar location
+is
+.Ar 1:48.85667:N:2.2014:E:117.47:m:1
+The first digit is always
+.Ar 1 .
+It is followed by the latitude, a letter for the direction (
+.Ar E
+or
+.Ar W
+for East or West), the longitude and a letter for the direction (
+.Ar N
+or
+.Ar S
+). The next figure is the altitude. It can be expressed in meters (the
+next letter is then
+.Ar m
+) or in floors (the letter should be
+.Ar f
+). The last digit is the datum. It can either be
+.Ar 1
+(WGS84), 
+.Ar 2
+(NAD83) or
+.Ar 3
+(NAD83/MLLW).
+.It Em Civic address
+The location can be expressed as an address. The format of the
+location is then
+.Ar 2:FR:6:Commercial Rd:3:Roseville:19:4
+The first digit is always
+.Ar 2 .
+The next two letters are the country code. Then, arguments are paired
+to form the address. The first member of the pair is a digit
+indicating the type of the second member. Here is the list of
+valid types:
+.Bl -tag -width "XXXX." -compact
+.It Sy 0
+Language
+.It Sy 1
+National subdivisions
+.It Sy 2
+County, parish, district
+.It Sy 3
+City, township
+.It Sy 4
+City division, borough, ward
+.It Sy 5
+Neighborhood, block
+.It Sy 6
+Street
+.It Sy 16
+Leading street direction
+.It Sy 17
+Trailing street suffix
+.It Sy 18
+Street suffix
+.It Sy 19
+House number
+.It Sy 20
+House number suffix
+.It Sy 21
+Landmark or vanity address
+.It Sy 22
+Additional location info
+.It Sy 23
+Name
+.It Sy 24
+Postal/ZIP code
+.It Sy 25
+Building
+.It Sy 26
+Unit
+.It Sy 27
+Floor
+.It Sy 28
+Room number
+.It Sy 29
+Place type
+.It Sy 128
+Script
+.El
+.It ECS ELIN
+This is a numerical string using for setting up emergency call. The
+format of the location is then the following:
+.Ar 3:0000000911
+where the first digit should be
+.Ar 3
+and the second argument is the ELIN number.
+.El
 .Sh FILES
 .Bl -tag -width "/var/run/lldpd.socketXX" -compact
 .It /var/run/lldpd.socket
index d37c52bb8bcf0136eb58cf20c6f0ba8336b08ee5..c455dfb3ca25befea9dfdbcb5b68f93ca2c882bb 100644 (file)
@@ -52,10 +52,11 @@ lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
        struct lldp_macphy macphy;
 #endif
 #ifdef ENABLE_LLDPMED
+       int i;
        const u_int8_t med[] = LLDP_TLV_ORG_MED;
        struct lldpmed_cap medcap;
        struct lldp_org medhw, medfw, medsw, medsn,
-           medmodel, medasset, medmanuf;
+           medmodel, medasset, medmanuf, medloc[3];
 #endif
        struct lldpd_port *port = &hardware->h_lport;
        u_int c = -1, len = 0;
@@ -302,6 +303,33 @@ lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
                        LLDP_INVENTORY(global->g_lchassis.c_med_asset,
                            medasset, LLDP_TLV_MED_IV_ASSET);
                }
+
+               /* LLDP-MED location */
+               for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
+                       if (global->g_lchassis.c_med_location[i].format == i + 1) {
+                               memset(&medloc[i], 0, sizeof(struct lldp_org));
+                               medloc[i].tlv_head.type_len =
+                                   LLDP_TLV_HEAD(LLDP_TLV_ORG,
+                                       sizeof(medloc[i].tlv_org_id) +
+                                       sizeof(medloc[i].tlv_org_subtype) + 1 +
+                                       global->g_lchassis.c_med_location[i].data_len);
+                               memcpy(medloc[i].tlv_org_id, med,
+                                   sizeof(medloc[i].tlv_org_id));
+                               medloc[i].tlv_org_subtype = LLDP_TLV_MED_LOCATION;
+                               IOV_NEW;
+                               iov[c].iov_base = &medloc[i];
+                               iov[c].iov_len = sizeof(medloc[i]);
+                               IOV_NEW;
+                               iov[c].iov_base =
+                                   &global->g_lchassis.c_med_location[i].format;
+                               iov[c].iov_len = 1;
+                               IOV_NEW;
+                               iov[c].iov_base =
+                                   global->g_lchassis.c_med_location[i].data;
+                               iov[c].iov_len =
+                                   global->g_lchassis.c_med_location[i].data_len;
+                       }
+               }
        }
 #endif
 
index 7f9ea63cbc4177c5ea9e762444eb2566c3a525d4..cd94ad101f68f2a6a7054db7a0e9cee978ded3f9 100644 (file)
@@ -287,7 +287,7 @@ display_fixed_precision(u_int64_t value, int intpart, int floatpart, int display
        u_int64_t tmp = value;
        int negative = 0;
        u_int32_t integer = 0;
-       if (value & (1ULL<<(intpart + floatpart))) {
+       if (value & (1ULL<<(intpart + floatpart - 1))) {
                negative = 1;
                tmp = ~value;
                tmp += 1;
index 5b7f10da3f83a8c77d896af92197815e39503c95..2cc3bd6c74578bf24287b8fff78534c9228955e9 100644 (file)
@@ -1362,6 +1362,188 @@ lldpd_loop(struct lldpd *cfg)
        lldpd_recv_all(cfg);
 }
 
+#ifdef ENABLE_LLDPMED
+void
+lldpd_parse_location(struct lldpd_chassis *chassis, const char *location)
+{
+       char *l, *e, *s, *data, *n;
+       double ll, altitude;
+       u_int32_t intpart, floatpart;
+       int type = 0, i;
+
+       if ((l = strdup(location)) == NULL)
+               fatal(NULL);
+       s = l;
+       if ((e = index(s, ':')) == NULL)
+               goto invalid_location;
+       *e = '\0';
+       type = atoi(s);
+       switch (type) {
+       case LLDPMED_LOCFORMAT_COORD:
+               /* Coordinates */
+               if ((chassis->c_med_location[0].data =
+                       (char *)malloc(16)) == NULL)
+                       fatal(NULL);
+               chassis->c_med_location[0].data_len = 16;
+               chassis->c_med_location[0].format = LLDPMED_LOCFORMAT_COORD;
+               data = chassis->c_med_location[0].data;
+
+               /* Latitude and longitude */
+               for (i = 0; i < 2; i++) {
+                       s = e+1;
+                       if ((e = index(s, ':')) == NULL)
+                               goto invalid_location;
+                       *e = '\0';
+                       ll = atof(s);
+                       s = e + 1;
+                       if ((e = index(s, ':')) == NULL)
+                               goto invalid_location;
+                       *e = '\0';
+                       intpart = (int)ll;
+                       floatpart = (ll - intpart) * (1 << 25);
+                       if (((i == 0) && (*s == 'S')) ||
+                           ((i == 1) && (*s == 'W'))) {
+                               intpart = ~intpart;
+                               intpart += 1;
+                               floatpart = ~floatpart;
+                               floatpart += 1;
+                       } else if (((i == 0) && (*s != 'N')) ||
+                           ((i == 1) && (*s != 'E'))) 
+                               goto invalid_location;
+                       *(u_int8_t *)data = (6 << 2) |         /* Precision */
+                           ((intpart & 0x180) >> 7);          /* Int part 2 bits */
+                       data++;
+                       *(u_int8_t *)data = (((intpart & 0x7f) << 1) | /* Int part 7 bits */
+                           ((floatpart & 0x1000000) >> 24));   /* Float part 1 bit */
+                       data++;
+                       *(u_int8_t *)data = (floatpart & 0xff0000) >> 16; /* 8 bits */
+                       data++;
+                       *(u_int8_t *)data = (floatpart & 0xff00) >> 8; /* 8 bits */
+                       data++;
+                       *(u_int8_t *)data = (floatpart & 0xff); /* 8 bits */
+                       data++;
+               }
+               
+               /* Altitude */
+               s = e+1;
+               if ((e = index(s, ':')) == NULL)
+                       goto invalid_location;
+               *e = '\0';
+               altitude = atof(s);
+               s = e+1;
+               if ((e = index(s, ':')) == NULL)
+                       goto invalid_location;
+               *e = '\0';
+               if (altitude < 0) {
+                       intpart = -(int)altitude;
+                       floatpart = (-(altitude + intpart)) * (1 << 8);
+                       intpart = ~intpart; intpart += 1;
+                       floatpart = ~floatpart; floatpart += 1;
+               } else {
+                       intpart = (int)altitude;
+                       floatpart = (altitude - intpart) * (1 << 8);
+               }
+               if ((*s != 'm') && (*s != 'f'))
+                       goto invalid_location;
+               *(u_int8_t *)data = ((((*s == 'm')?1:2) << 4) |        /* Type 4 bits */
+                   0);                                                /* Precision 4 bits */
+               data++;
+               *(u_int8_t *)data = ((6 << 6) |                        /* Precision 2 bits */
+                   ((intpart & 0x3f0000) >> 16));                     /* Int 6 bits */
+               data++;
+               *(u_int8_t *)data = (intpart & 0xff00) >> 8; /* Int 8 bits */
+               data++;
+               *(u_int8_t *)data = intpart & 0xff; /* Int 8 bits */
+               data++;
+               *(u_int8_t *)data = floatpart & 0xff; /* Float 8 bits */
+               data++;
+
+               /* Datum */
+               s = e + 1;
+               if (index(s, ':') != NULL)
+                       goto invalid_location;
+               *(u_int8_t *)data = atoi(s);
+               break;
+       case LLDPMED_LOCFORMAT_CIVIC:
+               /* Civic address */
+               chassis->c_med_location[1].data_len = 4;
+               s = e+1;
+               if ((s = index(s, ':')) == NULL)
+                       goto invalid_location;
+               s = s+1;
+               do {
+                       if ((s = index(s, ':')) == NULL)
+                               break;
+                       s = s+1;
+                       /* s is the beginning of the word */
+                       if ((n = index(s, ':')) == NULL)
+                               n = s + strlen(s);
+                       /* n is the end of the word */
+                       chassis->c_med_location[1].data_len += (n - s) + 2;
+                       if ((s = index(s, ':')) == NULL)
+                               break;
+                       s = s+1;
+               } while (1);
+               s = e+1;
+               if ((chassis->c_med_location[1].data =
+                       (char *)malloc(chassis->c_med_location[1].data_len)) ==
+                   NULL)
+                       fatal(NULL);
+               chassis->c_med_location[1].format = LLDPMED_LOCFORMAT_CIVIC;
+               data = chassis->c_med_location[1].data;
+               *(u_int8_t *)data = chassis->c_med_location[1].data_len - 1;
+               data++;
+               *(u_int8_t *)data = 2; /* Client location */
+               data++;
+               if ((e = index(s, ':')) == NULL)
+                       goto invalid_location;
+               if ((e - s) != 2)
+                       goto invalid_location;
+               memcpy(data, s, 2); /* Country code */
+               data += 2;
+               while (*e != '\0') {
+                       s=e+1;
+                       if ((e = index(s, ':')) == NULL)
+                               goto invalid_location;
+                       *e = '\0';
+                       *(u_int8_t *)data = atoi(s);
+                       data++;
+                       s=e+1;
+                       if ((e = index(s, ':')) == NULL)
+                               e = s + strlen(s);
+                       *(u_int8_t *)data = e - s;
+                       data++;
+                       memcpy(data, s, e-s);
+                       data += e-s;
+               }
+               break;
+       case LLDPMED_LOCFORMAT_ELIN:
+               s = e+1;
+               chassis->c_med_location[2].data_len = strlen(s);
+               if ((chassis->c_med_location[2].data =
+                       (char *)malloc(strlen(s))) == NULL)
+                       fatal(NULL);
+               chassis->c_med_location[2].format = LLDPMED_LOCFORMAT_ELIN;
+               strcpy(chassis->c_med_location[2].data, s);
+               break;
+       default:
+               goto invalid_location;
+       }
+
+       chassis->c_med_cap_enabled |= LLDPMED_CAP_LOCATION;
+       return;
+invalid_location:
+       LLOG_WARNX("the format of the location is invalid (%s)",
+               location);
+       if (type) {
+               free(chassis->c_med_location[type-1].data);
+               memset(&chassis->c_med_location[type-1], 0,
+                   sizeof(struct lldpd_med_loc));
+       }
+       free(l);
+}
+#endif
+
 void
 lldpd_shutdown(int sig)
 {
@@ -1402,7 +1584,7 @@ main(int argc, char *argv[])
        int snmp = 0;
 #endif
        char *mgmtp = NULL;
-       char *popt, opts[] = "vdxm:p:M:i@                    ";
+       char *popt, opts[] = "vdxm:p:M:iL:P:@                    ";
        int probe = 0, i, found, vlan = 0;
 #ifdef ENABLE_LLDPMED
        int lldpmed = 0, noinventory = 0;
@@ -1430,26 +1612,30 @@ main(int argc, char *argv[])
                case 'm':
                        mgmtp = optarg;
                        break;
-               case 'M':
 #ifdef ENABLE_LLDPMED
+               case 'M':
                        lldpmed = atoi(optarg);
                        if ((lldpmed < 1) || (lldpmed > 4)) {
                                fprintf(stderr, "-M requires an argument between 1 and 4\n");
                                usage();
                        }
-#else
-                       fprintf(stderr, "LLDP-MED support is not built-in\n");
-                       usage();
-#endif
                        break;
                case 'i':
-#ifdef ENABLE_LLDPMED
                        noinventory = 1;
+                       break;
+               case 'L':
+               case 'P':
+                       /* Handled later */
+                       break;
 #else
+               case 'M':
+               case 'i':
+               case 'L':
+               case 'P':
                        fprintf(stderr, "LLDP-MED support is not built-in\n");
                        usage();
-#endif
                        break;
+#endif
                case 'p':
                        probe = atoi(optarg);
                        break;
@@ -1474,7 +1660,7 @@ main(int argc, char *argv[])
                                usage();
                }
        }
-
+       
        log_init(debug);
 
        if (!debug) {
@@ -1518,10 +1704,20 @@ main(int argc, char *argv[])
                        cfg->g_lchassis.c_cap_available |= LLDP_CAP_TELEPHONE;
                cfg->g_lchassis.c_med_type = lldpmed;
                cfg->g_lchassis.c_med_cap_available = LLDPMED_CAP_CAP |
-                   LLDPMED_CAP_IV;
+                   LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION;
                cfg->g_lchassis.c_med_cap_enabled = LLDPMED_CAP_CAP;
                if (!noinventory)
                        cfg->g_lchassis.c_med_cap_enabled |= LLDPMED_CAP_IV;
+               optind = 1;
+               while ((ch = getopt(argc, argv, opts)) != -1) {
+                       switch (ch) {
+                       case 'L':
+                               lldpd_parse_location(&cfg->g_lchassis, optarg);
+                               break;
+                       case 'P':
+                               break;
+                       }
+               }
        }
 #endif