Home | History | Annotate | Line # | Download | only in netatalk
ddp_usrreq.c revision 1.4.6.2
      1  1.4.6.2   nathanw /*	$NetBSD: ddp_usrreq.c,v 1.4.6.2 2002/01/08 00:33:59 nathanw Exp $	 */
      2      1.1  christos 
      3      1.1  christos /*
      4      1.1  christos  * Copyright (c) 1990,1991 Regents of The University of Michigan.
      5      1.1  christos  * All Rights Reserved.
      6      1.1  christos  *
      7      1.1  christos  * Permission to use, copy, modify, and distribute this software and
      8      1.1  christos  * its documentation for any purpose and without fee is hereby granted,
      9      1.1  christos  * provided that the above copyright notice appears in all copies and
     10      1.1  christos  * that both that copyright notice and this permission notice appear
     11      1.1  christos  * in supporting documentation, and that the name of The University
     12      1.1  christos  * of Michigan not be used in advertising or publicity pertaining to
     13      1.1  christos  * distribution of the software without specific, written prior
     14      1.1  christos  * permission. This software is supplied as is without expressed or
     15      1.1  christos  * implied warranties of any kind.
     16      1.1  christos  *
     17      1.1  christos  * This product includes software developed by the University of
     18      1.1  christos  * California, Berkeley and its contributors.
     19      1.1  christos  *
     20      1.1  christos  *	Research Systems Unix Group
     21      1.1  christos  *	The University of Michigan
     22      1.1  christos  *	c/o Wesley Craig
     23      1.1  christos  *	535 W. William Street
     24      1.1  christos  *	Ann Arbor, Michigan
     25      1.1  christos  *	+1-313-764-2278
     26      1.1  christos  *	netatalk (at) umich.edu
     27      1.1  christos  */
     28  1.4.6.1   nathanw 
     29  1.4.6.1   nathanw #include <sys/cdefs.h>
     30  1.4.6.2   nathanw __KERNEL_RCSID(0, "$NetBSD: ddp_usrreq.c,v 1.4.6.2 2002/01/08 00:33:59 nathanw Exp $");
     31      1.1  christos 
     32      1.1  christos #include <sys/param.h>
     33  1.4.6.2   nathanw #include <sys/errno.h>
     34      1.1  christos #include <sys/systm.h>
     35      1.1  christos #include <sys/proc.h>
     36      1.1  christos #include <sys/mbuf.h>
     37      1.1  christos #include <sys/ioctl.h>
     38      1.1  christos #include <sys/socket.h>
     39      1.1  christos #include <sys/socketvar.h>
     40      1.1  christos #include <sys/protosw.h>
     41      1.1  christos #include <net/if.h>
     42      1.1  christos #include <net/route.h>
     43      1.1  christos #include <net/if_ether.h>
     44      1.1  christos #include <netinet/in.h>
     45      1.1  christos 
     46      1.1  christos #include <netatalk/at.h>
     47      1.1  christos #include <netatalk/at_var.h>
     48      1.1  christos #include <netatalk/ddp_var.h>
     49      1.1  christos #include <netatalk/aarp.h>
     50      1.1  christos #include <netatalk/at_extern.h>
     51      1.1  christos 
     52      1.1  christos static void at_pcbdisconnect __P((struct ddpcb *));
     53      1.1  christos static void at_sockaddr __P((struct ddpcb *, struct mbuf *));
     54      1.1  christos static int at_pcbsetaddr __P((struct ddpcb *, struct mbuf *, struct proc *));
     55      1.1  christos static int at_pcbconnect __P((struct ddpcb *, struct mbuf *, struct proc *));
     56      1.1  christos static void at_pcbdetach __P((struct socket *, struct ddpcb *));
     57      1.1  christos static int at_pcballoc __P((struct socket *));
     58      1.1  christos 
     59      1.1  christos struct ddpcb   *ddp_ports[ATPORT_LAST];
     60      1.1  christos struct ddpcb   *ddpcb = NULL;
     61      1.1  christos struct at_ifaddrhead at_ifaddr;		/* Here as inited in this file */
     62      1.1  christos u_long ddp_sendspace = DDP_MAXSZ;	/* Max ddp size + 1 (ddp_type) */
     63      1.2  christos u_long ddp_recvspace = 25 * (587 + sizeof(struct sockaddr_at));
     64      1.1  christos 
     65      1.1  christos /* ARGSUSED */
     66      1.1  christos int
     67      1.1  christos ddp_usrreq(so, req, m, addr, rights, p)
     68      1.1  christos 	struct socket  *so;
     69      1.1  christos 	int             req;
     70      1.1  christos 	struct mbuf    *m;
     71      1.1  christos 	struct mbuf    *addr;
     72      1.1  christos 	struct mbuf    *rights;
     73      1.1  christos 	struct proc    *p;
     74      1.1  christos {
     75      1.1  christos 	struct ddpcb   *ddp;
     76      1.1  christos 	int             error = 0;
     77      1.1  christos 
     78      1.1  christos 	ddp = sotoddpcb(so);
     79      1.1  christos 
     80      1.1  christos 	if (req == PRU_CONTROL) {
     81      1.1  christos 		return (at_control((long) m, (caddr_t) addr,
     82      1.1  christos 		    (struct ifnet *) rights, (struct proc *) p));
     83      1.3   thorpej 	}
     84      1.4   thorpej 	if (req == PRU_PURGEIF) {
     85      1.4   thorpej 		at_purgeif((struct ifnet *) rights);
     86      1.3   thorpej 		return (0);
     87      1.1  christos 	}
     88      1.1  christos 	if (rights && rights->m_len) {
     89      1.1  christos 		error = EINVAL;
     90      1.1  christos 		goto release;
     91      1.1  christos 	}
     92      1.1  christos 	if (ddp == NULL && req != PRU_ATTACH) {
     93      1.1  christos 		error = EINVAL;
     94      1.1  christos 		goto release;
     95      1.1  christos 	}
     96      1.1  christos 	switch (req) {
     97      1.1  christos 	case PRU_ATTACH:
     98      1.1  christos 		if (ddp != NULL) {
     99      1.1  christos 			error = EINVAL;
    100      1.1  christos 			break;
    101      1.1  christos 		}
    102      1.1  christos 		if ((error = at_pcballoc(so)) != 0) {
    103      1.1  christos 			break;
    104      1.1  christos 		}
    105      1.1  christos 		error = soreserve(so, ddp_sendspace, ddp_recvspace);
    106      1.1  christos 		break;
    107      1.1  christos 
    108      1.1  christos 	case PRU_DETACH:
    109      1.1  christos 		at_pcbdetach(so, ddp);
    110      1.1  christos 		break;
    111      1.1  christos 
    112      1.1  christos 	case PRU_BIND:
    113      1.1  christos 		error = at_pcbsetaddr(ddp, addr, p);
    114      1.1  christos 		break;
    115      1.1  christos 
    116      1.1  christos 	case PRU_SOCKADDR:
    117      1.1  christos 		at_sockaddr(ddp, addr);
    118      1.1  christos 		break;
    119      1.1  christos 
    120      1.1  christos 	case PRU_CONNECT:
    121      1.1  christos 		if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
    122      1.1  christos 			error = EISCONN;
    123      1.1  christos 			break;
    124      1.1  christos 		}
    125      1.1  christos 		error = at_pcbconnect(ddp, addr, p);
    126      1.1  christos 		if (error == 0)
    127      1.1  christos 			soisconnected(so);
    128      1.1  christos 		break;
    129      1.1  christos 
    130      1.1  christos 	case PRU_DISCONNECT:
    131      1.1  christos 		if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
    132      1.1  christos 			error = ENOTCONN;
    133      1.1  christos 			break;
    134      1.1  christos 		}
    135      1.1  christos 		at_pcbdisconnect(ddp);
    136      1.1  christos 		soisdisconnected(so);
    137      1.1  christos 		break;
    138      1.1  christos 
    139      1.1  christos 	case PRU_SHUTDOWN:
    140      1.1  christos 		socantsendmore(so);
    141      1.1  christos 		break;
    142      1.1  christos 
    143      1.1  christos 	case PRU_SEND:{
    144      1.1  christos 			int s = 0;
    145      1.1  christos 
    146      1.1  christos 			if (addr) {
    147      1.1  christos 				if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
    148      1.1  christos 					error = EISCONN;
    149      1.1  christos 					break;
    150      1.1  christos 				}
    151      1.1  christos 				s = splnet();
    152      1.1  christos 				error = at_pcbconnect(ddp, addr, p);
    153      1.1  christos 				if (error) {
    154      1.1  christos 					splx(s);
    155      1.1  christos 					break;
    156      1.1  christos 				}
    157      1.1  christos 			} else {
    158      1.1  christos 				if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) {
    159      1.1  christos 					error = ENOTCONN;
    160      1.1  christos 					break;
    161      1.1  christos 				}
    162      1.1  christos 			}
    163      1.1  christos 
    164      1.1  christos 			error = ddp_output(m, ddp);
    165      1.1  christos 			m = NULL;
    166      1.1  christos 			if (addr) {
    167      1.1  christos 				at_pcbdisconnect(ddp);
    168      1.1  christos 				splx(s);
    169      1.1  christos 			}
    170      1.1  christos 		}
    171      1.1  christos 		break;
    172      1.1  christos 
    173      1.1  christos 	case PRU_ABORT:
    174      1.1  christos 		soisdisconnected(so);
    175      1.1  christos 		at_pcbdetach(so, ddp);
    176      1.1  christos 		break;
    177      1.1  christos 
    178      1.1  christos 	case PRU_LISTEN:
    179      1.1  christos 	case PRU_CONNECT2:
    180      1.1  christos 	case PRU_ACCEPT:
    181      1.1  christos 	case PRU_SENDOOB:
    182      1.1  christos 	case PRU_FASTTIMO:
    183      1.1  christos 	case PRU_SLOWTIMO:
    184      1.1  christos 	case PRU_PROTORCV:
    185      1.1  christos 	case PRU_PROTOSEND:
    186      1.1  christos 		error = EOPNOTSUPP;
    187      1.1  christos 		break;
    188      1.1  christos 
    189      1.1  christos 	case PRU_RCVD:
    190      1.1  christos 	case PRU_RCVOOB:
    191      1.1  christos 		/*
    192      1.1  christos 		 * Don't mfree. Good architecture...
    193      1.1  christos 		 */
    194      1.1  christos 		return (EOPNOTSUPP);
    195      1.1  christos 
    196      1.1  christos 	case PRU_SENSE:
    197      1.1  christos 		/*
    198      1.1  christos 		 * 1. Don't return block size.
    199      1.1  christos 		 * 2. Don't mfree.
    200      1.1  christos 		 */
    201      1.1  christos 		return (0);
    202      1.1  christos 
    203      1.1  christos 	default:
    204      1.1  christos 		error = EOPNOTSUPP;
    205      1.1  christos 	}
    206      1.1  christos 
    207      1.1  christos release:
    208      1.1  christos 	if (m != NULL) {
    209      1.1  christos 		m_freem(m);
    210      1.1  christos 	}
    211      1.1  christos 	return (error);
    212      1.1  christos }
    213      1.1  christos 
    214      1.1  christos static void
    215      1.1  christos at_sockaddr(ddp, addr)
    216      1.1  christos 	struct ddpcb   *ddp;
    217      1.1  christos 	struct mbuf    *addr;
    218      1.1  christos {
    219      1.1  christos 	struct sockaddr_at *sat;
    220      1.1  christos 
    221      1.1  christos 	addr->m_len = sizeof(struct sockaddr_at);
    222      1.1  christos 	sat = mtod(addr, struct sockaddr_at *);
    223      1.1  christos 	*sat = ddp->ddp_lsat;
    224      1.1  christos }
    225      1.1  christos 
    226      1.1  christos static int
    227      1.1  christos at_pcbsetaddr(ddp, addr, p)
    228      1.1  christos 	struct ddpcb   *ddp;
    229      1.1  christos 	struct mbuf    *addr;
    230      1.1  christos 	struct proc    *p;
    231      1.1  christos {
    232      1.1  christos 	struct sockaddr_at lsat, *sat;
    233      1.1  christos 	struct at_ifaddr *aa;
    234      1.1  christos 	struct ddpcb   *ddpp;
    235      1.1  christos 
    236      1.1  christos 	if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) {	/* shouldn't be bound */
    237      1.1  christos 		return (EINVAL);
    238      1.1  christos 	}
    239      1.1  christos 	if (addr != 0) {	/* validate passed address */
    240      1.1  christos 		sat = mtod(addr, struct sockaddr_at *);
    241      1.1  christos 		if (addr->m_len != sizeof(*sat))
    242      1.1  christos 			return (EINVAL);
    243      1.1  christos 
    244      1.1  christos 		if (sat->sat_family != AF_APPLETALK)
    245      1.1  christos 			return (EAFNOSUPPORT);
    246      1.1  christos 
    247      1.1  christos 		if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
    248      1.1  christos 		    sat->sat_addr.s_net != ATADDR_ANYNET) {
    249      1.1  christos 			for (aa = at_ifaddr.tqh_first; aa;
    250      1.1  christos 			    aa = aa->aa_list.tqe_next) {
    251      1.1  christos 				if ((sat->sat_addr.s_net ==
    252      1.1  christos 				    AA_SAT(aa)->sat_addr.s_net) &&
    253      1.1  christos 				    (sat->sat_addr.s_node ==
    254      1.1  christos 				    AA_SAT(aa)->sat_addr.s_node))
    255      1.1  christos 					break;
    256      1.1  christos 			}
    257      1.1  christos 			if (!aa)
    258      1.1  christos 				return (EADDRNOTAVAIL);
    259      1.1  christos 		}
    260      1.1  christos 		if (sat->sat_port != ATADDR_ANYPORT) {
    261      1.1  christos 			if (sat->sat_port < ATPORT_FIRST ||
    262      1.1  christos 			    sat->sat_port >= ATPORT_LAST)
    263      1.1  christos 				return (EINVAL);
    264      1.1  christos 
    265      1.1  christos 			if (sat->sat_port < ATPORT_RESERVED &&
    266      1.1  christos 			    suser(p->p_ucred, &p->p_acflag))
    267      1.1  christos 				return (EACCES);
    268      1.1  christos 		}
    269      1.1  christos 	} else {
    270      1.1  christos 		bzero((caddr_t) & lsat, sizeof(struct sockaddr_at));
    271      1.1  christos 		lsat.sat_len = sizeof(struct sockaddr_at);
    272      1.1  christos 		lsat.sat_addr.s_node = ATADDR_ANYNODE;
    273      1.1  christos 		lsat.sat_addr.s_net = ATADDR_ANYNET;
    274      1.1  christos 		lsat.sat_family = AF_APPLETALK;
    275      1.1  christos 		sat = &lsat;
    276      1.1  christos 	}
    277      1.1  christos 
    278      1.1  christos 	if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
    279      1.1  christos 	    sat->sat_addr.s_net == ATADDR_ANYNET) {
    280      1.1  christos 		if (at_ifaddr.tqh_first == NULL)
    281      1.1  christos 			return (EADDRNOTAVAIL);
    282      1.1  christos 		sat->sat_addr = AA_SAT(at_ifaddr.tqh_first)->sat_addr;
    283      1.1  christos 	}
    284      1.1  christos 	ddp->ddp_lsat = *sat;
    285      1.1  christos 
    286      1.1  christos 	/*
    287      1.1  christos          * Choose port.
    288      1.1  christos          */
    289      1.1  christos 	if (sat->sat_port == ATADDR_ANYPORT) {
    290      1.1  christos 		for (sat->sat_port = ATPORT_RESERVED;
    291      1.1  christos 		     sat->sat_port < ATPORT_LAST; sat->sat_port++) {
    292      1.1  christos 			if (ddp_ports[sat->sat_port - 1] == 0)
    293      1.1  christos 				break;
    294      1.1  christos 		}
    295      1.1  christos 		if (sat->sat_port == ATPORT_LAST) {
    296      1.1  christos 			return (EADDRNOTAVAIL);
    297      1.1  christos 		}
    298      1.1  christos 		ddp->ddp_lsat.sat_port = sat->sat_port;
    299      1.1  christos 		ddp_ports[sat->sat_port - 1] = ddp;
    300      1.1  christos 	} else {
    301      1.1  christos 		for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
    302      1.1  christos 		     ddpp = ddpp->ddp_pnext) {
    303      1.1  christos 			if (ddpp->ddp_lsat.sat_addr.s_net ==
    304      1.1  christos 			    sat->sat_addr.s_net &&
    305      1.1  christos 			    ddpp->ddp_lsat.sat_addr.s_node ==
    306      1.1  christos 			    sat->sat_addr.s_node)
    307      1.1  christos 				break;
    308      1.1  christos 		}
    309      1.1  christos 		if (ddpp != NULL)
    310      1.1  christos 			return (EADDRINUSE);
    311      1.1  christos 
    312      1.1  christos 		ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
    313      1.1  christos 		ddp_ports[sat->sat_port - 1] = ddp;
    314      1.1  christos 		if (ddp->ddp_pnext)
    315      1.1  christos 			ddp->ddp_pnext->ddp_pprev = ddp;
    316      1.1  christos 	}
    317      1.1  christos 
    318      1.1  christos 	return 0;
    319      1.1  christos }
    320      1.1  christos 
    321      1.1  christos static int
    322      1.1  christos at_pcbconnect(ddp, addr, p)
    323      1.1  christos 	struct ddpcb   *ddp;
    324      1.1  christos 	struct mbuf    *addr;
    325      1.1  christos 	struct proc    *p;
    326      1.1  christos {
    327      1.1  christos 	struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *);
    328      1.1  christos 	struct route   *ro;
    329      1.1  christos 	struct at_ifaddr *aa = 0;
    330      1.1  christos 	struct ifnet   *ifp;
    331      1.1  christos 	u_short         hintnet = 0, net;
    332      1.1  christos 
    333      1.1  christos 	if (addr->m_len != sizeof(*sat))
    334      1.1  christos 		return (EINVAL);
    335      1.1  christos 	if (sat->sat_family != AF_APPLETALK) {
    336      1.1  christos 		return (EAFNOSUPPORT);
    337      1.1  christos 	}
    338      1.1  christos 	/*
    339      1.1  christos          * Under phase 2, network 0 means "the network".  We take "the
    340      1.1  christos          * network" to mean the network the control block is bound to.
    341      1.1  christos          * If the control block is not bound, there is an error.
    342      1.1  christos          */
    343      1.1  christos 	if (sat->sat_addr.s_net == ATADDR_ANYNET
    344      1.1  christos 	    && sat->sat_addr.s_node != ATADDR_ANYNODE) {
    345      1.1  christos 		if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
    346      1.1  christos 			return (EADDRNOTAVAIL);
    347      1.1  christos 		}
    348      1.1  christos 		hintnet = ddp->ddp_lsat.sat_addr.s_net;
    349      1.1  christos 	}
    350      1.1  christos 	ro = &ddp->ddp_route;
    351      1.1  christos 	/*
    352      1.1  christos          * If we've got an old route for this pcb, check that it is valid.
    353      1.1  christos          * If we've changed our address, we may have an old "good looking"
    354      1.1  christos          * route here.  Attempt to detect it.
    355      1.1  christos          */
    356      1.1  christos 	if (ro->ro_rt) {
    357      1.1  christos 		if (hintnet) {
    358      1.1  christos 			net = hintnet;
    359      1.1  christos 		} else {
    360      1.1  christos 			net = sat->sat_addr.s_net;
    361      1.1  christos 		}
    362      1.1  christos 		aa = 0;
    363      1.1  christos 		if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
    364      1.1  christos 			for (aa = at_ifaddr.tqh_first; aa;
    365      1.1  christos 			    aa = aa->aa_list.tqe_next) {
    366      1.1  christos 				if (aa->aa_ifp == ifp &&
    367      1.1  christos 				    ntohs(net) >= ntohs(aa->aa_firstnet) &&
    368      1.1  christos 				    ntohs(net) <= ntohs(aa->aa_lastnet)) {
    369      1.1  christos 					break;
    370      1.1  christos 				}
    371      1.1  christos 			}
    372      1.1  christos 		}
    373      1.1  christos 		if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
    374      1.1  christos 		    (hintnet ? hintnet : sat->sat_addr.s_net) ||
    375      1.1  christos 		    satosat(&ro->ro_dst)->sat_addr.s_node !=
    376      1.1  christos 		    sat->sat_addr.s_node)) {
    377      1.1  christos 			RTFREE(ro->ro_rt);
    378      1.1  christos 			ro->ro_rt = (struct rtentry *) 0;
    379      1.1  christos 		}
    380      1.1  christos 	}
    381      1.1  christos 	/*
    382      1.1  christos          * If we've got no route for this interface, try to find one.
    383      1.1  christos          */
    384      1.1  christos 	if (ro->ro_rt == (struct rtentry *) 0 ||
    385      1.1  christos 	    ro->ro_rt->rt_ifp == (struct ifnet *) 0) {
    386      1.1  christos 		bzero(&ro->ro_dst, sizeof(struct sockaddr_at));
    387      1.1  christos 		ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
    388      1.1  christos 		ro->ro_dst.sa_family = AF_APPLETALK;
    389      1.1  christos 		if (hintnet) {
    390      1.1  christos 			satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
    391      1.1  christos 		} else {
    392      1.1  christos 			satosat(&ro->ro_dst)->sat_addr.s_net =
    393      1.1  christos 			    sat->sat_addr.s_net;
    394      1.1  christos 		}
    395      1.1  christos 		satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
    396      1.1  christos 		rtalloc(ro);
    397      1.1  christos 	}
    398      1.1  christos 	/*
    399      1.1  christos          * Make sure any route that we have has a valid interface.
    400      1.1  christos          */
    401      1.1  christos 	aa = 0;
    402      1.1  christos 	if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
    403      1.1  christos 		for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) {
    404      1.1  christos 			if (aa->aa_ifp == ifp) {
    405      1.1  christos 				break;
    406      1.1  christos 			}
    407      1.1  christos 		}
    408      1.1  christos 	}
    409      1.1  christos 	if (aa == 0) {
    410      1.1  christos 		return (ENETUNREACH);
    411      1.1  christos 	}
    412      1.1  christos 	ddp->ddp_fsat = *sat;
    413      1.1  christos 	if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
    414      1.1  christos 		return (at_pcbsetaddr(ddp, (struct mbuf *) 0, p));
    415      1.1  christos 	}
    416      1.1  christos 	return (0);
    417      1.1  christos }
    418      1.1  christos 
    419      1.1  christos static void
    420      1.1  christos at_pcbdisconnect(ddp)
    421      1.1  christos 	struct ddpcb   *ddp;
    422      1.1  christos {
    423      1.1  christos 	ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
    424      1.1  christos 	ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
    425      1.1  christos 	ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
    426      1.1  christos }
    427      1.1  christos 
    428      1.1  christos static int
    429      1.1  christos at_pcballoc(so)
    430      1.1  christos 	struct socket  *so;
    431      1.1  christos {
    432      1.1  christos 	struct ddpcb   *ddp;
    433      1.1  christos 
    434      1.1  christos 	MALLOC(ddp, struct ddpcb *, sizeof(*ddp), M_PCB, M_WAIT);
    435      1.1  christos 	if (!ddp)
    436      1.1  christos 		panic("at_pcballoc");
    437      1.1  christos 	bzero((caddr_t) ddp, sizeof *ddp);
    438      1.1  christos 	ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
    439      1.1  christos 
    440      1.1  christos 	ddp->ddp_next = ddpcb;
    441      1.1  christos 	ddp->ddp_prev = NULL;
    442      1.1  christos 	ddp->ddp_pprev = NULL;
    443      1.1  christos 	ddp->ddp_pnext = NULL;
    444      1.1  christos 	if (ddpcb) {
    445      1.1  christos 		ddpcb->ddp_prev = ddp;
    446      1.1  christos 	}
    447      1.1  christos 	ddpcb = ddp;
    448      1.1  christos 
    449      1.1  christos 	ddp->ddp_socket = so;
    450      1.1  christos 	so->so_pcb = (caddr_t) ddp;
    451      1.1  christos 	return (0);
    452      1.1  christos }
    453      1.1  christos 
    454      1.1  christos static void
    455      1.1  christos at_pcbdetach(so, ddp)
    456      1.1  christos 	struct socket  *so;
    457      1.1  christos 	struct ddpcb   *ddp;
    458      1.1  christos {
    459      1.1  christos 	soisdisconnected(so);
    460      1.1  christos 	so->so_pcb = 0;
    461      1.1  christos 	sofree(so);
    462      1.1  christos 
    463      1.1  christos 	/* remove ddp from ddp_ports list */
    464      1.1  christos 	if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
    465      1.1  christos 	    ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
    466      1.1  christos 		if (ddp->ddp_pprev != NULL) {
    467      1.1  christos 			ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
    468      1.1  christos 		} else {
    469      1.1  christos 			ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
    470      1.1  christos 		}
    471      1.1  christos 		if (ddp->ddp_pnext != NULL) {
    472      1.1  christos 			ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
    473      1.1  christos 		}
    474      1.1  christos 	}
    475      1.1  christos 	if (ddp->ddp_route.ro_rt) {
    476      1.1  christos 		rtfree(ddp->ddp_route.ro_rt);
    477      1.1  christos 	}
    478      1.1  christos 	if (ddp->ddp_prev) {
    479      1.1  christos 		ddp->ddp_prev->ddp_next = ddp->ddp_next;
    480      1.1  christos 	} else {
    481      1.1  christos 		ddpcb = ddp->ddp_next;
    482      1.1  christos 	}
    483      1.1  christos 	if (ddp->ddp_next) {
    484      1.1  christos 		ddp->ddp_next->ddp_prev = ddp->ddp_prev;
    485      1.1  christos 	}
    486      1.1  christos 	free(ddp, M_PCB);
    487      1.1  christos }
    488      1.1  christos 
    489      1.1  christos /*
    490      1.1  christos  * For the moment, this just find the pcb with the correct local address.
    491      1.1  christos  * In the future, this will actually do some real searching, so we can use
    492      1.1  christos  * the sender's address to do de-multiplexing on a single port to many
    493      1.1  christos  * sockets (pcbs).
    494      1.1  christos  */
    495      1.1  christos struct ddpcb   *
    496      1.1  christos ddp_search(from, to, aa)
    497      1.1  christos 	struct sockaddr_at *from;
    498      1.1  christos 	struct sockaddr_at *to;
    499      1.1  christos 	struct at_ifaddr *aa;
    500      1.1  christos {
    501      1.1  christos 	struct ddpcb   *ddp;
    502      1.1  christos 
    503      1.1  christos 	/*
    504      1.1  christos          * Check for bad ports.
    505      1.1  christos          */
    506      1.1  christos 	if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) {
    507      1.1  christos 		return (NULL);
    508      1.1  christos 	}
    509      1.1  christos 	/*
    510      1.1  christos          * Make sure the local address matches the sent address.  What about
    511      1.1  christos          * the interface?
    512      1.1  christos          */
    513      1.1  christos 	for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
    514      1.1  christos 		/* XXX should we handle 0.YY? */
    515      1.1  christos 
    516      1.1  christos 		/* XXXX.YY to socket on destination interface */
    517      1.1  christos 		if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
    518      1.1  christos 		    to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
    519      1.1  christos 			break;
    520      1.1  christos 		}
    521      1.1  christos 		/* 0.255 to socket on receiving interface */
    522      1.1  christos 		if (to->sat_addr.s_node == ATADDR_BCAST &&
    523      1.1  christos 		    (to->sat_addr.s_net == 0 ||
    524      1.1  christos 		    to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
    525      1.1  christos 		ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
    526      1.1  christos 			break;
    527      1.1  christos 		}
    528      1.1  christos 		/* XXXX.0 to socket on destination interface */
    529      1.1  christos 		if (to->sat_addr.s_net == aa->aa_firstnet &&
    530      1.1  christos 		    to->sat_addr.s_node == 0 &&
    531      1.1  christos 		    ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
    532      1.1  christos 		    ntohs(aa->aa_firstnet) &&
    533      1.1  christos 		    ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
    534      1.1  christos 		    ntohs(aa->aa_lastnet)) {
    535      1.1  christos 			break;
    536      1.1  christos 		}
    537      1.1  christos 	}
    538      1.1  christos 	return (ddp);
    539      1.1  christos }
    540      1.1  christos 
    541      1.1  christos /*
    542      1.1  christos  * Initialize all the ddp & appletalk stuff
    543      1.1  christos  */
    544      1.1  christos void
    545      1.1  christos ddp_init()
    546      1.1  christos {
    547      1.1  christos 	TAILQ_INIT(&at_ifaddr);
    548      1.1  christos 	atintrq1.ifq_maxlen = IFQ_MAXLEN;
    549      1.1  christos 	atintrq2.ifq_maxlen = IFQ_MAXLEN;
    550      1.1  christos }
    551      1.1  christos 
    552      1.1  christos #if 0
    553      1.1  christos static void
    554      1.1  christos ddp_clean()
    555      1.1  christos {
    556      1.1  christos 	struct ddpcb   *ddp;
    557      1.1  christos 
    558      1.1  christos 	for (ddp = ddpcb; ddp; ddp = ddp->ddp_next)
    559      1.1  christos 		at_pcbdetach(ddp->ddp_socket, ddp);
    560      1.1  christos }
    561      1.1  christos #endif
    562