Remove building with NOCRYPTO option
[minix3.git] / minix / net / lwip / ifconf.c
blobe1a48c7f865bd067b8d13770ee6816180c4ad6c5
1 /* LWIP service - ifconf.c - interface configuration */
3 #include "lwip.h"
4 #include "ifaddr.h"
5 #include "lldata.h"
7 #include <net/if_media.h>
8 #include <minix/if.h>
10 #define LOOPBACK_IFNAME "lo0" /* name of the loopback interface */
13 * Initialize the first loopback device, which is present by default.
15 void
16 ifconf_init(void)
18 const struct sockaddr_in addr = {
19 .sin_family = AF_INET,
20 .sin_addr = { htonl(INADDR_LOOPBACK) }
22 struct sockaddr_in6 ll_addr6 = {
23 .sin6_family = AF_INET6,
25 const struct sockaddr_in6 lo_addr6 = {
26 .sin6_family = AF_INET6,
27 .sin6_addr = IN6ADDR_LOOPBACK_INIT
29 const struct in6_addrlifetime lifetime = {
30 .ia6t_vltime = ND6_INFINITE_LIFETIME,
31 .ia6t_pltime = ND6_INFINITE_LIFETIME
33 struct sockaddr_in6 mask6;
34 struct ifdev *ifdev;
35 socklen_t addr_len;
36 int r;
38 if ((r = ifdev_create(LOOPBACK_IFNAME)) != OK)
39 panic("unable to create loopback interface: %d", r);
41 if ((ifdev = ifdev_find_by_name(LOOPBACK_IFNAME)) == NULL)
42 panic("unable to find loopback interface");
44 if ((r = ifaddr_v4_add(ifdev, &addr, NULL, NULL, NULL, 0)) != OK)
45 panic("unable to set IPv4 address on loopback interface: %d",
46 r);
48 addr_len = sizeof(mask6);
49 addr_put_netmask((struct sockaddr *)&mask6, &addr_len, IPADDR_TYPE_V6,
50 64 /*prefix*/);
52 ll_addr6.sin6_addr.s6_addr[0] = 0xfe;
53 ll_addr6.sin6_addr.s6_addr[1] = 0x80;
54 ll_addr6.sin6_addr.s6_addr[15] = ifdev_get_index(ifdev);
56 if ((r = ifaddr_v6_add(ifdev, &ll_addr6, &mask6, NULL, 0,
57 &lifetime)) != OK)
58 panic("unable to set IPv6 address on loopback interface: %d",
59 r);
61 addr_len = sizeof(mask6);
62 addr_put_netmask((struct sockaddr *)&mask6, &addr_len, IPADDR_TYPE_V6,
63 128 /*prefix*/);
65 if ((r = ifaddr_v6_add(ifdev, &lo_addr6, &mask6, NULL, 0,
66 &lifetime)) != OK)
67 panic("unable to set IPv6 address on loopback interface: %d",
68 r);
70 if ((r = ifdev_set_ifflags(ifdev, IFF_UP)) != OK)
71 panic("unable to bring up loopback interface");
75 * Process an address family independent IOCTL request with an "ifreq"
76 * structure.
78 static int
79 ifconf_ioctl_ifreq(unsigned long request, const struct sockdriver_data * data)
81 struct ifdev *ifdev;
82 struct ifreq ifr;
83 int r;
85 if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
86 return r;
88 if (request != SIOCIFCREATE) {
89 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
91 if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
92 return ENXIO;
93 } else
94 ifdev = NULL;
96 switch (request) {
97 case SIOCGIFFLAGS:
98 ifr.ifr_flags = ifdev_get_ifflags(ifdev);
100 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
102 case SIOCSIFFLAGS:
104 * Unfortunately, ifr_flags is a signed integer and the sign
105 * bit is in fact used as a flag, so without explicit casting
106 * we end up setting all upper bits of the (full) integer. If
107 * NetBSD ever extends the field, this assert should trigger..
109 assert(sizeof(ifr.ifr_flags) == sizeof(short));
111 return ifdev_set_ifflags(ifdev, (unsigned short)ifr.ifr_flags);
113 case SIOCGIFMETRIC:
114 ifr.ifr_metric = ifdev_get_metric(ifdev);
116 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
118 case SIOCSIFMETRIC:
119 /* The metric is not used within the operating system. */
120 ifdev_set_metric(ifdev, ifr.ifr_metric);
122 return OK;
124 case SIOCSIFMEDIA:
125 return ifdev_set_ifmedia(ifdev, ifr.ifr_media);
127 case SIOCGIFMTU:
128 ifr.ifr_mtu = ifdev_get_mtu(ifdev);
130 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
132 case SIOCSIFMTU:
133 return ifdev_set_mtu(ifdev, ifr.ifr_mtu);
135 case SIOCIFCREATE:
136 if (memchr(ifr.ifr_name, '\0', sizeof(ifr.ifr_name)) == NULL)
137 return EINVAL;
139 return ifdev_create(ifr.ifr_name);
141 case SIOCIFDESTROY:
142 return ifdev_destroy(ifdev);
144 case SIOCGIFDLT:
145 ifr.ifr_dlt = ifdev_get_dlt(ifdev);
147 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
149 case SIOCGIFINDEX:
150 ifr.ifr_index = ifdev_get_index(ifdev);
152 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
154 default:
155 return ENOTTY;
160 * Process an address family independent IOCTL request with an "ifcapreq"
161 * structure.
163 static int
164 ifconf_ioctl_ifcap(unsigned long request,
165 const struct sockdriver_data * data)
167 struct ifdev *ifdev;
168 struct ifcapreq ifcr;
169 int r;
171 if ((r = sockdriver_copyin(data, 0, &ifcr, sizeof(ifcr))) != OK)
172 return r;
174 ifcr.ifcr_name[sizeof(ifcr.ifcr_name) - 1] = '\0';
176 if ((ifdev = ifdev_find_by_name(ifcr.ifcr_name)) == NULL)
177 return ENXIO;
179 switch (request) {
180 case SIOCSIFCAP:
181 return ifdev_set_ifcap(ifdev, ifcr.ifcr_capenable);
183 case SIOCGIFCAP:
184 ifdev_get_ifcap(ifdev, &ifcr.ifcr_capabilities,
185 &ifcr.ifcr_capenable);
187 return sockdriver_copyout(data, 0, &ifcr, sizeof(ifcr));
189 default:
190 return ENOTTY;
195 * Process an address family independent IOCTL request with an "ifmediareq"
196 * structure.
198 static int
199 ifconf_ioctl_ifmedia(unsigned long request,
200 const struct sockdriver_data * data)
202 struct ifdev *ifdev;
203 struct ifmediareq ifm;
204 int r;
206 if ((r = sockdriver_copyin(data, 0, &ifm, sizeof(ifm))) != OK)
207 return r;
209 ifm.ifm_name[sizeof(ifm.ifm_name) - 1] = '\0';
211 if ((ifdev = ifdev_find_by_name(ifm.ifm_name)) == NULL)
212 return ENXIO;
214 switch (request) {
215 case MINIX_SIOCGIFMEDIA:
216 if ((r = ifdev_get_ifmedia(ifdev, &ifm.ifm_current,
217 &ifm.ifm_active)) != OK)
218 return r;
219 ifm.ifm_mask = 0;
221 switch (ifdev_get_link(ifdev)) {
222 case LINK_STATE_UP:
223 ifm.ifm_status = IFM_AVALID | IFM_ACTIVE;
224 break;
225 case LINK_STATE_DOWN:
226 ifm.ifm_status = IFM_AVALID;
227 break;
228 default:
229 ifm.ifm_status = 0;
230 break;
234 * TODO: support for the list of supported media types. This
235 * one is not easy, because we cannot simply suspend the IOCTL
236 * and query the driver. For now, return only entry (which is
237 * the minimum for ifconfig(8) not to complain), namely the
238 * currently selected one.
240 if (ifm.ifm_ulist != NULL) {
241 if (ifm.ifm_count < 1)
242 return ENOMEM;
245 * Copy out the 'list', which consists of one entry.
246 * If we were to produce multiple entries, we would
247 * have to check against the MINIX_IF_MAXMEDIA limit.
249 if ((r = sockdriver_copyout(data,
250 offsetof(struct minix_ifmediareq, mifm_list),
251 &ifm.ifm_current, sizeof(ifm.ifm_current))) != OK)
252 return r;
254 ifm.ifm_count = 1;
256 return sockdriver_copyout(data, 0, &ifm, sizeof(ifm));
258 default:
259 return ENOTTY;
264 * Process an address family independent IOCTL request with an "if_clonereq"
265 * structure.
267 static int
268 ifconf_ioctl_ifclone(unsigned long request,
269 const struct sockdriver_data * data)
271 struct if_clonereq ifcr;
272 const char *ptr;
273 char name[IFNAMSIZ];
274 size_t off;
275 unsigned int num;
276 int r;
278 if ((r = sockdriver_copyin(data, 0, &ifcr, sizeof(ifcr))) != OK)
279 return r;
281 if (ifcr.ifcr_count < 0)
282 return EINVAL;
284 off = offsetof(struct minix_if_clonereq, mifcr_buffer);
286 for (num = 0; (ptr = ifdev_enum_vtypes(num)) != NULL; num++) {
287 /* Prevent overflow in case we ever have over 128 vtypes.. */
288 if (num == MINIX_IF_MAXCLONERS)
289 break;
291 if (ifcr.ifcr_buffer == NULL ||
292 num >= (unsigned int)ifcr.ifcr_count)
293 continue;
295 memset(name, 0, sizeof(name));
296 strlcpy(name, ptr, sizeof(name));
298 if ((r = sockdriver_copyout(data, off, name,
299 sizeof(name))) != OK)
300 return r;
302 off += sizeof(name);
305 ifcr.ifcr_total = num;
307 return sockdriver_copyout(data, 0, &ifcr, sizeof(ifcr));
311 * Process an address family independent IOCTL request with an "if_addrprefreq"
312 * structure.
314 static int
315 ifconf_ioctl_ifaddrpref(unsigned long request,
316 const struct sockdriver_data * data)
318 struct ifdev *ifdev;
319 struct if_addrprefreq ifap;
320 int r;
322 if ((r = sockdriver_copyin(data, 0, &ifap, sizeof(ifap))) != OK)
323 return r;
325 ifap.ifap_name[sizeof(ifap.ifap_name) - 1] = '\0';
327 if ((ifdev = ifdev_find_by_name(ifap.ifap_name)) == NULL)
328 return ENXIO;
331 * For now, we simply support only a preference of 0. We do not try to
332 * look up the given address, nor do we return the looked up address.
334 switch (request) {
335 case SIOCSIFADDRPREF:
336 if (ifap.ifap_preference != 0)
337 return EINVAL;
339 return OK;
341 case SIOCGIFADDRPREF:
342 ifap.ifap_preference = 0;
344 return sockdriver_copyout(data, 0, &ifap, sizeof(ifap));
346 default:
347 return ENOTTY;
352 * Process an IOCTL request for AF_INET with an "ifreq" structure.
354 static int
355 ifconf_ioctl_v4_ifreq(unsigned long request,
356 const struct sockdriver_data * data)
358 struct sockaddr_in addr, mask, bcast, dest, *sin = NULL /*gcc*/;
359 struct ifdev *ifdev;
360 struct ifreq ifr;
361 ifaddr_v4_num_t num;
362 int r, flags;
364 if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
365 return r;
367 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
369 if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
370 return ENXIO;
372 switch (request) {
373 case SIOCGIFADDR:
374 case SIOCGIFNETMASK:
375 case SIOCGIFBRDADDR:
376 case SIOCGIFDSTADDR:
377 /* Retrieve all addresses, then copy out the desired one. */
378 switch (request) {
379 case SIOCGIFADDR: sin = &addr; break;
380 case SIOCGIFNETMASK: sin = &mask; break;
381 case SIOCGIFBRDADDR: sin = &bcast; break;
382 case SIOCGIFDSTADDR: sin = &dest; break;
385 sin->sin_len = 0;
387 if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
388 &bcast, &dest)) != OK)
389 return r;
391 if (sin->sin_len == 0) /* not filled in */
392 return EADDRNOTAVAIL;
394 memcpy(&ifr.ifr_addr, sin, sizeof(*sin));
396 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
398 case SIOCGIFAFLAG_IN:
399 if ((r = ifaddr_v4_find(ifdev,
400 (struct sockaddr_in *)&ifr.ifr_addr, &num)) != OK)
401 return r;
403 ifr.ifr_addrflags = ifaddr_v4_get_flags(ifdev, num);
405 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
407 case SIOCSIFADDR:
409 * This one is slightly different from the rest, in that we
410 * either set or update the primary address: if we set it, we
411 * must let _add() generate a matching netmask automatically,
412 * while if we update it, _add() would fail unless we first
413 * delete the old entry.
415 sin = (struct sockaddr_in *)&ifr.ifr_addr;
417 if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
418 &bcast, &dest)) == OK) {
419 flags = ifaddr_v4_get_flags(ifdev, (ifaddr_v4_num_t)0);
421 ifaddr_v4_del(ifdev, (ifaddr_v4_num_t)0);
424 * If setting the new address fails, reinstating the
425 * old address should always work. This is really ugly
426 * as it generates routing socket noise, but this call
427 * is deprecated anyway.
429 if ((r = ifaddr_v4_add(ifdev, sin, &mask, &bcast,
430 &dest, 0 /*flags*/)) != OK)
431 (void)ifaddr_v4_add(ifdev, &addr, &mask,
432 &bcast, &dest, flags);
434 return r;
435 } else
436 return ifaddr_v4_add(ifdev, sin, NULL /*mask*/,
437 NULL /*bcast*/, NULL /*dest*/, 0 /*flags*/);
439 case SIOCSIFNETMASK:
440 case SIOCSIFBRDADDR:
441 case SIOCSIFDSTADDR:
442 /* These calls only update the existing primary address. */
443 if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
444 &bcast, &dest)) != OK)
445 return r;
447 sin = (struct sockaddr_in *)&ifr.ifr_addr;
449 switch (request) {
450 case SIOCSIFNETMASK: memcpy(&mask, sin, sizeof(mask)); break;
451 case SIOCSIFBRDADDR: memcpy(&bcast, sin, sizeof(bcast)); break;
452 case SIOCSIFDSTADDR: memcpy(&dest, sin, sizeof(dest)); break;
455 return ifaddr_v4_add(ifdev, &addr, &mask, &bcast, &dest,
456 ifaddr_v4_get_flags(ifdev, (ifaddr_v4_num_t)0));
458 case SIOCDIFADDR:
459 if ((r = ifaddr_v4_find(ifdev,
460 (struct sockaddr_in *)&ifr.ifr_addr, &num)) != OK)
461 return r;
463 ifaddr_v4_del(ifdev, num);
465 return OK;
467 default:
468 return ENOTTY;
473 * Process an IOCTL request for AF_INET with an "ifaliasreq" structure.
475 static int
476 ifconf_ioctl_v4_ifalias(unsigned long request,
477 const struct sockdriver_data * data)
479 struct ifdev *ifdev;
480 struct ifaliasreq ifra;
481 struct sockaddr_in dest;
482 ifaddr_v4_num_t num;
483 int r;
485 if ((r = sockdriver_copyin(data, 0, &ifra, sizeof(ifra))) != OK)
486 return r;
488 ifra.ifra_name[sizeof(ifra.ifra_name) - 1] = '\0';
490 if ((ifdev = ifdev_find_by_name(ifra.ifra_name)) == NULL)
491 return ENXIO;
493 switch (request) {
494 case SIOCAIFADDR:
495 return ifaddr_v4_add(ifdev,
496 (struct sockaddr_in *)&ifra.ifra_addr,
497 (struct sockaddr_in *)&ifra.ifra_mask,
498 (struct sockaddr_in *)&ifra.ifra_broadaddr,
499 (struct sockaddr_in *)&ifra.ifra_dstaddr, 0 /*flags*/);
501 case SIOCGIFALIAS:
502 if ((r = ifaddr_v4_find(ifdev,
503 (struct sockaddr_in *)&ifra.ifra_addr, &num)) != OK)
504 return r;
507 * The broadcast and destination address are stored in the same
508 * ifaliasreq field. We cannot pass a pointer to the same
509 * field to ifaddr_v4_get(). So, use a temporary variable.
511 (void)ifaddr_v4_get(ifdev, num,
512 (struct sockaddr_in *)&ifra.ifra_addr,
513 (struct sockaddr_in *)&ifra.ifra_mask,
514 (struct sockaddr_in *)&ifra.ifra_broadaddr, &dest);
516 if (ifra.ifra_broadaddr.sa_len == 0)
517 memcpy(&ifra.ifra_dstaddr, &dest, sizeof(dest));
519 return sockdriver_copyout(data, 0, &ifra, sizeof(ifra));
521 default:
522 return ENOTTY;
527 * Process an IOCTL request for AF_INET.
529 static int
530 ifconf_ioctl_v4(unsigned long request, const struct sockdriver_data * data,
531 endpoint_t user_endpt)
534 switch (request) {
535 case SIOCSIFADDR:
536 case SIOCSIFDSTADDR:
537 case SIOCSIFBRDADDR:
538 case SIOCSIFNETMASK:
539 case SIOCDIFADDR:
540 if (!util_is_root(user_endpt))
541 return EPERM;
543 /* FALLTHROUGH */
544 case SIOCGIFADDR:
545 case SIOCGIFDSTADDR:
546 case SIOCGIFBRDADDR:
547 case SIOCGIFNETMASK:
548 case SIOCGIFAFLAG_IN:
549 return ifconf_ioctl_v4_ifreq(request, data);
551 case SIOCAIFADDR:
552 if (!util_is_root(user_endpt))
553 return EPERM;
555 /* FALLTHROUGH */
556 case SIOCGIFALIAS:
557 return ifconf_ioctl_v4_ifalias(request, data);
559 default:
560 return ENOTTY;
564 #ifdef INET6
566 * Process an IOCTL request for AF_INET6 with an "in6_ifreq" structure.
568 static int
569 ifconf_ioctl_v6_ifreq(unsigned long request,
570 const struct sockdriver_data * data)
572 struct ifdev *ifdev;
573 struct in6_ifreq ifr;
574 ifaddr_v6_num_t num;
575 int r;
577 if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
578 return r;
580 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
582 if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
583 return ENXIO;
585 if ((r = ifaddr_v6_find(ifdev, &ifr.ifr_addr, &num)) != OK)
586 return r;
588 switch (request) {
589 case SIOCGIFADDR_IN6:
590 /* This IOCTL basically checks if the given address exists. */
591 ifaddr_v6_get(ifdev, num, &ifr.ifr_addr, NULL, NULL);
593 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
595 case SIOCDIFADDR_IN6:
596 ifaddr_v6_del(ifdev, num);
598 return OK;
600 case SIOCGIFNETMASK_IN6:
601 ifaddr_v6_get(ifdev, num, NULL, &ifr.ifr_addr, NULL);
603 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
605 case SIOCGIFAFLAG_IN6:
606 ifr.ifr_ifru.ifru_flags6 = ifaddr_v6_get_flags(ifdev, num);
608 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
610 case SIOCGIFALIFETIME_IN6:
611 ifaddr_v6_get_lifetime(ifdev, num,
612 &ifr.ifr_ifru.ifru_lifetime);
614 return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
616 default:
617 return ENOTTY;
622 * Process an IOCTL request for AF_INET6 with an "in6_aliasreq" structure.
624 static int
625 ifconf_ioctl_v6_ifalias(unsigned long request,
626 const struct sockdriver_data * data)
628 struct ifdev *ifdev;
629 struct in6_aliasreq ifra;
630 int r;
632 if ((r = sockdriver_copyin(data, 0, &ifra, sizeof(ifra))) != OK)
633 return r;
635 ifra.ifra_name[sizeof(ifra.ifra_name) - 1] = '\0';
637 if ((ifdev = ifdev_find_by_name(ifra.ifra_name)) == NULL)
638 return ENXIO;
640 switch (request) {
641 case SIOCAIFADDR_IN6:
642 return ifaddr_v6_add(ifdev, &ifra.ifra_addr,
643 &ifra.ifra_prefixmask, &ifra.ifra_dstaddr,
644 ifra.ifra_flags, &ifra.ifra_lifetime);
646 default:
647 return ENOTTY;
652 * Process an IOCTL request for AF_INET6 with an "in6_ndireq" structure.
654 static int
655 ifconf_ioctl_v6_ndireq(unsigned long request,
656 const struct sockdriver_data * data)
658 struct ifdev *ifdev;
659 struct in6_ndireq ndi;
660 int r;
662 if ((r = sockdriver_copyin(data, 0, &ndi, sizeof(ndi))) != OK)
663 return r;
665 ndi.ifname[sizeof(ndi.ifname) - 1] = '\0';
667 if ((ifdev = ifdev_find_by_name(ndi.ifname)) == NULL)
668 return ENXIO;
670 switch (request) {
671 case SIOCGIFINFO_IN6:
672 memset(&ndi.ndi, 0, sizeof(ndi.ndi));
674 ndi.ndi.linkmtu = ifdev_get_mtu(ifdev);
675 ndi.ndi.flags = ifdev_get_nd6flags(ifdev);
676 ndi.ndi.initialized = 1;
677 /* TODO: all the other fields.. */
679 return sockdriver_copyout(data, 0, &ndi, sizeof(ndi));
681 case SIOCSIFINFO_IN6:
682 /* TODO: all the other fields.. */
684 /* FALLTHROUGH */
685 case SIOCSIFINFO_FLAGS:
686 return ifdev_set_nd6flags(ifdev, ndi.ndi.flags);
688 default:
689 return ENOTTY;
694 * Process an IOCTL request for AF_INET6 with an "in6_nbrinfo" structure.
696 static int
697 ifconf_ioctl_v6_nbrinfo(unsigned long request,
698 const struct sockdriver_data * data)
700 struct ifdev *ifdev;
701 struct sockaddr_in6 addr;
702 struct in6_nbrinfo nbri;
703 lldata_ndp_num_t num;
704 int r;
706 if ((r = sockdriver_copyin(data, 0, &nbri, sizeof(nbri))) != OK)
707 return r;
709 nbri.ifname[sizeof(nbri.ifname) - 1] = '\0';
711 if ((ifdev = ifdev_find_by_name(nbri.ifname)) == NULL)
712 return ENXIO;
714 switch (request) {
715 case SIOCGNBRINFO_IN6:
717 * Convert the given in6_addr to a full sockaddr_in6, mainly
718 * for internal consistency. It would have been nice if the
719 * KAME management API had had any sort of consistency itself.
721 memset(&addr, 0, sizeof(addr));
722 addr.sin6_family = AF_INET6;
723 memcpy(&addr.sin6_addr.s6_addr, &nbri.addr,
724 sizeof(addr.sin6_addr.s6_addr));
726 if ((r = lldata_ndp_find(ifdev, &addr, &num)) != OK)
727 return r;
729 lldata_ndp_get_info(num, &nbri.asked, &nbri.isrouter,
730 &nbri.state, &nbri.expire);
732 return sockdriver_copyout(data, 0, &nbri, sizeof(nbri));
734 default:
735 return ENOTTY;
740 * Process an IOCTL request for AF_INET6.
742 static int
743 ifconf_ioctl_v6(unsigned long request, const struct sockdriver_data * data,
744 endpoint_t user_endpt)
747 switch (request) {
748 case SIOCDIFADDR_IN6:
749 if (!util_is_root(user_endpt))
750 return EPERM;
752 /* FALLTHROUGH */
753 case SIOCGIFADDR_IN6:
754 case SIOCGIFNETMASK_IN6:
755 case SIOCGIFAFLAG_IN6:
756 case SIOCGIFALIFETIME_IN6:
757 return ifconf_ioctl_v6_ifreq(request, data);
759 case SIOCAIFADDR_IN6:
760 if (!util_is_root(user_endpt))
761 return EPERM;
763 return ifconf_ioctl_v6_ifalias(request, data);
765 case SIOCSIFINFO_IN6:
766 case SIOCSIFINFO_FLAGS:
767 if (!util_is_root(user_endpt))
768 return EPERM;
770 /* FALLTHROUGH */
771 case SIOCGIFINFO_IN6:
772 return ifconf_ioctl_v6_ndireq(request, data);
774 case SIOCGNBRINFO_IN6:
775 return ifconf_ioctl_v6_nbrinfo(request, data);
777 default:
778 return ENOTTY;
781 #endif /* INET6 */
784 * Process an IOCTL request for AF_LINK with an "if_laddrreq" structure.
786 static int
787 ifconf_ioctl_dl_lifaddr(unsigned long request,
788 const struct sockdriver_data * data)
790 struct ifdev *ifdev;
791 struct if_laddrreq iflr;
792 ifaddr_dl_num_t num;
793 int r;
795 if ((r = sockdriver_copyin(data, 0, &iflr, sizeof(iflr))) != OK)
796 return r;
798 iflr.iflr_name[sizeof(iflr.iflr_name) - 1] = '\0';
800 if ((ifdev = ifdev_find_by_name(iflr.iflr_name)) == NULL)
801 return ENXIO;
803 switch (request) {
804 case SIOCGLIFADDR:
805 if (iflr.flags & IFLR_PREFIX) {
806 /* We ignore the prefix length, like NetBSD does. */
807 if ((r = ifaddr_dl_find(ifdev,
808 (struct sockaddr_dlx *)&iflr.addr,
809 sizeof(iflr.addr), &num)) != OK)
810 return r;
811 } else
812 num = (ifaddr_dl_num_t)0; /* this always works */
814 ifaddr_dl_get(ifdev, num, (struct sockaddr_dlx *)&iflr.addr);
815 iflr.flags = ifaddr_dl_get_flags(ifdev, num);
816 memset(&iflr.dstaddr, 0, sizeof(iflr.dstaddr));
818 return sockdriver_copyout(data, 0, &iflr, sizeof(iflr));
820 case SIOCALIFADDR:
821 return ifaddr_dl_add(ifdev, (struct sockaddr_dlx *)&iflr.addr,
822 sizeof(iflr.addr), iflr.flags);
824 case SIOCDLIFADDR:
825 if ((r = ifaddr_dl_find(ifdev,
826 (struct sockaddr_dlx *)&iflr.addr, sizeof(iflr.addr),
827 &num)) != OK)
828 return r;
830 return ifaddr_dl_del(ifdev, num);
832 default:
833 return ENOTTY;
838 * Process an IOCTL request for AF_LINK.
840 static int
841 ifconf_ioctl_dl(unsigned long request, const struct sockdriver_data * data,
842 endpoint_t user_endpt)
845 switch (request) {
846 case SIOCALIFADDR:
847 case SIOCDLIFADDR:
848 if (!util_is_root(user_endpt))
849 return EPERM;
851 /* FALLTHROUGH */
852 case SIOCGLIFADDR:
853 return ifconf_ioctl_dl_lifaddr(request, data);
855 default:
856 return ENOTTY;
861 * Process an IOCTL request. This routine is shared between TCP, UDP, RAW, and
862 * link sockets. The given socket may be used to obtain the target domain:
863 * AF_INET, AF_INET6, or AF_LINK.
866 ifconf_ioctl(struct sock * sock, unsigned long request,
867 const struct sockdriver_data * data, endpoint_t user_endpt)
869 int domain;
871 domain = sockevent_get_domain(sock);
873 switch (request) {
874 case SIOCSIFFLAGS:
875 case SIOCSIFMETRIC:
876 case SIOCSIFMEDIA:
877 case SIOCSIFMTU:
878 case SIOCIFCREATE:
879 case SIOCIFDESTROY:
880 if (!util_is_root(user_endpt))
881 return EPERM;
883 /* FALLTHROUGH */
884 case SIOCGIFFLAGS:
885 case SIOCGIFMETRIC:
886 case SIOCGIFMTU:
887 case SIOCGIFDLT:
888 case SIOCGIFINDEX:
889 return ifconf_ioctl_ifreq(request, data);
891 case SIOCSIFCAP:
892 if (!util_is_root(user_endpt))
893 return EPERM;
895 /* FALLTHROUGH */
896 case SIOCGIFCAP:
897 return ifconf_ioctl_ifcap(request, data);
899 case MINIX_SIOCGIFMEDIA:
900 return ifconf_ioctl_ifmedia(request, data);
902 case MINIX_SIOCIFGCLONERS:
903 return ifconf_ioctl_ifclone(request, data);
905 case SIOCSIFADDRPREF:
906 if (!util_is_root(user_endpt))
907 return EPERM;
909 /* FALLTHROUGH */
910 case SIOCGIFADDRPREF:
911 return ifconf_ioctl_ifaddrpref(request, data);
913 default:
914 switch (domain) {
915 case AF_INET:
916 return ifconf_ioctl_v4(request, data, user_endpt);
918 #ifdef INET6
919 case AF_INET6:
920 return ifconf_ioctl_v6(request, data, user_endpt);
921 #endif /* INET6 */
923 case AF_LINK:
924 return ifconf_ioctl_dl(request, data, user_endpt);
926 default:
927 return ENOTTY;