144743Smarkm /*
244743Smarkm  * This part for NCR UNIX with is from Andrew Maffei (arm@aqua.whoi.edu). It
344743Smarkm  * assumes TLI throughout. In order to look up endpoint address information
444743Smarkm  * we must talk to the "timod" streams module. For some reason "timod" wants
544743Smarkm  * to sit directly on top of the device driver. Therefore we pop off all
644743Smarkm  * streams modules except the driver, install the "timod" module so that we
744743Smarkm  * can figure out network addresses, and then restore the original state.
844743Smarkm  */
944743Smarkm
1044743Smarkm#ifndef lint
1144743Smarkmstatic char sccsid[] = "@(#) ncr.c 1.1 94/12/28 17:42:34";
1244743Smarkm#endif
1344743Smarkm
1444743Smarkm#include <sys/types.h>
1544743Smarkm#include <stdio.h>
1644743Smarkm#include <syslog.h>
1744743Smarkm#include <sys/tiuser.h>
1844743Smarkm#include <stropts.h>
1944743Smarkm#include <sys/conf.h>
2044743Smarkm
2144743Smarkm#include "tcpd.h"
2244743Smarkm
2344743Smarkm#define MAX_MODULE_COUNT	10	/* XXX */
2444743Smarkm
2544743Smarkm/* fromhost - tear down the streams stack then rebuild it */
2644743Smarkm
2744743Smarkmvoid    fromhost(request)
2844743Smarkmstruct request_info *request;
2944743Smarkm{
3044743Smarkm    int     i;
3144743Smarkm    int     num_mod;
3244743Smarkm    struct str_list str_list;
3344743Smarkm    struct str_mlist mod_buffer[MAX_MODULE_COUNT];
3444743Smarkm    int     fd = request->fd;
3544743Smarkm
3644743Smarkm    str_list.sl_nmods = MAX_MODULE_COUNT;
3744743Smarkm    str_list.sl_modlist = &mod_buffer[0];
3844743Smarkm
3944743Smarkm    /*
4044743Smarkm     * On systems with WIN streams support we have to be careful about what
4144743Smarkm     * is on the stream we are passed. This code POPs off all modules above
4244743Smarkm     * the pseudo driver, pushes timod, gets the host address information,
4344743Smarkm     * pops timod and then pushes all modules back on the stream.
4444743Smarkm     *
4544743Smarkm     * Some state may be lost in this process. /usr/etc/tlid seems to do special
4644743Smarkm     * things to the stream depending on the TCP port being serviced. (not a
4744743Smarkm     * very nice thing to do!). It is unclear what to do if this code breaks
4844743Smarkm     * - the stream may be left in an unknown condition.
4944743Smarkm     */
5044743Smarkm    if ((num_mod = ioctl(fd, I_LIST, NULL)) < 0)
5144743Smarkm	tcpd_warn("fromhost: LIST failed: %m");
5244743Smarkm    if (ioctl(fd, I_LIST, &str_list) < 0)
5344743Smarkm	tcpd_warn("fromhost: LIST failed: %m");
5444743Smarkm
5544743Smarkm    /*
5644743Smarkm     * POP stream modules except for the driver.
5744743Smarkm     */
5844743Smarkm    for (i = 0; i < num_mod - 1; i++)
5944743Smarkm	if (ioctl(fd, I_POP, 0) < 0)
6044743Smarkm	    tcpd_warn("fromhost: POP %s: %m", mod_buffer[i].l_name);
6144743Smarkm
6244743Smarkm    /*
6344743Smarkm     * PUSH timod so that host address ioctls can be executed.
6444743Smarkm     */
6544743Smarkm    if (ioctl(fd, I_PUSH, "timod") < 0)
6644743Smarkm	tcpd_warn("fromhost: PUSH timod: %m");
6744743Smarkm    tli_host(request);
6844743Smarkm
6944743Smarkm    /*
7044743Smarkm     * POP timod, we're done with it now.
7144743Smarkm     */
7244743Smarkm    if (ioctl(fd, I_POP, 0) < 0)
7344743Smarkm	tcpd_warn("fromhost: POP timod: %m");
7444743Smarkm
7544743Smarkm    /*
7644743Smarkm     * Restore stream modules.
7744743Smarkm     */
7844743Smarkm    for (i = num_mod - 2; i >= 0; i--)
7944743Smarkm	if (ioctl(fd, I_PUSH, mod_buffer[i].l_name) < 0)
8044743Smarkm	    tcpd_warn("fromhost: PUSH %s: %m", mod_buffer[i].l_name);
8144743Smarkm}
82