FreeBSD/sys/dev/e1000/if_igb.c
/*********************************************************************
 *  Ioctl entry point
 *
 *  igb_ioctl is called when the user wants to configure the
 *  interface.
 *
 *  return 0 on success, positive on failure
 **********************************************************************/
Ioctl entry point
igb_ioctl is called when the user wants to configure the
interface.

return 0 on success, positive on failure
Ioctl entry point igb_ioctl is called when the user wants to configure the interface . return 0 on success positive on failure
static int
igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
	struct adapter	*adapter = ifp->if_softc;
	struct ifreq	*ifr = (struct ifreq *)data;
#if defined(INET) || defined(INET6)
	struct ifaddr	*ifa = (struct ifaddr *)data;
#endif
	bool		avoid_reset = FALSE;
	int		error = 0;
	if (adapter->in_detach)
		return (error);
	switch (command) {
	case SIOCSIFADDR:
#ifdef INET
		if (ifa->ifa_addr->sa_family == AF_INET)
			avoid_reset = TRUE;
#endif
#ifdef INET6
		if (ifa->ifa_addr->sa_family == AF_INET6)
			avoid_reset = TRUE;
#endif
		if (avoid_reset) {
			ifp->if_flags |= IFF_UP;
			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
				igb_init(adapter);
#ifdef INET
			if (!(ifp->if_flags & IFF_NOARP))
				arp_ifinit(ifp, ifa);
#endif
		} else
			error = ether_ioctl(ifp, command, data);
		break;
	case SIOCSIFMTU:
	    {
		int max_frame_size;
		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
		IGB_CORE_LOCK(adapter);
		max_frame_size = 9234;
		if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN -
		    ETHER_CRC_LEN) {
			IGB_CORE_UNLOCK(adapter);
			error = EINVAL;
			break;
		}
		ifp->if_mtu = ifr->ifr_mtu;
		adapter->max_frame_size =
		    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
			igb_init_locked(adapter);
		IGB_CORE_UNLOCK(adapter);
		break;
	    }
	case SIOCSIFFLAGS:
		IOCTL_DEBUGOUT("ioctl rcv'd:\
		    SIOCSIFFLAGS (Set Interface Flags)");
		IGB_CORE_LOCK(adapter);
		if (ifp->if_flags & IFF_UP) {
			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
				if ((ifp->if_flags ^ adapter->if_flags) &
				    (IFF_PROMISC | IFF_ALLMULTI)) {
					igb_disable_promisc(adapter);
					igb_set_promisc(adapter);
				}
			} else
				igb_init_locked(adapter);
		} else
			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
				igb_stop(adapter);
		adapter->if_flags = ifp->if_flags;
		IGB_CORE_UNLOCK(adapter);
		break;
	case SIOCADDMULTI:
	case SIOCDELMULTI:
		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
			IGB_CORE_LOCK(adapter);
			igb_disable_intr(adapter);
			igb_set_multi(adapter);
#ifdef DEVICE_POLLING
			if (!(ifp->if_capenable & IFCAP_POLLING))
#endif
				igb_enable_intr(adapter);
			IGB_CORE_UNLOCK(adapter);
		}
		break;
	case SIOCSIFMEDIA:
		IGB_CORE_LOCK(adapter);
		if (e1000_check_reset_block(&adapter->hw)) {
			IGB_CORE_UNLOCK(adapter);
			device_printf(adapter->dev, "Media change is"
			    " blocked due to SOL/IDER session.\n");
			break;
		}
		IGB_CORE_UNLOCK(adapter);
	case SIOCGIFMEDIA:
		IOCTL_DEBUGOUT("ioctl rcv'd: \
		    SIOCxIFMEDIA (Get/Set Interface Media)");
		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
		break;
	case SIOCSIFCAP:
	    {
		int mask, reinit;
		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
		reinit = 0;
		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
#ifdef DEVICE_POLLING
		if (mask & IFCAP_POLLING) {
			if (ifr->ifr_reqcap & IFCAP_POLLING) {
				error = ether_poll_register(igb_poll, ifp);
				if (error)
					return (error);
				IGB_CORE_LOCK(adapter);
				igb_disable_intr(adapter);
				ifp->if_capenable |= IFCAP_POLLING;
				IGB_CORE_UNLOCK(adapter);
			} else {
				error = ether_poll_deregister(ifp);
				IGB_CORE_LOCK(adapter);
				igb_enable_intr(adapter);
				ifp->if_capenable &= ~IFCAP_POLLING;
				IGB_CORE_UNLOCK(adapter);
			}
		}
#endif
#if __FreeBSD_version >= 1000000
		if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
			ifp->if_capenable ^= IFCAP_RXCSUM;
			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
			reinit = 1;
		}
		if (mask & IFCAP_TXCSUM) {
			ifp->if_capenable ^= IFCAP_TXCSUM;
			reinit = 1;
		}
		if (mask & IFCAP_TXCSUM_IPV6) {
			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
			reinit = 1;
		}
