chiark / gitweb /
shared: use SocketAddress in socket_address_matches_fd()
[elogind.git] / src / shared / socket-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <arpa/inet.h>
28 #include <stdio.h>
29 #include <net/if.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stddef.h>
33 #include <sys/ioctl.h>
34 #include <netdb.h>
35
36 #include "macro.h"
37 #include "util.h"
38 #include "mkdir.h"
39 #include "path-util.h"
40 #include "socket-util.h"
41 #include "missing.h"
42 #include "fileio.h"
43
44 int socket_address_parse(SocketAddress *a, const char *s) {
45         char *e, *n;
46         unsigned u;
47         int r;
48
49         assert(a);
50         assert(s);
51
52         zero(*a);
53         a->type = SOCK_STREAM;
54
55         if (*s == '[') {
56                 /* IPv6 in [x:.....:z]:p notation */
57
58                 if (!socket_ipv6_is_supported()) {
59                         log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
60                         return -EAFNOSUPPORT;
61                 }
62
63                 e = strchr(s+1, ']');
64                 if (!e)
65                         return -EINVAL;
66
67                 n = strndupa(s+1, e-s-1);
68
69                 errno = 0;
70                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
71                         return errno > 0 ? -errno : -EINVAL;
72
73                 e++;
74                 if (*e != ':')
75                         return -EINVAL;
76
77                 e++;
78                 r = safe_atou(e, &u);
79                 if (r < 0)
80                         return r;
81
82                 if (u <= 0 || u > 0xFFFF)
83                         return -EINVAL;
84
85                 a->sockaddr.in6.sin6_family = AF_INET6;
86                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
87                 a->size = sizeof(struct sockaddr_in6);
88
89         } else if (*s == '/') {
90                 /* AF_UNIX socket */
91
92                 size_t l;
93
94                 l = strlen(s);
95                 if (l >= sizeof(a->sockaddr.un.sun_path))
96                         return -EINVAL;
97
98                 a->sockaddr.un.sun_family = AF_UNIX;
99                 memcpy(a->sockaddr.un.sun_path, s, l);
100                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
101
102         } else if (*s == '@') {
103                 /* Abstract AF_UNIX socket */
104                 size_t l;
105
106                 l = strlen(s+1);
107                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
108                         return -EINVAL;
109
110                 a->sockaddr.un.sun_family = AF_UNIX;
111                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
112                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
113
114         } else {
115                 e = strchr(s, ':');
116                 if (e) {
117                         r = safe_atou(e+1, &u);
118                         if (r < 0)
119                                 return r;
120
121                         if (u <= 0 || u > 0xFFFF)
122                                 return -EINVAL;
123
124                         n = strndupa(s, e-s);
125
126                         /* IPv4 in w.x.y.z:p notation? */
127                         r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
128                         if (r < 0)
129                                 return -errno;
130
131                         if (r > 0) {
132                                 /* Gotcha, it's a traditional IPv4 address */
133                                 a->sockaddr.in.sin_family = AF_INET;
134                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
135                                 a->size = sizeof(struct sockaddr_in);
136                         } else {
137                                 unsigned idx;
138
139                                 if (strlen(n) > IF_NAMESIZE-1)
140                                         return -EINVAL;
141
142                                 /* Uh, our last resort, an interface name */
143                                 idx = if_nametoindex(n);
144                                 if (idx == 0)
145                                         return -EINVAL;
146
147                                 if (!socket_ipv6_is_supported()) {
148                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
149                                         return -EAFNOSUPPORT;
150                                 }
151
152                                 a->sockaddr.in6.sin6_family = AF_INET6;
153                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
154                                 a->sockaddr.in6.sin6_scope_id = idx;
155                                 a->sockaddr.in6.sin6_addr = in6addr_any;
156                                 a->size = sizeof(struct sockaddr_in6);
157                         }
158                 } else {
159
160                         /* Just a port */
161                         r = safe_atou(s, &u);
162                         if (r < 0)
163                                 return r;
164
165                         if (u <= 0 || u > 0xFFFF)
166                                 return -EINVAL;
167
168                         if (socket_ipv6_is_supported()) {
169                                 a->sockaddr.in6.sin6_family = AF_INET6;
170                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
171                                 a->sockaddr.in6.sin6_addr = in6addr_any;
172                                 a->size = sizeof(struct sockaddr_in6);
173                         } else {
174                                 a->sockaddr.in.sin_family = AF_INET;
175                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
176                                 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
177                                 a->size = sizeof(struct sockaddr_in);
178                         }
179                 }
180         }
181
182         return 0;
183 }
184
185 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
186         int family;
187         unsigned group = 0;
188         _cleanup_free_ char *sfamily = NULL;
189         assert(a);
190         assert(s);
191
192         zero(*a);
193         a->type = SOCK_RAW;
194
195         errno = 0;
196         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
197                 return errno > 0 ? -errno : -EINVAL;
198
199         family = netlink_family_from_string(sfamily);
200         if (family < 0)
201                 return -EINVAL;
202
203         a->sockaddr.nl.nl_family = AF_NETLINK;
204         a->sockaddr.nl.nl_groups = group;
205
206         a->type = SOCK_RAW;
207         a->size = sizeof(struct sockaddr_nl);
208         a->protocol = family;
209
210         return 0;
211 }
212
213 int socket_address_verify(const SocketAddress *a) {
214         assert(a);
215
216         switch (socket_address_family(a)) {
217
218         case AF_INET:
219                 if (a->size != sizeof(struct sockaddr_in))
220                         return -EINVAL;
221
222                 if (a->sockaddr.in.sin_port == 0)
223                         return -EINVAL;
224
225                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
226                         return -EINVAL;
227
228                 return 0;
229
230         case AF_INET6:
231                 if (a->size != sizeof(struct sockaddr_in6))
232                         return -EINVAL;
233
234                 if (a->sockaddr.in6.sin6_port == 0)
235                         return -EINVAL;
236
237                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
238                         return -EINVAL;
239
240                 return 0;
241
242         case AF_UNIX:
243                 if (a->size < offsetof(struct sockaddr_un, sun_path))
244                         return -EINVAL;
245
246                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
247
248                         if (a->sockaddr.un.sun_path[0] != 0) {
249                                 char *e;
250
251                                 /* path */
252                                 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
253                                 if (!e)
254                                         return -EINVAL;
255
256                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
257                                         return -EINVAL;
258                         }
259                 }
260
261                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
262                         return -EINVAL;
263
264                 return 0;
265
266         case AF_NETLINK:
267
268                 if (a->size != sizeof(struct sockaddr_nl))
269                         return -EINVAL;
270
271                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
272                         return -EINVAL;
273
274                 return 0;
275
276         default:
277                 return -EAFNOSUPPORT;
278         }
279 }
280
281 int socket_address_print(const SocketAddress *a, char **ret) {
282         int r;
283
284         assert(a);
285         assert(ret);
286
287         r = socket_address_verify(a);
288         if (r < 0)
289                 return r;
290
291         if (socket_address_family(a) == AF_NETLINK) {
292                 _cleanup_free_ char *sfamily = NULL;
293
294                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
295                 if (r < 0)
296                         return r;
297
298                 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
299                 if (r < 0)
300                         return -ENOMEM;
301
302                 return 0;
303         }
304
305         return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
306 }
307
308 bool socket_address_can_accept(const SocketAddress *a) {
309         assert(a);
310
311         return
312                 a->type == SOCK_STREAM ||
313                 a->type == SOCK_SEQPACKET;
314 }
315
316 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
317         assert(a);
318         assert(b);
319
320         /* Invalid addresses are unequal to all */
321         if (socket_address_verify(a) < 0 ||
322             socket_address_verify(b) < 0)
323                 return false;
324
325         if (a->type != b->type)
326                 return false;
327
328         if (socket_address_family(a) != socket_address_family(b))
329                 return false;
330
331         switch (socket_address_family(a)) {
332
333         case AF_INET:
334                 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
335                         return false;
336
337                 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
338                         return false;
339
340                 break;
341
342         case AF_INET6:
343                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
344                         return false;
345
346                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
347                         return false;
348
349                 break;
350
351         case AF_UNIX:
352                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
353                         return false;
354
355                 if (a->sockaddr.un.sun_path[0]) {
356                         if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
357                                 return false;
358                 } else {
359                         if (a->size != b->size)
360                                 return false;
361
362                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
363                                 return false;
364                 }
365
366                 break;
367
368         case AF_NETLINK:
369                 if (a->protocol != b->protocol)
370                         return false;
371
372                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
373                         return false;
374
375                 break;
376
377         default:
378                 /* Cannot compare, so we assume the addresses are different */
379                 return false;
380         }
381
382         return true;
383 }
384
385 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
386         struct SocketAddress b;
387
388         assert(a);
389         assert(s);
390
391         if (socket_address_parse(&b, s) < 0)
392                 return false;
393
394         b.type = type;
395
396         return socket_address_equal(a, &b);
397 }
398
399 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
400         struct SocketAddress b;
401
402         assert(a);
403         assert(s);
404
405         if (socket_address_parse_netlink(&b, s) < 0)
406                 return false;
407
408         return socket_address_equal(a, &b);
409 }
410
411 const char* socket_address_get_path(const SocketAddress *a) {
412         assert(a);
413
414         if (socket_address_family(a) != AF_UNIX)
415                 return NULL;
416
417         if (a->sockaddr.un.sun_path[0] == 0)
418                 return NULL;
419
420         return a->sockaddr.un.sun_path;
421 }
422
423 bool socket_ipv6_is_supported(void) {
424         _cleanup_free_ char *l = NULL;
425
426         if (access("/sys/module/ipv6", F_OK) != 0)
427                 return false;
428
429         /* If we can't check "disable" parameter, assume enabled */
430         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
431                 return true;
432
433         /* If module was loaded with disable=1 no IPv6 available */
434         return l[0] == '0';
435 }
436
437 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
438         SocketAddress b;
439         socklen_t solen;
440
441         assert(a);
442         assert(fd >= 0);
443
444         b.size = sizeof(b.sockaddr);
445         if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
446                 return false;
447
448         if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
449                 return false;
450
451         solen = sizeof(b.type);
452         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
453                 return false;
454
455         if (b.type != a->type)
456                 return false;
457
458         if (a->protocol != 0)  {
459                 solen = sizeof(b.protocol);
460                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
461                         return false;
462
463                 if (b.protocol != a->protocol)
464                         return false;
465         }
466
467         switch (b.sockaddr.sa.sa_family) {
468
469         case AF_INET:
470                 return b.sockaddr.in.sin_port == a->sockaddr.in.sin_port &&
471                         b.sockaddr.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
472
473         case AF_INET6:
474                 return b.sockaddr.in6.sin6_port == a->sockaddr.in6.sin6_port &&
475                         memcmp(&b.sockaddr.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
476
477         case AF_UNIX:
478                 return b.sockaddr.size == a->size &&
479                         memcmp(b.sockaddr.un.sun_path, a->sockaddr.un.sun_path, b.size - offsetof(struct sockaddr_un, sun_path)) == 0;
480
481         }
482
483         return false;
484 }
485
486 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
487         union sockaddr_union *sa = (union sockaddr_union*) _sa;
488         char *p;
489
490         assert(sa);
491         assert(salen >= sizeof(sa->sa.sa_family));
492
493         switch (sa->sa.sa_family) {
494
495         case AF_INET: {
496                 uint32_t a;
497
498                 a = ntohl(sa->in.sin_addr.s_addr);
499
500                 if (asprintf(&p,
501                              "%u.%u.%u.%u:%u",
502                              a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
503                              ntohs(sa->in.sin_port)) < 0)
504                         return -ENOMEM;
505
506                 break;
507         }
508
509         case AF_INET6: {
510                 static const unsigned char ipv4_prefix[] = {
511                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
512                 };
513
514                 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
515                         const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
516
517                         if (asprintf(&p,
518                                      "%u.%u.%u.%u:%u",
519                                      a[0], a[1], a[2], a[3],
520                                      ntohs(sa->in6.sin6_port)) < 0)
521                                 return -ENOMEM;
522                 } else {
523                         char a[INET6_ADDRSTRLEN];
524
525                         if (asprintf(&p,
526                                      "[%s]:%u",
527                                      inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
528                                      ntohs(sa->in6.sin6_port)) < 0)
529                                 return -ENOMEM;
530                 }
531
532                 break;
533         }
534
535         case AF_UNIX:
536                 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
537                         p = strdup("<unnamed>");
538                         if (!p)
539                                 return -ENOMEM;
540
541                 } else if (sa->un.sun_path[0] == 0) {
542                         /* abstract */
543
544                         /* FIXME: We assume we can print the
545                          * socket path here and that it hasn't
546                          * more than one NUL byte. That is
547                          * actually an invalid assumption */
548
549                         p = new(char, sizeof(sa->un.sun_path)+1);
550                         if (!p)
551                                 return -ENOMEM;
552
553                         p[0] = '@';
554                         memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
555                         p[sizeof(sa->un.sun_path)] = 0;
556
557                 } else {
558                         p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
559                         if (!ret)
560                                 return -ENOMEM;
561                 }
562
563                 break;
564
565         default:
566                 return -ENOTSUP;
567         }
568
569
570         *ret = p;
571         return 0;
572 }
573
574 int getpeername_pretty(int fd, char **ret) {
575         union sockaddr_union sa;
576         socklen_t salen = sizeof(sa);
577         int r;
578
579         assert(fd >= 0);
580         assert(ret);
581
582         if (getpeername(fd, &sa.sa, &salen) < 0)
583                 return -errno;
584
585         if (sa.sa.sa_family == AF_UNIX) {
586                 struct ucred ucred = {};
587
588                 /* UNIX connection sockets are anonymous, so let's use
589                  * PID/UID as pretty credentials instead */
590
591                 r = getpeercred(fd, &ucred);
592                 if (r < 0)
593                         return r;
594
595                 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
596                         return -ENOMEM;
597
598                 return 0;
599         }
600
601         /* For remote sockets we translate IPv6 addresses back to IPv4
602          * if applicable, since that's nicer. */
603
604         return sockaddr_pretty(&sa.sa, salen, true, ret);
605 }
606
607 int getsockname_pretty(int fd, char **ret) {
608         union sockaddr_union sa;
609         socklen_t salen = sizeof(sa);
610
611         assert(fd >= 0);
612         assert(ret);
613
614         if (getsockname(fd, &sa.sa, &salen) < 0)
615                 return -errno;
616
617         /* For local sockets we do not translate IPv6 addresses back
618          * to IPv6 if applicable, since this is usually used for
619          * listening sockets where the difference between IPv4 and
620          * IPv6 matters. */
621
622         return sockaddr_pretty(&sa.sa, salen, false, ret);
623 }
624
625 int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
626         int r;
627         char host[NI_MAXHOST], *ret;
628
629         assert(_ret);
630
631         r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
632                         NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
633         if (r != 0) {
634                 int saved_errno = errno;
635
636                 r = sockaddr_pretty(&sa->sa, salen, true, &ret);
637                 if (r < 0)
638                         return log_error_errno(r, "sockadd_pretty() failed: %m");
639
640                 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
641         } else {
642                 ret = strdup(host);
643                 if (!ret)
644                         return log_oom();
645         }
646
647         *_ret = ret;
648         return 0;
649 }
650
651 int getnameinfo_pretty(int fd, char **ret) {
652         union sockaddr_union sa;
653         socklen_t salen = sizeof(sa);
654
655         assert(fd >= 0);
656         assert(ret);
657
658         if (getsockname(fd, &sa.sa, &salen) < 0)
659                 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
660
661         return socknameinfo_pretty(&sa, salen, ret);
662 }
663
664 int socket_address_unlink(SocketAddress *a) {
665         assert(a);
666
667         if (socket_address_family(a) != AF_UNIX)
668                 return 0;
669
670         if (a->sockaddr.un.sun_path[0] == 0)
671                 return 0;
672
673         if (unlink(a->sockaddr.un.sun_path) < 0)
674                 return -errno;
675
676         return 1;
677 }
678
679 static const char* const netlink_family_table[] = {
680         [NETLINK_ROUTE] = "route",
681         [NETLINK_FIREWALL] = "firewall",
682         [NETLINK_INET_DIAG] = "inet-diag",
683         [NETLINK_NFLOG] = "nflog",
684         [NETLINK_XFRM] = "xfrm",
685         [NETLINK_SELINUX] = "selinux",
686         [NETLINK_ISCSI] = "iscsi",
687         [NETLINK_AUDIT] = "audit",
688         [NETLINK_FIB_LOOKUP] = "fib-lookup",
689         [NETLINK_CONNECTOR] = "connector",
690         [NETLINK_NETFILTER] = "netfilter",
691         [NETLINK_IP6_FW] = "ip6-fw",
692         [NETLINK_DNRTMSG] = "dnrtmsg",
693         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
694         [NETLINK_GENERIC] = "generic",
695         [NETLINK_SCSITRANSPORT] = "scsitransport",
696         [NETLINK_ECRYPTFS] = "ecryptfs"
697 };
698
699 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
700
701 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
702         [SOCKET_ADDRESS_DEFAULT] = "default",
703         [SOCKET_ADDRESS_BOTH] = "both",
704         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
705 };
706
707 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
708
709 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
710         assert(a);
711         assert(b);
712
713         if (a->sa.sa_family != b->sa.sa_family)
714                 return false;
715
716         if (a->sa.sa_family == AF_INET)
717                 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
718
719         if (a->sa.sa_family == AF_INET6)
720                 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
721
722         return false;
723 }
724
725 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
726         assert(addr);
727         assert(buffer);
728
729         /* Like ether_ntoa() but uses %02x instead of %x to print
730          * ethernet addresses, which makes them look less funny. Also,
731          * doesn't use a static buffer. */
732
733         sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
734                 addr->ether_addr_octet[0],
735                 addr->ether_addr_octet[1],
736                 addr->ether_addr_octet[2],
737                 addr->ether_addr_octet[3],
738                 addr->ether_addr_octet[4],
739                 addr->ether_addr_octet[5]);
740
741         return buffer;
742 }