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

return 0 on success, positive on failure
Ioctl entry point em_ioctl is called when the user wants to configure the interface . return 0 on success positive on failure
static int
lem_ioctl(if_t ifp, u_long command, caddr_t data)
{
	struct adapter	*adapter = if_getsoftc(ifp);
	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) {
			if_setflagbits(ifp, IFF_UP, 0);
			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
				lem_init(adapter);
#ifdef INET
			if (!(if_getflags(ifp) & 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)");
		EM_CORE_LOCK(adapter);
		switch (adapter->hw.mac.type) {
		case e1000_82542:
			max_frame_size = ETHER_MAX_LEN;
			break;
		default:
			max_frame_size = MAX_JUMBO_FRAME_SIZE;
		}
		if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN -
		    ETHER_CRC_LEN) {
			EM_CORE_UNLOCK(adapter);
			error = EINVAL;
			break;
		}
		if_setmtu(ifp, ifr->ifr_mtu);
		adapter->max_frame_size =
		    if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
		if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING))
			lem_init_locked(adapter);
		EM_CORE_UNLOCK(adapter);
		break;
	    }
	case SIOCSIFFLAGS:
		IOCTL_DEBUGOUT("ioctl rcv'd:\
		    SIOCSIFFLAGS (Set Interface Flags)");
		EM_CORE_LOCK(adapter);
		if (if_getflags(ifp) & IFF_UP) {
			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
				if ((if_getflags(ifp) ^ adapter->if_flags) &
				    (IFF_PROMISC | IFF_ALLMULTI)) {
					lem_disable_promisc(adapter);
					lem_set_promisc(adapter);
				}
			} else
				lem_init_locked(adapter);
		} else
			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
				EM_TX_LOCK(adapter);
				lem_stop(adapter);
				EM_TX_UNLOCK(adapter);
			}
		adapter->if_flags = if_getflags(ifp);
		EM_CORE_UNLOCK(adapter);
		break;
	case SIOCADDMULTI:
	case SIOCDELMULTI:
		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
			EM_CORE_LOCK(adapter);
			lem_disable_intr(adapter);
			lem_set_multi(adapter);
			if (adapter->hw.mac.type == e1000_82542 && 
	    		    adapter->hw.revision_id == E1000_REVISION_2) {
				lem_initialize_receive_unit(adapter);
			}
#ifdef DEVICE_POLLING
			if (!(if_getcapenable(ifp) & IFCAP_POLLING))
#endif
				lem_enable_intr(adapter);
			EM_CORE_UNLOCK(adapter);
		}
		break;
	case SIOCSIFMEDIA:
		EM_CORE_LOCK(adapter);
		if (e1000_check_reset_block(&adapter->hw)) {
			EM_CORE_UNLOCK(adapter);
			device_printf(adapter->dev, "Media change is"
			    " blocked due to SOL/IDER session.\n");
			break;
		}
		EM_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 ^ if_getcapenable(ifp);
#ifdef DEVICE_POLLING
		if (mask & IFCAP_POLLING) {
			if (ifr->ifr_reqcap & IFCAP_POLLING) {
				error = ether_poll_register(lem_poll, ifp);
				if (error)
					return (error);
				EM_CORE_LOCK(adapter);
				lem_disable_intr(adapter);
				if_setcapenablebit(ifp, IFCAP_POLLING, 0);
				EM_CORE_UNLOCK(adapter);
			} else {
				error = ether_poll_deregister(ifp);
				EM_CORE_LOCK(adapter);
				lem_enable_intr(adapter);
				if_setcapenablebit(ifp, 0, IFCAP_POLLING);
				EM_CORE_UNLOCK(adapter);
			}
		}
