/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* bos720 src/bos/usr/samples/ndd/entsamp_ctl.c 1.1 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 1994 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ static char sccsid[] = "@(#)41 1.1 src/bos/usr/samples/ndd/entsamp_ctl.c, entsamp, bos720 1/14/94 13:39:51"; /* * COMPONENT_NAME: (ENTSAMP) IBM BOS Sample Program * * FUNCTIONS: * entsamp_ctl * entsamp_cmd * * ORIGINS: 27 * * (C) COPYRIGHT International Business Machines Corp. 1994 * All Rights Reserved * Licensed Materials - Property of IBM * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* NOTICE TO USERS OF THE SOURCE CODE EXAMPLES THE SOURCE CODE EXAMPLES PROVIDED BY IBM ARE ONLY INTENDED TO ASSIST IN THE DEVELOPMENT OF A WORKING SOFTWARE PROGRAM. THE SOURCE CODE EXAMPLES DO NOT FUNCTION AS WRITTEN: ADDITIONAL CODE IS REQUIRED. IN ADDITION, THE SOURCE CODE EXAMPLES MAY NOT COMPILE AND/OR BIND SUCCESSFULLY AS WRITTEN. INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, IS WITH YOU. SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IBM does not warrant that the contents of the source code examples, whether individually or as one or more groups, will meet your requirements or that the source code examples are error-free. IBM may make improvements and/or changes in the source code examples at any time. Changes may be made periodically to the information in the source code examples; these changes may be reported, for the sample device drivers included herein, in new editions of the examples. References in the source code examples to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM licensed program in the source code examples is not intended to state or imply that only IBM's licensed program may be used. Any functionally equivalent program may be used. * RISC System/6000 is a trademark of International Business Machines Corporation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "entsamp_mac.h" #include "entsamp.h" extern ethernet_all_mib_t entsamp_mib_status; /*****************************************************************************/ /* * NAME: entsamp_ctl * * FUNCTION: Ethernet driver ioctl routine. * * EXECUTION ENVIRONMENT: process only * * NOTES: * * CALLED FROM: * NS user by using the ndd_ctl field in the NDD on the NDD chain. * * INPUT: * p_ndd - pointer to the ndd. * cmd - control command * arg - pointer to the argument for the control command * length - length of the argument. * * RETURNS: * 0 - OK * ENETUNREACH - device is currently unreachable * ENETDOWN - device is down * EINVAL - invalid paramter * ENOMEM - unable to allocate required memory * EOPNOTSUPP - operation not supported */ /*****************************************************************************/ entsamp_ctl( ndd_t *p_ndd, /* pointer to the ndd in the dev_ctl area */ int cmd, /* control command */ caddr_t arg, /* argument of the control command */ int length) /* length of the argument */ { entsamp_dev_ctl_t *p_dev_ctl = (entsamp_dev_ctl_t *)(p_ndd->ndd_correlator); int rc = 0; /* return code */ int ipri; TRACE_SYS(HKWD_ENTSAMP_OTHER, "IctB", (ulong)p_ndd, cmd, (ulong)arg); TRACE_SYS(HKWD_ENTSAMP_OTHER, "IctC", length, 0, 0); /* * Lock the complex lock ctl_clock to lock out other ioctl to the same device. */ lock_write(&CTL_LOCK); switch(cmd) { /* * Get the generic statistics. * This is for ndd_genstats + ent_genstats. */ case NDD_GET_STATS: { if (length != sizeof(ent_ndd_stats_t)) { rc = EINVAL; break; } /* * Perform device-specific operations to gather various * statistics and put them in the device control table. * * A section of device-specific code was omitted here. */ /* copy statistics to user's buffer */ bcopy(&NDD.ndd_genstats, arg, sizeof(ndd_genstats_t)); bcopy(&(ENTSTATS), arg + sizeof(ndd_genstats_t), sizeof(ent_genstats_t)); break; } /* * Get all of the device statistics. * This is for ndd_genstats + ent_genstats + entsamp_stats */ case NDD_GET_ALL_STATS: { if (length != sizeof(entsamp_all_stats_t)) { rc = EINVAL; break; } /* * Perform device-specific operations to gather various * statistics and put them in the device control table. * * A section of device-specific code was omitted here. */ /* copy statistics to user's buffer */ bcopy(&NDD.ndd_genstats, arg, sizeof(ndd_genstats_t)); bcopy(&(ENTSTATS), arg + sizeof(ndd_genstats_t), sizeof(ent_genstats_t) + sizeof(entsamp_stats_t)); break; } /* * Clear all of the statistics. */ case NDD_CLEAR_STATS: { /* * Perform device-specific operations to reset various * statistics counters either in the driver or on the * device. * * A section of device-specific code was omitted here. */ break; } /* * Enable the adapter to receive all of the multicast packets on the network. */ case NDD_ENABLE_MULTICAST: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } WRK.enable_multi++; /* inc the reference counter */ if (WRK.enable_multi == 1) { p_ndd->ndd_flags |= NDD_MULTICAST; entsamp_cmd(p_dev_ctl, NDD_ENABLE_MULTICAST, FALSE); } break; } /* * Disable the all multicast function. */ case NDD_DISABLE_MULTICAST: { if (!WRK.enable_multi) { rc = EINVAL; break; } WRK.enable_multi--; /* dec the reference counter */ if (!WRK.enable_multi) { p_ndd->ndd_flags &= ~NDD_MULTICAST; entsamp_cmd(p_dev_ctl, NDD_DISABLE_MULTICAST, FALSE); } break; } /* * Enable the promiscuous mode. */ case NDD_PROMISCUOUS_ON: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } WRK.promiscuous_count++; /* inc the reference counter */ if (WRK.promiscuous_count == 1) { p_ndd->ndd_flags |= NDD_PROMISC; entsamp_cmd(p_dev_ctl, NDD_PROMISCUOUS_ON, FALSE); } break; } /* * Disable the promiscuous mode. */ case NDD_PROMISCUOUS_OFF: { if (!WRK.promiscuous_count) { rc = EINVAL; break; } WRK.promiscuous_count--; /* dev the reference counter */ if (!WRK.promiscuous_count) { p_ndd->ndd_flags &= ~NDD_PROMISC; entsamp_cmd(p_dev_ctl, NDD_PROMISCUOUS_OFF, FALSE); } break; } /* * Add a filter. Since the demuxer is managing all the type filtering, * this operation doesn't mean a whole lot to the driver. * Increment a reference count and return. */ case NDD_ADD_FILTER: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } WRK.filter_count++; /* inc the reference counter */ break; } /* * Delete a filter. The driver decrement the reference count and return. */ case NDD_DEL_FILTER: { if (!WRK.filter_count) { rc = EINVAL; break; } WRK.filter_count--; /* dec the reference counter */ break; } /* * Query the MIB support status on the driver. */ case NDD_MIB_QUERY: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } if (length != sizeof(ethernet_all_mib_t)) { rc = EINVAL; break; } /* copy status to user's buffer */ bcopy(&entsamp_mib_status, arg, sizeof(ethernet_all_mib_t)); break; } /* * Get all MIB values. */ case NDD_MIB_GET: { if (length != sizeof(ethernet_all_mib_t)) { rc = EINVAL; break; } /* * Performs device-specific operations to gather various * statistics for the MIB variables. * * A section of device-specific code was omitted here. */ /* copy mibs to user's buffer */ bcopy(&MIB, arg, sizeof(ethernet_all_mib_t)); break; } /* * Get receive address table (mainly for MIB variables). * The receive address table is consists of all the addresses that the * adapter is armed to receive packets with. It includes the host * network address, the broadcast address and the currently registered * multicast addresses. */ case NDD_MIB_ADDR: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } if (length < sizeof(ndd_mib_addr_t)) { rc = EINVAL; break; } /* * Performs device-specific operations to gather all * the current valid receive addresses for the device * and copy them into the user provided table. * * A section of device-specific code was omitted here. */ break; } /* * Add an asynchronous status filter. This driver only track the * NDD_BAD_PKTS status filter. If this is the first time the bad packets * status is added, the driver will config the adapter to start receiving * bad packets on the network. */ case NDD_ADD_STATUS: { ns_com_status_t *p_stat = (ns_com_status_t *)arg; if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } if (p_stat->filtertype == NS_STATUS_MASK) { if (p_stat->mask == NDD_BAD_PKTS) { WRK.badframe_count++; /* inc reference count */ if (WRK.badframe_count == 1) { p_ndd->ndd_flags |= ENT_RCV_BAD_FRAME; entsamp_cmd(p_dev_ctl, NDD_ADD_STATUS, FALSE); } } else { WRK.otherstatus++; /* inc reference count */ } } else { rc = EINVAL; } break; } /* * Delete an asynchronous status filter. This driver only track the * NDD_BAD_PKTS status filter. If this is the last time the bad packets * status is deleted, the driver will config the adapter to stop receiving * bad packets on the network. */ case NDD_DEL_STATUS: { ns_com_status_t *p_stat = (ns_com_status_t *)arg; if (p_stat->filtertype == NS_STATUS_MASK) { if (p_stat->mask == NDD_BAD_PKTS) { if (!WRK.badframe_count) { rc = EINVAL; break; } WRK.badframe_count--; /* dec reference count */ if (!WRK.badframe_count) { p_ndd->ndd_flags &= ~ENT_RCV_BAD_FRAME; entsamp_cmd(p_dev_ctl, NDD_DEL_STATUS, FALSE); } } else { if (!WRK.otherstatus) { rc = EINVAL; break; } WRK.otherstatus--; /* dec reference count */ } } else { rc = EINVAL; } break; } /* * Add a multicast address to the multicast filter. */ case NDD_ENABLE_ADDRESS: { if (p_dev_ctl->device_state != OPENED) { if (p_dev_ctl->device_state == DEAD) { rc = ENETDOWN; } else { rc = ENETUNREACH; } break; } /* verify that it is a valid multicast address */ if (*((char *)arg) & MULTI_BIT_MASK) { /* * Perform device-specific operations to add a multicast * address to the multicast filter on the device. * * A section of device-specific code was omitted here. */ } else { rc = EINVAL; } break; } /* * Delete a multicast address from the multicast filter. */ case NDD_DISABLE_ADDRESS: { /* verify that it is a valid multicast address */ if (*((char *)arg) & MULTI_BIT_MASK) { /* * Perform device-specific operations to remove a * multicast address from the multicast filter on the device. * * A section of device-specific code was omitted here. */ } else rc = EINVAL; break; } default: rc = EOPNOTSUPP; TRACE_SYS(HKWD_ENTSAMP_ERR, "Ict3", rc, cmd, 0); break; } lock_done(&CTL_LOCK); TRACE_SYS(HKWD_ENTSAMP_OTHER, "IctE", rc, 0, 0); return(rc); } /*****************************************************************************/ /* * NAME: entsamp_cmd * * FUNCTION: Issue device-specific control commands to the adapter. * * EXECUTION ENVIRONMENT: process or interrupt * * NOTES: * * CALLED FROM: * entsamp_ctl * * INPUT: * p_dev_ctl - pointer to the device control area. * cmd - adapter control command * at_int_lvl - flag for running at interrupt or process level * * RETURNS: * 0 - OK * ENETUNREACH - device is currently unreachable * ENETDOWN - device is down * EOPNOTSUPP - operation not supported */ /*****************************************************************************/ entsamp_cmd( entsamp_dev_ctl_t *p_dev_ctl, /* pointer to device control area */ int cmd, /* adapter control command */ int at_int_lvl) /* flag for intr/proc level */ { int ipri; TRACE_SYS(HKWD_ENTSAMP_OTHER, "IcmB", (ulong)p_dev_ctl, cmd, at_int_lvl); /* * Get the cmd_lock and check the device state, make sure that the * error recovery has not occurred. */ if (!at_int_lvl) { ipri = disable_lock(PL_IMP, &CMD_LOCK); if (p_dev_ctl->device_state != OPENED && p_dev_ctl->device_state != OPEN_PENDING) { if (p_dev_ctl->device_state == DEAD) { unlock_enable(ipri, &CMD_LOCK); TRACE_SYS(HKWD_ENTSAMP_ERR, "Icm1", ENETDOWN, p_dev_ctl->device_state, 0); return(ENETDOWN); } else { unlock_enable(ipri, &CMD_LOCK); TRACE_SYS(HKWD_ENTSAMP_ERR, "Icm2", ENETUNREACH, p_dev_ctl->device_state, 0); return(ENETUNREACH); } } } /* * According to the cmd parameter, perform various device-specific * control operations to the adapter. * * A section of device-specific code was omitted here. */ if (!at_int_lvl) { p_dev_ctl->ctl_pending = TRUE; /* set null event to sleep on */ p_dev_ctl->ctl_event = EVENT_NULL; /* start the ioctl timer */ w_start(&(CTLWDT)); /* * go to sleep with the cmd_slock freed up/regained. * Note that the ctl_slock remained locked during the whole time */ e_sleep_thread(&p_dev_ctl->ctl_event, &CMD_LOCK, LOCK_HANDLER); p_dev_ctl->ctl_pending = FALSE; } if (!at_int_lvl) unlock_enable(ipri, &CMD_LOCK); TRACE_SYS(HKWD_ENTSAMP_OTHER, "IcmE", (ulong)p_dev_ctl->ctl_status, 0, 0); return(p_dev_ctl->ctl_status); }