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