#endif
		if (mask & IFCAP_HWCSUM) {
			if_togglecapenable(ifp, IFCAP_HWCSUM);
			reinit = 1;
		}
		if (mask & IFCAP_VLAN_HWTAGGING) {
			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
			reinit = 1;
		}
		if ((mask & IFCAP_WOL) &&
		    (if_getcapabilities(ifp) & IFCAP_WOL) != 0) {
			if (mask & IFCAP_WOL_MCAST)
				if_togglecapenable(ifp, IFCAP_WOL_MCAST);
			if (mask & IFCAP_WOL_MAGIC)
				if_togglecapenable(ifp, IFCAP_WOL_MAGIC);
		}
		if (reinit && (if_getdrvflags(ifp) & IFF_DRV_RUNNING))
			lem_init(adapter);
		if_vlancap(ifp);
		break;
	    }
	default:
		error = ether_ioctl(ifp, command, data);
		break;
	}
	return (error);
}
static int lem_ioctl ( if_t ifp , u_long command , caddr_t data ) { struct adapter * adapter = if_getsoftc ( ifp ) ; 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 ) { if_setflagbits ( ifp , IFF_UP , 0 ) ; if ( ! ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) ) lem_init ( adapter ) ; #ifdef INET if ( ! ( if_getflags ( ifp ) & IFF_NOARP ) ) arp_ifinit ( ifp , ifa ) ; #endif } else error = ether_ioctl ( ifp , command , data ) ; break ; case SIOCSIFMTU : { int max_frame_size ; IOCTL_DEBUGOUT ( " " ) ; EM_CORE_LOCK ( adapter ) ; switch ( adapter -> hw . mac . type ) { case e1000_82542 : max_frame_size = ETHER_MAX_LEN ; break ; default : max_frame_size = MAX_JUMBO_FRAME_SIZE ; } if ( ifr -> ifr_mtu > max_frame_size - ETHER_HDR_LEN - ETHER_CRC_LEN ) { EM_CORE_UNLOCK ( adapter ) ; error = EINVAL ; break ; } if_setmtu ( ifp , ifr -> ifr_mtu ) ; adapter -> max_frame_size = if_getmtu ( ifp ) + ETHER_HDR_LEN + ETHER_CRC_LEN ; if ( ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) ) lem_init_locked ( adapter ) ; EM_CORE_UNLOCK ( adapter ) ; break ; } case SIOCSIFFLAGS : IOCTL_DEBUGOUT ( " \
 " ) ; EM_CORE_LOCK ( adapter ) ; if ( if_getflags ( ifp ) & IFF_UP ) { if ( ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) ) { if ( ( if_getflags ( ifp ) ^ adapter -> if_flags ) & ( IFF_PROMISC | IFF_ALLMULTI ) ) { lem_disable_promisc ( adapter ) ; lem_set_promisc ( adapter ) ; } } else lem_init_locked ( adapter ) ; } else if ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) { EM_TX_LOCK ( adapter ) ; lem_stop ( adapter ) ; EM_TX_UNLOCK ( adapter ) ; } adapter -> if_flags = if_getflags ( ifp ) ; EM_CORE_UNLOCK ( adapter ) ; break ; case SIOCADDMULTI : case SIOCDELMULTI : IOCTL_DEBUGOUT ( " " ) ; if ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) { EM_CORE_LOCK ( adapter ) ; lem_disable_intr ( adapter ) ; lem_set_multi ( adapter ) ; if ( adapter -> hw . mac . type == e1000_82542 && adapter -> hw . revision_id == E1000_REVISION_2 ) { lem_initialize_receive_unit ( adapter ) ; } #ifdef DEVICE_POLLING if ( ! ( if_getcapenable ( ifp ) & IFCAP_POLLING ) ) #endif lem_enable_intr ( adapter ) ; EM_CORE_UNLOCK ( adapter ) ; } break ; case SIOCSIFMEDIA : EM_CORE_LOCK ( adapter ) ; if ( e1000_check_reset_block ( & adapter -> hw ) ) { EM_CORE_UNLOCK ( adapter ) ; device_printf ( adapter -> dev , " " " \n " ) ; break ; } EM_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 ^ if_getcapenable ( ifp ) ; #ifdef DEVICE_POLLING if ( mask & IFCAP_POLLING ) { if ( ifr -> ifr_reqcap & IFCAP_POLLING ) { error = ether_poll_register ( lem_poll , ifp ) ; if ( error ) return ( error ) ; EM_CORE_LOCK ( adapter ) ; lem_disable_intr ( adapter ) ; if_setcapenablebit ( ifp , IFCAP_POLLING , 0 ) ; EM_CORE_UNLOCK ( adapter ) ; } else { error = ether_poll_deregister ( ifp ) ; EM_CORE_LOCK ( adapter ) ; lem_enable_intr ( adapter ) ; if_setcapenablebit ( ifp , 0 , IFCAP_POLLING ) ; EM_CORE_UNLOCK ( adapter ) ; } } #endif if ( mask & IFCAP_HWCSUM ) { if_togglecapenable ( ifp , IFCAP_HWCSUM ) ; reinit = 1 ; } if ( mask & IFCAP_VLAN_HWTAGGING ) { if_togglecapenable ( ifp , IFCAP_VLAN_HWTAGGING ) ; reinit = 1 ; } if ( ( mask & IFCAP_WOL ) && ( if_getcapabilities ( ifp ) & IFCAP_WOL ) != 0 ) { if ( mask & IFCAP_WOL_MCAST ) if_togglecapenable ( ifp , IFCAP_WOL_MCAST ) ; if ( mask & IFCAP_WOL_MAGIC ) if_togglecapenable ( ifp , IFCAP_WOL_MAGIC ) ; } if ( reinit && ( if_getdrvflags ( ifp ) & IFF_DRV_RUNNING ) ) lem_init ( adapter ) ; if_vlancap ( ifp ) ; break ; } default : error = ether_ioctl ( ifp , command , data ) ; break ; } return ( error ) ; }
Ioctl entry point
  em_ioctl is called when the user wants to configure the
  interface.
Ioctl entry point em_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 */