int if_address(const struct interface *iface, const struct in_addr *address, const struct in_addr *netmask, const struct in_addr *broadcast, int action) { int retval; struct ifaliasreq ifa; union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; memset(&ifa, 0, sizeof(ifa)); strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name)); #define ADDADDR(_var, _addr) { \ _s.sa = &_var; \ _s.sin->sin_family = AF_INET; \ _s.sin->sin_len = sizeof(*_s.sin); \ memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \ } ADDADDR(ifa.ifra_addr, address); ADDADDR(ifa.ifra_mask, netmask); if (action >= 0 && broadcast) { ADDADDR(ifa.ifra_broadaddr, broadcast); } #undef ADDADDR if (action < 0) retval = ifioctl(socket_afnet, SIOCDIFADDR, &ifa, curlwp); else retval = ifioctl(socket_afnet, SIOCAIFADDR, &ifa, curlwp); return retval; }
int init_interface(const char *ifname, struct interface **ifacep) { struct ifnet *ifp; struct ifreq ifr; struct interface *iface = NULL; int error; ifp = ifunit(ifname); if (!ifp) return EXDEV; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if ((error = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0) goto eexit; iface = kmem_zalloc(sizeof(*iface), KM_SLEEP); strlcpy(iface->name, ifname, sizeof(iface->name)); iface->ifp = ifp; iface->flags = ifr.ifr_flags; /* We reserve the 100 range for virtual interfaces, if and when * we can work them out. */ iface->metric = 200 + iface->ifp->if_index; if (getifssid(ifname, iface->ssid) == 0) { iface->wireless = 1; iface->metric += 100; } if (ifioctl(socket_afnet, SIOCGIFMTU, &ifr, curlwp) != 0) goto eexit; /* Ensure that the MTU is big enough for DHCP */ if (ifr.ifr_mtu < MTU_MIN) { ifr.ifr_mtu = MTU_MIN; strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if ((error = ifioctl(socket_afnet, SIOCSIFMTU, &ifr, curlwp)) != 0) goto eexit; } /* 0 is a valid fd, so init to -1 */ iface->raw_fd = -1; iface->udp_fd = -1; iface->arp_fd = -1; eexit: if (error) { kmem_free(iface, sizeof(*iface)); iface = NULL; } *ifacep = iface; return error; }
static int so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t command, void *buffer) { switch (command) { case FIONBIO: if (*(int *)buffer) { iop->flags |= O_NONBLOCK; so->so_state |= SS_NBIO; } else { iop->flags &= ~O_NONBLOCK; so->so_state &= ~SS_NBIO; } return 0; case FIONREAD: *(int *)buffer = so->so_rcv.sb_cc; return 0; } if (IOCGROUP(command) == 'i') return ifioctl (so, command, buffer, NULL); if (IOCGROUP(command) == 'r') return rtioctl (command, buffer, NULL); return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0); }
static int ff_veth_setaddr(struct ff_veth_softc *sc) { struct in_aliasreq req; bzero(&req, sizeof req); strcpy(req.ifra_name, sc->ifp->if_dname); struct sockaddr_in sa; bzero(&sa, sizeof(sa)); sa.sin_len = sizeof(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = sc->ip; bcopy(&sa, &req.ifra_addr, sizeof(sa)); sa.sin_addr.s_addr = sc->netmask; bcopy(&sa, &req.ifra_mask, sizeof(sa)); sa.sin_addr.s_addr = sc->broadcast; bcopy(&sa, &req.ifra_broadaddr, sizeof(sa)); struct socket *so = NULL; socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread); int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread); sofree(so); return ret; }
int nfs_boot_deladdress(struct ifnet *ifp, struct lwp *lwp, uint32_t addr) { struct socket *so; struct ifreq ifr; struct sockaddr_in sin; struct in_addr ia = {.s_addr = addr}; int error; /* * Get a socket to use for various things in here. * After this, use "goto out" to cleanup and return. */ error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL); if (error) { printf("deladdress: socreate, error=%d\n", error); return (error); } memset(&ifr, 0, sizeof(ifr)); memcpy(ifr.ifr_name, ifp->if_xname, IFNAMSIZ); sockaddr_in_init(&sin, &ia, 0); ifreq_setaddr(SIOCDIFADDR, &ifr, sintocsa(&sin)); error = ifioctl(so, SIOCDIFADDR, &ifr, lwp); if (error) { printf("deladdress, error=%d\n", error); goto out; } out: soclose(so); return (error); }
int nfs_boot_ifupdown(struct ifnet *ifp, struct lwp *lwp, int up) { struct socket *so; struct ifreq ireq; int error; memset(&ireq, 0, sizeof(ireq)); memcpy(ireq.ifr_name, ifp->if_xname, IFNAMSIZ); /* * Get a socket to use for various things in here. * After this, use "goto out" to cleanup and return. */ error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL); if (error) { printf("ifupdown: socreate, error=%d\n", error); return (error); } /* * Bring up the interface. (just set the "up" flag) * Get the old interface flags and or IFF_UP into them so * things like media selection flags are not clobbered. */ error = ifioctl(so, SIOCGIFFLAGS, (void *)&ireq, lwp); if (error) { printf("ifupdown: GIFFLAGS, error=%d\n", error); goto out; } if (up) ireq.ifr_flags |= IFF_UP; else ireq.ifr_flags &= ~IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, &ireq, lwp); if (error) { printf("ifupdown: SIFFLAGS, error=%d\n", error); goto out; } if (up) /* give the link some time to get up */ tsleep(nfs_boot_ifupdown, PZERO, "nfsbif", 3 * hz); out: soclose(so); return (error); }
int soo_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p) { struct socket *so = (struct socket *)fp->f_data; switch (cmd) { case FIONBIO: if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; return (0); case FIOASYNC: if (*(int *)data) { so->so_state |= SS_ASYNC; so->so_rcv.sb_flags |= SB_ASYNC; so->so_snd.sb_flags |= SB_ASYNC; } else { so->so_state &= ~SS_ASYNC; so->so_rcv.sb_flags &= ~SB_ASYNC; so->so_snd.sb_flags &= ~SB_ASYNC; } return (0); case FIONREAD: *(int *)data = so->so_rcv.sb_datacc; return (0); case SIOCSPGRP: so->so_pgid = *(int *)data; so->so_siguid = p->p_cred->p_ruid; so->so_sigeuid = p->p_ucred->cr_uid; return (0); case SIOCGPGRP: *(int *)data = so->so_pgid; return (0); case SIOCATMARK: *(int *)data = (so->so_state&SS_RCVATMARK) != 0; return (0); } /* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ if (IOCGROUP(cmd) == 'i') return (ifioctl(so, cmd, data, p)); if (IOCGROUP(cmd) == 'r') return (rtioctl(cmd, data, p)); return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0, p)); }
int nfs_boot_setaddress(struct ifnet *ifp, struct lwp *lwp, uint32_t addr, uint32_t netmask, uint32_t braddr) { struct socket *so; struct ifaliasreq iareq; struct sockaddr_in *sin; int error; /* * Get a socket to use for various things in here. * After this, use "goto out" to cleanup and return. */ error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL); if (error) { printf("setaddress: socreate, error=%d\n", error); return (error); } memset(&iareq, 0, sizeof(iareq)); memcpy(iareq.ifra_name, ifp->if_xname, IFNAMSIZ); /* Set the I/F address */ sin = (struct sockaddr_in *)&iareq.ifra_addr; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; /* Set the netmask */ if (netmask != INADDR_ANY) { sin = (struct sockaddr_in *)&iareq.ifra_mask; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = netmask; } /* else leave subnetmask unspecified (len=0) */ /* Set the broadcast addr. */ if (braddr != INADDR_ANY) { sin = (struct sockaddr_in *)&iareq.ifra_broadaddr; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = braddr; } /* else leave broadcast addr unspecified (len=0) */ error = ifioctl(so, SIOCAIFADDR, (void *)&iareq, lwp); if (error) { printf("setaddress, error=%d\n", error); goto out; } /* give the link some time to get up */ tsleep(nfs_boot_setaddress, PZERO, "nfsbtd", 3 * hz); out: soclose(so); return (error); }
static int uinet_ifconfig_do(struct socket *so, unsigned long what, void *req) { int error; error = ifioctl(so, what, (caddr_t)req, curthread); if (error != 0) printf("ifioctl 0x%08lx failed %d\n", what, error); return (error); }
static int wrapifioctl(struct socket *so, u_long cmd, void *data) { int rv; KERNEL_LOCK(1, NULL); rv = ifioctl(so, cmd, data, curlwp); KERNEL_UNLOCK_ONE(NULL); return rv; }
int do_mtu(const char *ifname, short int mtu) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_mtu = mtu; if (ifioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr, curlwp)) return -1; return ifr.ifr_mtu; }
int carrier_status(struct interface *iface) { int ret; struct ifreq ifr; struct ifmediareq ifmr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); if ((ret = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0) return ret; iface->flags = ifr.ifr_flags; ret = -1; memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name)); if (ifioctl(socket_afnet, SIOCGIFMEDIA, &ifmr, curlwp) == 0 && ifmr.ifm_status & IFM_AVALID) ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0; if (ret != 0) ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0; return ret; }
static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data) { register struct socket *so = (struct socket *)fp->f_data; void *p = 0; switch (cmd) { case FIONBIO: if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; return (0); case FIOASYNC: if (*(int *)data) { so->so_state |= SS_ASYNC; so->so_rcv.sb_flags |= SB_ASYNC; so->so_snd.sb_flags |= SB_ASYNC; } else { so->so_state &= ~SS_ASYNC; so->so_rcv.sb_flags &= ~SB_ASYNC; so->so_snd.sb_flags &= ~SB_ASYNC; } return (0); case FIONREAD: *(int *)data = so->so_rcv.sb_cc; return (0); case SIOCATMARK: *(int *)data = (so->so_state&SS_RCVATMARK) != 0; return (0); } /* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ if (IOCGROUP(cmd) == 'i') return (ifioctl(so, (u_long)cmd, (caddr_t)data, p)); if (IOCGROUP(cmd) == 'r') return (rtioctl((u_long)cmd, (caddr_t)data, p)); return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0)); }
/* * Create a socket and call ifioctl() to configure the interface. * This trickles down to virtif_ioctl(). */ static int configaddr(struct ifnet *ifp, struct ifaliasreq *ia) { struct socket *so; int error; strcpy(ia->ifra_name, ifp->if_xname); error = socreate(ia->ifra_addr.sa_family, &so, SOCK_DGRAM, 0, curlwp, NULL); if (error) return error; error = ifioctl(so, SIOCAIFADDR, ia, curlwp); soclose(so); return error; }
int getifssid(const char *ifname, char *ssid) { struct ifreq ifr; struct ieee80211_nwid nwid; int error; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); memset(&nwid, 0, sizeof(nwid)); ifr.ifr_data = (void *)&nwid; if ((error = ifioctl(socket_afnet, SIOCG80211NWID, &ifr, curlwp)) == 0) { memcpy(ssid, nwid.i_nwid, nwid.i_len); ssid[nwid.i_len] = '\0'; } return error; }
static void dhcp_context_free(struct dhcp_context * context, struct proc * procp) { if (context == NULL) { return; } if (context->so != NULL) { int error; /* disable reception of DHCP packets before address assignment */ context->ifr.ifr_intval = 0; error = ifioctl(context->so, SIOCAUTOADDR, (caddr_t)&context->ifr, procp); if (error) { printf("dhcp: SIOCAUTOADDR failed: %d\n", error); } soclose(context->so); } kfree(context, sizeof(*context)); return; }
__private_extern__ int inet_aifaddr(struct socket * so, const char * name, const struct in_addr * addr, const struct in_addr * mask, const struct in_addr * broadcast) { struct ifaliasreq ifra; bzero(&ifra, sizeof(ifra)); strlcpy(ifra.ifra_name, name, sizeof(ifra.ifra_name)); if (addr) { *((struct sockaddr_in *)&ifra.ifra_addr) = blank_sin; ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr = *addr; } if (mask) { *((struct sockaddr_in *)&ifra.ifra_mask) = blank_sin; ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr = *mask; } if (broadcast) { *((struct sockaddr_in *)&ifra.ifra_broadaddr) = blank_sin; ((struct sockaddr_in *)&ifra.ifra_broadaddr)->sin_addr = *broadcast; } return (ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, current_proc())); }
int libcfs_ipif_enumerate (char ***namesp) { /* Allocate and fill in 'names', returning # interfaces/error */ char **names; int toobig; int nalloc; int nfound; struct socket *so; struct ifreq *ifr; struct ifconf ifc; int rc; int nob; int i; CFS_DECL_FUNNEL_DATA; CFS_NET_IN; rc = socreate(PF_INET, &so, SOCK_STREAM, 0); CFS_NET_EX; if (rc != 0) { CERROR ("Can't create socket: %d\n", rc); return (-rc); } nalloc = 16; /* first guess at max interfaces */ toobig = 0; for (;;) { if (nalloc * sizeof(*ifr) > CFS_PAGE_SIZE) { toobig = 1; nalloc = CFS_PAGE_SIZE/sizeof(*ifr); CWARN("Too many interfaces: only enumerating first %d\n", nalloc); } LIBCFS_ALLOC(ifr, nalloc * sizeof(*ifr)); if (ifr == NULL) { CERROR ("ENOMEM enumerating up to %d interfaces\n", nalloc); rc = -ENOMEM; goto out0; } ifc.ifc_buf = (char *)ifr; ifc.ifc_len = nalloc * sizeof(*ifr); CFS_NET_IN; rc = -ifioctl(so, SIOCGIFCONF, (caddr_t)&ifc, current_proc()); CFS_NET_EX; if (rc < 0) { CERROR ("Error %d enumerating interfaces\n", rc); goto out1; } nfound = ifc.ifc_len/sizeof(*ifr); LASSERT (nfound <= nalloc); if (nfound < nalloc || toobig) break; LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); nalloc *= 2; } if (nfound == 0) goto out1; LIBCFS_ALLOC(names, nfound * sizeof(*names)); if (names == NULL) { rc = -ENOMEM; goto out1; } /* NULL out all names[i] */ memset (names, 0, nfound * sizeof(*names)); for (i = 0; i < nfound; i++) { nob = strnlen (ifr[i].ifr_name, IFNAMSIZ); if (nob == IFNAMSIZ) { /* no space for terminating NULL */ CERROR("interface name %.*s too long (%d max)\n", nob, ifr[i].ifr_name, IFNAMSIZ); rc = -ENAMETOOLONG; goto out2; } LIBCFS_ALLOC(names[i], IFNAMSIZ); if (names[i] == NULL) { rc = -ENOMEM; goto out2; } memcpy(names[i], ifr[i].ifr_name, nob); names[i][nob] = 0; } *namesp = names; rc = nfound; out2: if (rc < 0) libcfs_ipif_free_enumeration(names, nfound); out1: LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); out0: CFS_NET_IN; soclose(so); CFS_NET_EX; return rc; }
/* * Mount a remote root fs via. nfs. This depends on the info in the * nfs_diskless structure that has been filled in properly by some primary * bootstrap. * It goes something like this: * - do enough of "ifconfig" by calling ifioctl() so that the system * can talk to the server * - If nfs_diskless.mygateway is filled in, use that address as * a default gateway. * - build the rootfs mount point and call mountnfs() to do the rest. */ int nfs_mountroot(struct mount *mp) { struct mount *swap_mp; struct nfsv3_diskless *nd = &nfsv3_diskless; struct socket *so; struct vnode *vp; struct thread *td = curthread; /* XXX */ int error, i; u_long l; char buf[128]; #if defined(BOOTP_NFSROOT) && defined(BOOTP) bootpc_init(); /* use bootp to get nfs_diskless filled in */ #endif /* * XXX time must be non-zero when we init the interface or else * the arp code will wedge... */ while (mycpu->gd_time_seconds == 0) tsleep(mycpu, 0, "arpkludge", 10); /* * The boot code may have passed us a diskless structure. */ kprintf("DISKLESS %d\n", nfs_diskless_valid); if (nfs_diskless_valid == 1) nfs_convert_diskless(); /* * NFSv3 is required. */ nd->root_args.flags |= NFSMNT_NFSV3 | NFSMNT_RDIRPLUS; nd->swap_args.flags |= NFSMNT_NFSV3; #define SINP(sockaddr) ((struct sockaddr_in *)(sockaddr)) kprintf("nfs_mountroot: interface %s ip %s", nd->myif.ifra_name, inet_ntoa(SINP(&nd->myif.ifra_addr)->sin_addr)); kprintf(" bcast %s", inet_ntoa(SINP(&nd->myif.ifra_broadaddr)->sin_addr)); kprintf(" mask %s\n", inet_ntoa(SINP(&nd->myif.ifra_mask)->sin_addr)); #undef SINP /* * XXX splnet, so networks will receive... */ crit_enter(); /* * BOOTP does not necessarily have to be compiled into the kernel * for an NFS root to work. If we inherited the network * configuration for PXEBOOT then pxe_setup_nfsdiskless() has figured * out our interface for us and all we need to do is ifconfig the * interface. We only do this if the interface has not already been * ifconfig'd by e.g. BOOTP. */ error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, td); if (error) { panic("nfs_mountroot: socreate(%04x): %d", nd->myif.ifra_addr.sa_family, error); } error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, proc0.p_ucred); if (error) panic("nfs_mountroot: SIOCAIFADDR: %d", error); soclose(so, FNONBLOCK); /* * If the gateway field is filled in, set it as the default route. */ if (nd->mygateway.sin_len != 0) { struct sockaddr_in mask, sin; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); kprintf("nfs_mountroot: gateway %s\n", inet_ntoa(nd->mygateway.sin_addr)); error = rtrequest_global(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, RTF_UP | RTF_GATEWAY); if (error) kprintf("nfs_mountroot: unable to set gateway, error %d, continuing anyway\n", error); } /* * Create the rootfs mount point. */ nd->root_args.fh = nd->root_fh; nd->root_args.fhsize = nd->root_fhsize; l = ntohl(nd->root_saddr.sin_addr.s_addr); ksnprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam); kprintf("NFS_ROOT: %s\n",buf); error = nfs_mountdiskless(buf, "/", MNT_RDONLY, &nd->root_saddr, &nd->root_args, td, &vp, &mp); if (error) { mp->mnt_vfc->vfc_refcount--; crit_exit(); return (error); } swap_mp = NULL; if (nd->swap_nblks) { /* Convert to DEV_BSIZE instead of Kilobyte */ nd->swap_nblks *= 2; /* * Create a fake mount point just for the swap vnode so that the * swap file can be on a different server from the rootfs. */ nd->swap_args.fh = nd->swap_fh; nd->swap_args.fhsize = nd->swap_fhsize; l = ntohl(nd->swap_saddr.sin_addr.s_addr); ksnprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam); kprintf("NFS SWAP: %s\n",buf); error = nfs_mountdiskless(buf, "/swap", 0, &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp); if (error) { crit_exit(); return (error); } vfs_unbusy(swap_mp); VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = nd->swap_nblks * DEV_BSIZE ; /* * Since the swap file is not the root dir of a file system, * hack it to a regular file. */ vclrflags(vp, VROOT); vref(vp); nfs_setvtype(vp, VREG); swaponvp(td, vp, nd->swap_nblks); }
int soo_ioctl(file_t *fp, u_long cmd, void *data) { struct socket *so = fp->f_data; int error = 0; switch (cmd) { case FIONBIO: solock(so); if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; sounlock(so); break; case FIOASYNC: solock(so); if (*(int *)data) { so->so_state |= SS_ASYNC; so->so_rcv.sb_flags |= SB_ASYNC; so->so_snd.sb_flags |= SB_ASYNC; } else { so->so_state &= ~SS_ASYNC; so->so_rcv.sb_flags &= ~SB_ASYNC; so->so_snd.sb_flags &= ~SB_ASYNC; } sounlock(so); break; case FIONREAD: *(int *)data = so->so_rcv.sb_cc; break; case FIONWRITE: *(int *)data = so->so_snd.sb_cc; break; case FIONSPACE: /* * See the comment around sbspace()'s definition * in sys/socketvar.h in face of counts about maximum * to understand the following test. We detect overflow * and return zero. */ solock(so); if ((so->so_snd.sb_hiwat < so->so_snd.sb_cc) || (so->so_snd.sb_mbmax < so->so_snd.sb_mbcnt)) *(int *)data = 0; else *(int *)data = sbspace(&so->so_snd); sounlock(so); break; case SIOCSPGRP: case FIOSETOWN: case TIOCSPGRP: error = fsetown(&so->so_pgid, cmd, data); break; case SIOCGPGRP: case FIOGETOWN: case TIOCGPGRP: error = fgetown(so->so_pgid, cmd, data); break; case SIOCATMARK: *(int *)data = (so->so_state&SS_RCVATMARK) != 0; break; default: /* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ KERNEL_LOCK(1, NULL); if (IOCGROUP(cmd) == 'i') error = ifioctl(so, cmd, data, curlwp); else if (IOCGROUP(cmd) == 'r') error = rtioctl(cmd, data, curlwp); else { error = (*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, NULL, curlwp); } KERNEL_UNLOCK_ONE(NULL); break; } return error; }
int libcfs_ipif_query (char *name, int *up, __u32 *ip, __u32 *mask) { struct socket *so; struct ifreq ifr; int nob; int rc; __u32 val; CFS_DECL_FUNNEL_DATA; CFS_NET_IN; rc = socreate(PF_INET, &so, SOCK_STREAM, 0); CFS_NET_EX; if (rc != 0) { CERROR ("Can't create socket: %d\n", rc); return (-rc); } nob = strnlen(name, IFNAMSIZ); if (nob == IFNAMSIZ) { CERROR("Interface name %s too long\n", name); rc = -EINVAL; goto out; } CLASSERT (sizeof(ifr.ifr_name) >= IFNAMSIZ); strcpy(ifr.ifr_name, name); CFS_NET_IN; rc = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ifr, current_proc()); CFS_NET_EX; if (rc != 0) { CERROR("Can't get flags for interface %s\n", name); goto out; } if ((ifr.ifr_flags & IFF_UP) == 0) { CDEBUG(D_NET, "Interface %s down\n", name); *up = 0; *ip = *mask = 0; goto out; } *up = 1; strcpy(ifr.ifr_name, name); *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin(); CFS_NET_IN; rc = ifioctl(so, SIOCGIFADDR, (caddr_t)&ifr, current_proc()); CFS_NET_EX; if (rc != 0) { CERROR("Can't get IP address for interface %s\n", name); goto out; } val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; *ip = ntohl(val); strcpy(ifr.ifr_name, name); *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin(); CFS_NET_IN; rc = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ifr, current_proc()); CFS_NET_EX; if (rc != 0) { CERROR("Can't get netmask for interface %s\n", name); goto out; } val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; *mask = ntohl(val); out: CFS_NET_IN; soclose(so); CFS_NET_EX; return -rc; }
int bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, struct sockaddr_in *myaddr, struct sockaddr_in *netmask, struct sockaddr_in *gw, struct proc *procp) { int error; struct sockaddr_in oldgw; struct sockaddr_in olddst; struct sockaddr_in oldmask; struct sockaddr_in *sin; /* Remove old default route to 0.0.0.0 */ bzero((caddr_t) &olddst, sizeof(olddst)); olddst.sin_len=sizeof(olddst); olddst.sin_family=AF_INET; olddst.sin_addr.s_addr = INADDR_ANY; bzero((caddr_t) &oldgw, sizeof(oldgw)); oldgw.sin_len=sizeof(oldgw); oldgw.sin_family=AF_INET; oldgw.sin_addr.s_addr = INADDR_ANY; bzero((caddr_t) &oldmask, sizeof(oldmask)); oldmask.sin_len=sizeof(oldmask); oldmask.sin_family=AF_INET; oldmask.sin_addr.s_addr = INADDR_ANY; error = rtrequest(RTM_DELETE, (struct sockaddr *) &olddst, (struct sockaddr *) &oldgw, (struct sockaddr *) &oldmask, (RTF_UP | RTF_STATIC), NULL); if (error) { printf("nfs_boot: del default route, error=%d\n", error); return error; } /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set netmask, error=%s\n", strerror(error)); return error; } /* Broadcast is with host part of IP address all 1's */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set broadcast addr, error=%s\n", strerror(error)); return error; } bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set if addr, error=%s\n", strerror(error)); return error; } /* Add new default route */ error = rtrequest(RTM_ADD, (struct sockaddr *) &olddst, (struct sockaddr *) gw, (struct sockaddr *) &oldmask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); if (error) { printf("bootpc_adjust_interface: add net route, error=%d\n", error); } return error; }
static struct dhcp_context * dhcp_context_create(struct ifnet * ifp, int max_try, struct proc * procp, int * error_p) { struct dhcp_context * context = NULL; struct sockaddr_dl * dl_p; struct in_addr lo_addr; struct in_addr lo_mask; int error; struct sockaddr_in sin; /* get the hardware address from the interface */ dl_p = link_from_ifnet(ifp); if (dl_p == NULL) { printf("dhcp: can't get link address\n"); error = ENXIO; goto failed; } printf("dhcp: h/w addr "); link_print(dl_p); if (dl_p->sdl_type != IFT_ETHER) { printf("dhcp: hardware type %d not supported\n", dl_p->sdl_type); error = ENXIO; goto failed; } context = (struct dhcp_context *)kalloc(sizeof(*context)); if (context == NULL) { printf("dhcp: failed to allocate context\n"); error = ENOMEM; goto failed; } bzero(context, sizeof(*context)); /* get a socket */ error = socreate(AF_INET, &context->so, SOCK_DGRAM, 0); if (error != 0) { printf("dhcp: socreate failed %d\n", error); goto failed; } /* assign 127.0.0.1 to lo0 so that the bind will succeed */ lo_addr.s_addr = htonl(INADDR_LOOPBACK); lo_mask.s_addr = htonl(IN_CLASSA_NET); error = inet_aifaddr(context->so, "lo0", &lo_addr, &lo_mask, NULL); if (error != 0) { printf("dhcp: assigning loopback address failed %d\n", error); } /* enable reception of DHCP packets before an address is assigned */ snprintf(context->ifr.ifr_name, sizeof(context->ifr.ifr_name), "%s%d", ifp->if_name, ifp->if_unit); context->ifr.ifr_intval = 1; error = ifioctl(context->so, SIOCAUTOADDR, (caddr_t)&context->ifr, procp); if (error) { printf("dhcp: SIOCAUTOADDR failed: %d\n", error); goto failed; } dprintf(("dhcp: SIOCAUTOADDR done\n")); error = ifioctl(context->so, SIOCPROTOATTACH, (caddr_t)&context->ifr, procp); if (error) { printf("dhcp: SIOCPROTOATTACH failed: %d\n", error); goto failed; } dprintf(("dhcp: SIOCPROTOATTACH done\n")); /* bind the socket */ sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(IPPORT_BOOTPC); sin.sin_addr.s_addr = INADDR_ANY; error = sobind(context->so, (struct sockaddr *)&sin); if (error) { printf("dhcp: sobind failed, %d\n", error); goto failed; } /* make it non-blocking I/O */ socket_lock(context->so, 1); context->so->so_state |= SS_NBIO; socket_unlock(context->so, 1); /* save passed-in information */ context->max_try = max_try; context->dl_p = dl_p; context->ifp = ifp; /* get a random transaction id */ context->xid = random(); return (context); failed: dhcp_context_free(context, procp); *error_p = error; return (NULL); }
/* * Mount a remote root fs via. nfs. This depends on the info in the * nfs_diskless structure that has been filled in properly by some primary * bootstrap. * It goes something like this: * - do enough of "ifconfig" by calling ifioctl() so that the system * can talk to the server * - If nfs_diskless.mygateway is filled in, use that address as * a default gateway. * - build the rootfs mount point and call mountnfs() to do the rest. * * It is assumed to be safe to read, modify, and write the nfsv3_diskless * structure, as well as other global NFS client variables here, as * nfs_mountroot() will be called once in the boot before any other NFS * client activity occurs. */ int nfs_mountroot(struct mount *mp) { struct thread *td = curthread; struct nfsv3_diskless *nd = &nfsv3_diskless; struct socket *so; struct vnode *vp; struct ifreq ir; int error; u_long l; char buf[128]; char *cp; #if defined(BOOTP_NFSROOT) && defined(BOOTP) bootpc_init(); /* use bootp to get nfs_diskless filled in */ #elif defined(NFS_ROOT) nfs_setup_diskless(); #endif if (nfs_diskless_valid == 0) { return (-1); } if (nfs_diskless_valid == 1) nfs_convert_diskless(); /* * XXX splnet, so networks will receive... */ splnet(); /* * Do enough of ifconfig(8) so that the critical net interface can * talk to the server. */ error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, td->td_ucred, td); if (error) panic("nfs_mountroot: socreate(%04x): %d", nd->myif.ifra_addr.sa_family, error); #if 0 /* XXX Bad idea */ /* * We might not have been told the right interface, so we pass * over the first ten interfaces of the same kind, until we get * one of them configured. */ for (i = strlen(nd->myif.ifra_name) - 1; nd->myif.ifra_name[i] >= '0' && nd->myif.ifra_name[i] <= '9'; nd->myif.ifra_name[i] ++) { error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); if(!error) break; } #endif error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); if (error) panic("nfs_mountroot: SIOCAIFADDR: %d", error); if ((cp = getenv("boot.netif.mtu")) != NULL) { ir.ifr_mtu = strtol(cp, NULL, 10); bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); freeenv(cp); error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); if (error) printf("nfs_mountroot: SIOCSIFMTU: %d", error); } soclose(so); /* * If the gateway field is filled in, set it as the default route. * Note that pxeboot will set a default route of 0 if the route * is not set by the DHCP server. Check also for a value of 0 * to avoid panicking inappropriately in that situation. */ if (nd->mygateway.sin_len != 0 && nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); /* XXX MRT use table 0 for this sort of thing */ CURVNET_SET(TD_TO_VNET(td)); error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); CURVNET_RESTORE(); if (error) panic("nfs_mountroot: RTM_ADD: %d", error); } /* * Create the rootfs mount point. */ nd->root_args.fh = nd->root_fh; nd->root_args.fhsize = nd->root_fhsize; l = ntohl(nd->root_saddr.sin_addr.s_addr); snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); printf("NFS ROOT: %s\n", buf); nd->root_args.hostname = buf; if ((error = nfs_mountdiskless(buf, &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { return (error); } /* * This is not really an nfs issue, but it is much easier to * set hostname here and then let the "/etc/rc.xxx" files * mount the right /var based upon its preset value. */ mtx_lock(&prison0.pr_mtx); strlcpy(prison0.pr_hostname, nd->my_hostnam, sizeof (prison0.pr_hostname)); mtx_unlock(&prison0.pr_mtx); inittodr(ntohl(nd->root_time)); return (0); }
int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, struct proc *procp) { struct sockaddr_in *sin; int error; struct sockaddr_in dst; struct sockaddr_in gw; struct sockaddr_in mask; /* * Bring up the interface. * * Get the old interface flags and or IFF_UP into them; if * IFF_UP set blindly, interface selection can be clobbered. */ error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: GIFFLAGS, error=%s\n", strerror(error)); return error; } ireq->ifr_flags |= IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: SIFFLAGS, error=%s\n", strerror(error)); return error; } /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ /* addr is 0.0.0.0 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); /* * Ignore a File already exists (EEXIST) error code. This means a * route for the address is already present and is returned on * a second pass to here. */ if (error && (error != EEXIST)) { printf("bootpc_fakeup_interface: set if addr, error=%s\n", strerror(error)); return error; } /* netmask is 0.0.0.0 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: set if netmask, error=%s\n", strerror(error)); return error; } /* Broadcast is 255.255.255.255 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_BROADCAST; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: set broadcast addr, error=%s\n", strerror(error)); return error; } /* Add default route to 0.0.0.0 so we can send data */ bzero((caddr_t) &dst, sizeof(dst)); dst.sin_len=sizeof(dst); dst.sin_family=AF_INET; dst.sin_addr.s_addr = htonl(0); bzero((caddr_t) &gw, sizeof(gw)); gw.sin_len=sizeof(gw); gw.sin_family=AF_INET; gw.sin_addr.s_addr = htonl(0x0); bzero((caddr_t) &mask, sizeof(mask)); mask.sin_len=sizeof(mask); mask.sin_family=AF_INET; mask.sin_addr.s_addr = htonl(0); error = rtrequest(RTM_ADD, (struct sockaddr *) &dst, (struct sockaddr *) &gw, (struct sockaddr *) &mask, RTF_UP | RTF_STATIC , NULL); if (error && error != EEXIST) printf("bootpc_fakeup_interface: add default route, error=%s\n", strerror(error)); return error; }
static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, struct bootpc_globalcontext *gctx, struct thread *td) { int error; struct sockaddr_in defdst; struct sockaddr_in defmask; struct sockaddr_in *sin; struct ifreq *ireq; struct socket *so; struct sockaddr_in *myaddr; struct sockaddr_in *netmask; struct sockaddr_in *gw; ireq = &ifctx->ireq; so = ifctx->so; myaddr = &ifctx->myaddr; netmask = &ifctx->netmask; gw = &ifctx->gw; if (bootpc_ifctx_isresolved(ifctx) == 0) { /* Shutdown interfaces where BOOTP failed */ printf("Shutdown interface %s\n", ifctx->ireq.ifr_name); error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td); if (error != 0) panic("bootpc_adjust_interface: " "SIOCGIFFLAGS, error=%d", error); ireq->ifr_flags &= ~IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td); if (error != 0) panic("bootpc_adjust_interface: " "SIOCSIFFLAGS, error=%d", error); sin = (struct sockaddr_in *) &ireq->ifr_addr; clear_sinaddr(sin); error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td); if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces)) panic("bootpc_adjust_interface: " "SIOCDIFADDR, error=%d", error); return 0; } printf("Adjusted interface %s\n", ifctx->ireq.ifr_name); /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask)); error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td); if (error != 0) panic("bootpc_adjust_interface: " "set if netmask, error=%d", error); /* Broadcast is with host part of IP address all 1's */ sin = (struct sockaddr_in *) &ireq->ifr_addr; clear_sinaddr(sin); sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td); if (error != 0) panic("bootpc_adjust_interface: " "set if broadcast addr, error=%d", error); bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr)); error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td); if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces)) panic("bootpc_adjust_interface: " "set if addr, error=%d", error); /* Add new default route */ if (ifctx->gotgw != 0 || gctx->gotgw == 0) { clear_sinaddr(&defdst); clear_sinaddr(&defmask); /* XXX MRT just table 0 */ error = rtrequest_fib(RTM_ADD, (struct sockaddr *) &defdst, (struct sockaddr *) gw, (struct sockaddr *) &defmask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, 0); if (error != 0) { printf("bootpc_adjust_interface: " "add net route, error=%d\n", error); return error; } } return 0; }
static int soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { struct socket *so = fp->f_data; int error = 0; switch (cmd) { case FIONBIO: SOCK_LOCK(so); if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; SOCK_UNLOCK(so); break; case FIOASYNC: /* * XXXRW: This code separately acquires SOCK_LOCK(so) and * SOCKBUF_LOCK(&so->so_rcv) even though they are the same * mutex to avoid introducing the assumption that they are * the same. */ if (*(int *)data) { SOCK_LOCK(so); so->so_state |= SS_ASYNC; SOCK_UNLOCK(so); SOCKBUF_LOCK(&so->so_rcv); so->so_rcv.sb_flags |= SB_ASYNC; SOCKBUF_UNLOCK(&so->so_rcv); SOCKBUF_LOCK(&so->so_snd); so->so_snd.sb_flags |= SB_ASYNC; SOCKBUF_UNLOCK(&so->so_snd); } else { SOCK_LOCK(so); so->so_state &= ~SS_ASYNC; SOCK_UNLOCK(so); SOCKBUF_LOCK(&so->so_rcv); so->so_rcv.sb_flags &= ~SB_ASYNC; SOCKBUF_UNLOCK(&so->so_rcv); SOCKBUF_LOCK(&so->so_snd); so->so_snd.sb_flags &= ~SB_ASYNC; SOCKBUF_UNLOCK(&so->so_snd); } break; case FIONREAD: /* Unlocked read. */ *(int *)data = sbavail(&so->so_rcv); break; case FIONWRITE: /* Unlocked read. */ *(int *)data = sbavail(&so->so_snd); break; case FIONSPACE: /* Unlocked read. */ if ((so->so_snd.sb_hiwat < sbused(&so->so_snd)) || (so->so_snd.sb_mbmax < so->so_snd.sb_mbcnt)) *(int *)data = 0; else *(int *)data = sbspace(&so->so_snd); break; case FIOSETOWN: error = fsetown(*(int *)data, &so->so_sigio); break; case FIOGETOWN: *(int *)data = fgetown(&so->so_sigio); break; case SIOCSPGRP: error = fsetown(-(*(int *)data), &so->so_sigio); break; case SIOCGPGRP: *(int *)data = -fgetown(&so->so_sigio); break; case SIOCATMARK: /* Unlocked read. */ *(int *)data = (so->so_rcv.sb_state & SBS_RCVATMARK) != 0; break; default: /* * Interface/routing/protocol specific ioctls: interface and * routing ioctls should have a different entry since a * socket is unnecessary. */ if (IOCGROUP(cmd) == 'i') error = ifioctl(so, cmd, data, td); else if (IOCGROUP(cmd) == 'r') { CURVNET_SET(so->so_vnet); error = rtioctl_fib(cmd, data, so->so_fibnum); CURVNET_RESTORE(); } else { CURVNET_SET(so->so_vnet); error = ((*so->so_proto->pr_usrreqs->pru_control) (so, cmd, data, 0, td)); CURVNET_RESTORE(); } break; } return (error); }
/* * MPSAFE */ int soo_ioctl(struct file *fp, u_long cmd, caddr_t data, struct ucred *cred, struct sysmsg *msg) { struct socket *so; int error; so = (struct socket *)fp->f_data; switch (cmd) { case FIOASYNC: if (*(int *)data) { sosetstate(so, SS_ASYNC); atomic_set_int(&so->so_rcv.ssb_flags, SSB_ASYNC); atomic_set_int(&so->so_snd.ssb_flags, SSB_ASYNC); } else { soclrstate(so, SS_ASYNC); atomic_clear_int(&so->so_rcv.ssb_flags, SSB_ASYNC); atomic_clear_int(&so->so_snd.ssb_flags, SSB_ASYNC); } error = 0; break; case FIONREAD: *(int *)data = so->so_rcv.ssb_cc; error = 0; break; case FIOSETOWN: error = fsetown(*(int *)data, &so->so_sigio); break; case FIOGETOWN: *(int *)data = fgetown(&so->so_sigio); error = 0; break; case SIOCSPGRP: error = fsetown(-(*(int *)data), &so->so_sigio); break; case SIOCGPGRP: *(int *)data = -fgetown(&so->so_sigio); error = 0; break; case SIOCATMARK: *(int *)data = (so->so_state&SS_RCVATMARK) != 0; error = 0; break; default: /* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ if (IOCGROUP(cmd) == 'i') { error = ifioctl(so, cmd, data, cred); } else if (IOCGROUP(cmd) == 'r') { error = rtioctl(cmd, data, cred); } else { error = so_pru_control_direct(so, cmd, data, NULL); } break; } return (error); }
static int bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td) { struct socket *so; struct sockaddr_in *sin, dst; struct uio auio; struct sockopt sopt; struct iovec aio; int error, on, rcvflg, timo, len; time_t atimo; time_t rtimo; struct timeval tv; struct bootpc_ifcontext *ifctx; int outstanding; int gotrootpath; int retry; const char *s; /* * Create socket and set its recieve timeout. */ error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td); if (error != 0) goto out0; tv.tv_sec = 1; tv.tv_usec = 0; bzero(&sopt, sizeof(sopt)); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_name = SO_RCVTIMEO; sopt.sopt_val = &tv; sopt.sopt_valsize = sizeof tv; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Enable broadcast. */ on = 1; sopt.sopt_name = SO_BROADCAST; sopt.sopt_val = &on; sopt.sopt_valsize = sizeof on; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Disable routing. */ on = 1; sopt.sopt_name = SO_DONTROUTE; sopt.sopt_val = &on; sopt.sopt_valsize = sizeof on; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Bind the local endpoint to a bootp client port. */ sin = &dst; clear_sinaddr(sin); sin->sin_port = htons(IPPORT_BOOTPC); error = sobind(so, (struct sockaddr *)sin, td); if (error != 0) { printf("bind failed\n"); goto out; } /* * Setup socket address for the server. */ sin = &dst; clear_sinaddr(sin); sin->sin_addr.s_addr = INADDR_BROADCAST; sin->sin_port = htons(IPPORT_BOOTPS); /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ timo = 0; rtimo = 0; for (;;) { outstanding = 0; gotrootpath = 0; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0 && bootpc_tag(&gctx->tmptag, &ifctx->reply, ifctx->replylen, TAG_ROOT) != NULL) gotrootpath = 1; } for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { ifctx->outstanding = 0; if (bootpc_ifctx_isresolved(ifctx) != 0 && gotrootpath != 0) { continue; } if (bootpc_ifctx_isfailed(ifctx) != 0) continue; outstanding++; ifctx->outstanding = 1; /* Proceed to next step in DHCP negotiation */ if ((ifctx->state == IF_DHCP_OFFERED && ifctx->dhcpquerytype != DHCP_REQUEST) || (ifctx->state == IF_DHCP_UNRESOLVED && ifctx->dhcpquerytype != DHCP_DISCOVER) || (ifctx->state == IF_BOOTP_UNRESOLVED && ifctx->dhcpquerytype != DHCP_NOMSG)) { ifctx->sentmsg = 0; bootpc_compose_query(ifctx, gctx, td); } /* Send BOOTP request (or re-send). */ if (ifctx->sentmsg == 0) { switch(ifctx->dhcpquerytype) { case DHCP_DISCOVER: s = "DHCP Discover"; break; case DHCP_REQUEST: s = "DHCP Request"; break; case DHCP_NOMSG: default: s = "BOOTP Query"; break; } printf("Sending %s packet from " "interface %s (%*D)\n", s, ifctx->ireq.ifr_name, ifctx->sdl->sdl_alen, (unsigned char *) LLADDR(ifctx->sdl), ":"); ifctx->sentmsg = 1; } aio.iov_base = (caddr_t) &ifctx->call; aio.iov_len = sizeof(ifctx->call); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_offset = 0; auio.uio_resid = sizeof(ifctx->call); auio.uio_td = td; /* Set netmask to 0.0.0.0 */ sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; clear_sinaddr(sin); error = ifioctl(ifctx->so, SIOCSIFNETMASK, (caddr_t) &ifctx->ireq, td); if (error != 0) panic("bootpc_call:" "set if netmask, error=%d", error); error = sosend(so, (struct sockaddr *) &dst, &auio, NULL, NULL, 0, td); if (error != 0) { printf("bootpc_call: sosend: %d state %08x\n", error, (int) so->so_state); } /* XXX: Is this needed ? */ pause("bootpw", hz/10); /* Set netmask to 255.0.0.0 */ sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; clear_sinaddr(sin); sin->sin_addr.s_addr = htonl(0xff000000u); error = ifioctl(ifctx->so, SIOCSIFNETMASK, (caddr_t) &ifctx->ireq, td); if (error != 0) panic("bootpc_call:" "set if netmask, error=%d", error); } if (outstanding == 0 && (rtimo == 0 || time_second >= rtimo)) { error = 0; goto gotreply; } /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else { printf("DHCP/BOOTP timeout for server "); print_sin_addr(&dst); printf("\n"); } /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ atimo = timo + time_second; while (time_second < atimo) { aio.iov_base = (caddr_t) &gctx->reply; aio.iov_len = sizeof(gctx->reply); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_offset = 0; auio.uio_resid = sizeof(gctx->reply); auio.uio_td = td; rcvflg = 0; error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); gctx->secs = time_second - gctx->starttime; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0 || bootpc_ifctx_isfailed(ifctx) != 0) continue; ifctx->call.secs = htons(gctx->secs); } if (error == EWOULDBLOCK) continue; if (error != 0) goto out; len = sizeof(gctx->reply) - auio.uio_resid; /* Do we have the required number of bytes ? */ if (len < BOOTP_MIN_LEN) continue; gctx->replylen = len; /* Is it a reply? */ if (gctx->reply.op != BOOTP_REPLY) continue; /* Is this an answer to our query */ for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (gctx->reply.xid != ifctx->call.xid) continue; /* Same HW address size ? */ if (gctx->reply.hlen != ifctx->call.hlen) continue; /* Correct HW address ? */ if (bcmp(gctx->reply.chaddr, ifctx->call.chaddr, ifctx->call.hlen) != 0) continue; break; } if (ifctx != NULL) { s = bootpc_tag(&gctx->tmptag, &gctx->reply, gctx->replylen, TAG_DHCP_MSGTYPE); if (s != NULL) { switch (*s) { case DHCP_OFFER: s = "DHCP Offer"; break; case DHCP_ACK: s = "DHCP Ack"; break; default: s = "DHCP (unexpected)"; break; } } else s = "BOOTP Reply"; printf("Received %s packet" " on %s from ", s, ifctx->ireq.ifr_name); print_in_addr(gctx->reply.siaddr); if (gctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { printf(" via "); print_in_addr(gctx->reply.giaddr); } if (bootpc_received(gctx, ifctx) != 0) { printf(" (accepted)"); if (ifctx->outstanding) { ifctx->outstanding = 0; outstanding--; } /* Network settle delay */ if (outstanding == 0) atimo = time_second + BOOTP_SETTLE_DELAY; } else printf(" (ignored)"); if (ifctx->gotrootpath) { gotrootpath = 1; rtimo = time_second + BOOTP_SETTLE_DELAY; printf(" (got root path)"); } else printf(" (no root path)"); printf("\n"); } } /* while secs */ #ifdef BOOTP_TIMEOUT if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) break; #endif /* Force a retry if halfway in DHCP negotiation */ retry = 0; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (ifctx->state == IF_DHCP_OFFERED) { if (ifctx->dhcpquerytype == DHCP_DISCOVER) retry = 1; else ifctx->state = IF_DHCP_UNRESOLVED; } } if (retry != 0) continue; if (gotrootpath != 0) { gctx->gotrootpath = gotrootpath; if (rtimo != 0 && time_second >= rtimo) break; } } /* forever send/receive */ /* * XXX: These are errors of varying seriousness being silently * ignored */ for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) == 0) { printf("%s timeout for interface %s\n", ifctx->dhcpquerytype != DHCP_NOMSG ? "DHCP" : "BOOTP", ifctx->ireq.ifr_name); } } if (gctx->gotrootpath != 0) { #if 0 printf("Got a root path, ignoring remaining timeout\n"); #endif error = 0; goto out; } #ifndef BOOTP_NFSROOT for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0) { error = 0; goto out; } } #endif error = ETIMEDOUT; goto out; gotreply: out: soclose(so); out0: return error; }
static int bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct bootpc_globalcontext *gctx, struct thread *td) { struct sockaddr_in *sin; int error; struct ifreq *ireq; struct socket *so; struct ifaddr *ifa; struct sockaddr_dl *sdl; error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td->td_ucred, td); if (error != 0) panic("nfs_boot: socreate, error=%d", error); ireq = &ifctx->ireq; so = ifctx->so; /* * Bring up the interface. * * Get the old interface flags and or IFF_UP into them; if * IFF_UP set blindly, interface selection can be clobbered. */ error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td); if (error != 0) panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); ireq->ifr_flags |= IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td); if (error != 0) panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ /* addr is 0.0.0.0 */ sin = (struct sockaddr_in *) &ireq->ifr_addr; clear_sinaddr(sin); error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td); if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces)) panic("bootpc_fakeup_interface: " "set if addr, error=%d", error); /* netmask is 255.0.0.0 */ sin = (struct sockaddr_in *) &ireq->ifr_addr; clear_sinaddr(sin); sin->sin_addr.s_addr = htonl(0xff000000u); error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td); if (error != 0) panic("bootpc_fakeup_interface: set if netmask, error=%d", error); /* Broadcast is 255.255.255.255 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; clear_sinaddr(sin); clear_sinaddr(&ifctx->broadcast); sin->sin_addr.s_addr = htonl(INADDR_BROADCAST); ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td); if (error != 0) panic("bootpc_fakeup_interface: " "set if broadcast addr, error=%d", error); /* Get HW address */ sdl = NULL; TAILQ_FOREACH(ifa, &ifctx->ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)ifa->ifa_addr; if (sdl->sdl_type == IFT_ETHER) break; } if (sdl == NULL) panic("bootpc: Unable to find HW address for %s", ifctx->ireq.ifr_name); ifctx->sdl = sdl; return error; }