#else
		if (mask & IFCAP_HWCSUM) {
			ifp->if_capenable ^= IFCAP_HWCSUM;
			reinit = 1;
		}
#endif
		if (mask & IFCAP_TSO4) {
			ifp->if_capenable ^= IFCAP_TSO4;
			reinit = 1;
		}
		if (mask & IFCAP_TSO6) {
			ifp->if_capenable ^= IFCAP_TSO6;
			reinit = 1;
		}
		if (mask & IFCAP_VLAN_HWTAGGING) {
			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
			reinit = 1;
		}
		if (mask & IFCAP_VLAN_HWFILTER) {
			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
			reinit = 1;
		}
		if (mask & IFCAP_VLAN_HWTSO) {
			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
			reinit = 1;
		}
		if (mask & IFCAP_LRO) {
			ifp->if_capenable ^= IFCAP_LRO;
			reinit = 1;
		}
		if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING))
			igb_init(adapter);
		VLAN_CAPABILITIES(ifp);
		break;
	    }
	default:
		error = ether_ioctl(ifp, command, data);
		break;
	}
	return (error);
}
static int igb_ioctl ( struct ifnet * ifp , u_long command , caddr_t data ) { struct adapter * adapter = ifp -> if_softc ; struct ifreq * ifr = ( struct ifreq * ) data ; #if defined ( INET ) || defined ( INET6 ) struct ifaddr * ifa = ( struct ifaddr * ) data ; #endif bool avoid_reset = FALSE ; int error = 0 ; if ( adapter -> in_detach ) return ( error ) ; switch ( command ) { case SIOCSIFADDR : #ifdef INET if ( ifa -> ifa_addr -> sa_family == AF_INET ) avoid_reset = TRUE ; #endif #ifdef INET6 if ( ifa -> ifa_addr -> sa_family == AF_INET6 ) avoid_reset = TRUE ; #endif if ( avoid_reset ) { ifp -> if_flags |= IFF_UP ; if ( ! ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) ) igb_init ( adapter ) ; #ifdef INET if ( ! ( ifp -> if_flags & IFF_NOARP ) ) arp_ifinit ( ifp , ifa ) ; #endif } else error = ether_ioctl ( ifp , command , data ) ; break ; case SIOCSIFMTU : { int max_frame_size ; IOCTL_DEBUGOUT ( " " ) ; IGB_CORE_LOCK ( adapter ) ; max_frame_size = 9234 ; if ( ifr -> ifr_mtu > max_frame_size - ETHER_HDR_LEN - ETHER_CRC_LEN ) { IGB_CORE_UNLOCK ( adapter ) ; error = EINVAL ; break ; } ifp -> if_mtu = ifr -> ifr_mtu ; adapter -> max_frame_size = ifp -> if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN ; if ( ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) ) igb_init_locked ( adapter ) ; IGB_CORE_UNLOCK ( adapter ) ; break ; } case SIOCSIFFLAGS : IOCTL_DEBUGOUT ( " \
 " ) ; IGB_CORE_LOCK ( adapter ) ; if ( ifp -> if_flags & IFF_UP ) { if ( ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) ) { if ( ( ifp -> if_flags ^ adapter -> if_flags ) & ( IFF_PROMISC | IFF_ALLMULTI ) ) { igb_disable_promisc ( adapter ) ; igb_set_promisc ( adapter ) ; } } else igb_init_locked ( adapter ) ; } else if ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) igb_stop ( adapter ) ; adapter -> if_flags = ifp -> if_flags ; IGB_CORE_UNLOCK ( adapter ) ; break ; case SIOCADDMULTI : case SIOCDELMULTI : IOCTL_DEBUGOUT ( " " ) ; if ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) { IGB_CORE_LOCK ( adapter ) ; igb_disable_intr ( adapter ) ; igb_set_multi ( adapter ) ; #ifdef DEVICE_POLLING if ( ! ( ifp -> if_capenable & IFCAP_POLLING ) ) #endif igb_enable_intr ( adapter ) ; IGB_CORE_UNLOCK ( adapter ) ; } break ; case SIOCSIFMEDIA : IGB_CORE_LOCK ( adapter ) ; if ( e1000_check_reset_block ( & adapter -> hw ) ) { IGB_CORE_UNLOCK ( adapter ) ; device_printf ( adapter -> dev , " " " \n " ) ; break ; } IGB_CORE_UNLOCK ( adapter ) ; case SIOCGIFMEDIA : IOCTL_DEBUGOUT ( " \
 " ) ; error = ifmedia_ioctl ( ifp , ifr , & adapter -> media , command ) ; break ; case SIOCSIFCAP : { int mask , reinit ; IOCTL_DEBUGOUT ( " " ) ; reinit = 0 ; mask = ifr -> ifr_reqcap ^ ifp -> if_capenable ; #ifdef DEVICE_POLLING if ( mask & IFCAP_POLLING ) { if ( ifr -> ifr_reqcap & IFCAP_POLLING ) { error = ether_poll_register ( igb_poll , ifp ) ; if ( error ) return ( error ) ; IGB_CORE_LOCK ( adapter ) ; igb_disable_intr ( adapter ) ; ifp -> if_capenable |= IFCAP_POLLING ; IGB_CORE_UNLOCK ( adapter ) ; } else { error = ether_poll_deregister ( ifp ) ; IGB_CORE_LOCK ( adapter ) ; igb_enable_intr ( adapter ) ; ifp -> if_capenable &= ~ IFCAP_POLLING ; IGB_CORE_UNLOCK ( adapter ) ; } } #endif #if __FreeBSD_version >= 1000000 if ( mask & ( IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 ) ) { ifp -> if_capenable ^= IFCAP_RXCSUM ; ifp -> if_capenable ^= IFCAP_RXCSUM_IPV6 ; reinit = 1 ; } if ( mask & IFCAP_TXCSUM ) { ifp -> if_capenable ^= IFCAP_TXCSUM ; reinit = 1 ; } if ( mask & IFCAP_TXCSUM_IPV6 ) { ifp -> if_capenable ^= IFCAP_TXCSUM_IPV6 ; reinit = 1 ; } #else if ( mask & IFCAP_HWCSUM ) { ifp -> if_capenable ^= IFCAP_HWCSUM ; reinit = 1 ; } #endif if ( mask & IFCAP_TSO4 ) { ifp -> if_capenable ^= IFCAP_TSO4 ; reinit = 1 ; } if ( mask & IFCAP_TSO6 ) { ifp -> if_capenable ^= IFCAP_TSO6 ; reinit = 1 ; } if ( mask & IFCAP_VLAN_HWTAGGING ) { ifp -> if_capenable ^= IFCAP_VLAN_HWTAGGING ; reinit = 1 ; } if ( mask & IFCAP_VLAN_HWFILTER ) { ifp -> if_capenable ^= IFCAP_VLAN_HWFILTER ; reinit = 1 ; } if ( mask & IFCAP_VLAN_HWTSO ) { ifp -> if_capenable ^= IFCAP_VLAN_HWTSO ; reinit = 1 ; } if ( mask & IFCAP_LRO ) { ifp -> if_capenable ^= IFCAP_LRO ; reinit = 1 ; } if ( reinit && ( ifp -> if_drv_flags & IFF_DRV_RUNNING ) ) igb_init ( adapter ) ; VLAN_CAPABILITIES ( ifp ) ; break ; } default : error = ether_ioctl ( ifp , command , data ) ; break ; } return ( error ) ; }
Ioctl entry point
  igb_ioctl is called when the user wants to configure the
  interface.
Ioctl entry point igb_ioctl is called when the user wants to configure the interface .
/*
		** Calling init results in link renegotiation,
		** so we avoid doing it when possible.
		*/ /* Check SOL/IDER usage */ /* Enable interrupt even in error case */ /* HW cannot turn these on/off separately */