ddp_pcb.c revision 127293
18097Sjkh/* 28097Sjkh * Copyright (c) 1990,1994 Regents of The University of Michigan. 38097Sjkh * All Rights Reserved. See COPYRIGHT. 48097Sjkh * 58097Sjkh * $FreeBSD: head/sys/netatalk/ddp_pcb.c 127293 2004-03-22 04:54:36Z rwatson $ 68097Sjkh */ 721673Sjkh 88097Sjkh#include <sys/param.h> 98097Sjkh#include <sys/systm.h> 108097Sjkh#include <sys/malloc.h> 118097Sjkh#include <sys/mbuf.h> 128097Sjkh#include <sys/socket.h> 138097Sjkh#include <sys/socketvar.h> 148097Sjkh#include <sys/protosw.h> 158097Sjkh#include <net/if.h> 168881Srgrimes#include <net/route.h> 178881Srgrimes#include <net/netisr.h> 188097Sjkh 198097Sjkh#include <netatalk/at.h> 208097Sjkh#include <netatalk/at_var.h> 218097Sjkh#include <netatalk/ddp_var.h> 228097Sjkh#include <netatalk/ddp_pcb.h> 238097Sjkh#include <netatalk/at_extern.h> 248097Sjkh 258097Sjkhstatic struct ddpcb *ddp_ports[ ATPORT_LAST ]; 268097Sjkhstruct ddpcb *ddpcb_list = NULL; 278097Sjkh 288097Sjkhvoid 298097Sjkhat_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) 308097Sjkh{ 318097Sjkh *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT); 328097Sjkh} 338097Sjkh 348097Sjkhint 358097Sjkhat_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 368097Sjkh{ 378097Sjkh struct sockaddr_at lsat, *sat; 388097Sjkh struct at_ifaddr *aa; 398097Sjkh struct ddpcb *ddpp; 4021243Sjkh 4121243Sjkh if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */ 428097Sjkh return (EINVAL); 438097Sjkh } 448097Sjkh 458097Sjkh if (addr != NULL) { /* validate passed address */ 468097Sjkh sat = (struct sockaddr_at *)addr; 4721243Sjkh if (sat->sat_family != AF_APPLETALK) { 4821243Sjkh return (EAFNOSUPPORT); 4921243Sjkh } 5021243Sjkh 518281Sjkh if (sat->sat_addr.s_node != ATADDR_ANYNODE || 528405Sjkh sat->sat_addr.s_net != ATADDR_ANYNET) { 5312661Speter for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 548097Sjkh if ((sat->sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) && 558208Sjkh (sat->sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node)) { 568208Sjkh break; 5719385Sjkh } 5819385Sjkh } 5921765Sjkh if (!aa) { 6021276Sjkh return (EADDRNOTAVAIL); 6119385Sjkh } 6219385Sjkh } 6321766Sjkh 6419385Sjkh if (sat->sat_port != ATADDR_ANYPORT) { 658208Sjkh if (sat->sat_port < ATPORT_FIRST || 6612661Speter sat->sat_port >= ATPORT_LAST) { 6712661Speter return (EINVAL); 688549Sjkh } 6917007Sjkh if (sat->sat_port < ATPORT_RESERVED && 708208Sjkh suser(td)) { 718705Sjkh return (EACCES); 728705Sjkh } 738705Sjkh } 748705Sjkh } else { 758705Sjkh bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 768705Sjkh lsat.sat_len = sizeof(struct sockaddr_at); 778705Sjkh lsat.sat_addr.s_node = ATADDR_ANYNODE; 788705Sjkh lsat.sat_addr.s_net = ATADDR_ANYNET; 7912661Speter lsat.sat_family = AF_APPLETALK; 808208Sjkh sat = &lsat; 8112661Speter } 8215788Sjkh 8315788Sjkh if (sat->sat_addr.s_node == ATADDR_ANYNODE && 8415788Sjkh sat->sat_addr.s_net == ATADDR_ANYNET) { 8515788Sjkh if (at_ifaddr_list == NULL) { 8615788Sjkh return (EADDRNOTAVAIL); 8715788Sjkh } 888549Sjkh sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr; 8912661Speter } 9012661Speter ddp->ddp_lsat = *sat; 9112661Speter 9212661Speter /* 9312661Speter * Choose port. 9412661Speter */ 9512661Speter if (sat->sat_port == ATADDR_ANYPORT) { 9612661Speter for (sat->sat_port = ATPORT_RESERVED; 9712661Speter sat->sat_port < ATPORT_LAST; sat->sat_port++) { 9814763Sjkh if (ddp_ports[ sat->sat_port - 1 ] == NULL) { 9912661Speter break; 10016410Sjkh } 10112661Speter } 10212661Speter if (sat->sat_port == ATPORT_LAST) { 10316462Sjkh return (EADDRNOTAVAIL); 10412661Speter } 10512661Speter ddp->ddp_lsat.sat_port = sat->sat_port; 10616410Sjkh ddp_ports[ sat->sat_port - 1 ] = ddp; 10712661Speter } else { 10812661Speter for (ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; 10912661Speter ddpp = ddpp->ddp_pnext) { 11012661Speter if (ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && 11112661Speter ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node) { 11217034Sjkh break; 11312661Speter } 11412661Speter } 11512661Speter if (ddpp != NULL) { 11612661Speter return (EADDRINUSE); 11712661Speter } 11812661Speter ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; 11912661Speter ddp_ports[ sat->sat_port - 1 ] = ddp; 12016410Sjkh if (ddp->ddp_pnext) { 12112661Speter ddp->ddp_pnext->ddp_pprev = ddp; 12216327Sjkh } 12312661Speter } 12416828Sjkh 12516963Sjkh return (0); 12616366Sjkh} 12716366Sjkh 12812661Speterint 12912661Speterat_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 13012661Speter{ 13119385Sjkh struct sockaddr_at *sat = (struct sockaddr_at *)addr; 13219385Sjkh struct route *ro; 13316366Sjkh struct at_ifaddr *aa = NULL; 13412661Speter struct ifnet *ifp; 13512661Speter u_short hintnet = 0, net; 13612661Speter 13712661Speter if (sat->sat_family != AF_APPLETALK) { 13812661Speter return (EAFNOSUPPORT); 13912661Speter } 1409202Srgrimes 14112661Speter /* 1429202Srgrimes * Under phase 2, network 0 means "the network". We take "the 14312661Speter * network" to mean the network the control block is bound to. 14412661Speter * If the control block is not bound, there is an error. 1458549Sjkh */ 14616208Sjkh if (sat->sat_addr.s_net == ATADDR_ANYNET 14716294Sjkh && sat->sat_addr.s_node != ATADDR_ANYNODE) { 14816366Sjkh if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 14916208Sjkh return (EADDRNOTAVAIL); 15020247Sjkh } 15120569Sjkh hintnet = ddp->ddp_lsat.sat_addr.s_net; 15216366Sjkh } 1538208Sjkh 1548097Sjkh ro = &ddp->ddp_route; 1558549Sjkh /* 1568549Sjkh * If we've got an old route for this pcb, check that it is valid. 1578097Sjkh * If we've changed our address, we may have an old "good looking" 15815242Sjkh * route here. Attempt to detect it. 15915242Sjkh */ 16015242Sjkh if (ro->ro_rt) { 16115242Sjkh if (hintnet) { 16215242Sjkh net = hintnet; 1638097Sjkh } else { 1648097Sjkh net = sat->sat_addr.s_net; 16515242Sjkh } 1668174Sjkh aa = NULL; 1678174Sjkh if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 1688174Sjkh for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 1698174Sjkh if (aa->aa_ifp == ifp && 17015091Sjkh ntohs(net) >= ntohs(aa->aa_firstnet) && 1718097Sjkh ntohs(net) <= ntohs(aa->aa_lastnet)) { 1728097Sjkh break; 1738097Sjkh } 1748097Sjkh } 1758097Sjkh } 17620331Sjkh if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 17720331Sjkh (hintnet ? hintnet : sat->sat_addr.s_net) || 1788097Sjkh satosat(&ro->ro_dst)->sat_addr.s_node != 1798097Sjkh sat->sat_addr.s_node)) { 18021243Sjkh RTFREE(ro->ro_rt); 18121243Sjkh ro->ro_rt = NULL; 18221243Sjkh } 18321243Sjkh } 18421243Sjkh 18521243Sjkh /* 18621243Sjkh * If we've got no route for this interface, try to find one. 18721243Sjkh */ 18821243Sjkh if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 18921243Sjkh ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 19021243Sjkh ro->ro_dst.sa_family = AF_APPLETALK; 19121243Sjkh if (hintnet) { 19221243Sjkh satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 19312661Speter } else { 1948792Sjkh satosat(&ro->ro_dst)->sat_addr.s_net = sat->sat_addr.s_net; 19512661Speter } 19612661Speter satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 1978792Sjkh rtalloc(ro); 1988792Sjkh } 19920355Sjkh 20020355Sjkh /* 2018792Sjkh * Make sure any route that we have has a valid interface. 2028792Sjkh */ 2038208Sjkh aa = NULL; 2048363Sjkh if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 2058208Sjkh for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 2068208Sjkh if (aa->aa_ifp == ifp) { 2078756Sjkh break; 2088208Sjkh } 2098208Sjkh } 2108208Sjkh } 2118642Sjkh if (aa == NULL) { 2128837Sjkh return (ENETUNREACH); 2138837Sjkh } 2148363Sjkh 2158208Sjkh ddp->ddp_fsat = *sat; 2168097Sjkh if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 21717189Sjkh return (at_pcbsetaddr(ddp, NULL, td)); 21817189Sjkh } 21917189Sjkh return (0); 22017189Sjkh} 22117189Sjkh 2228208Sjkhvoid 2238208Sjkhat_pcbdisconnect(struct ddpcb *ddp) 2248208Sjkh{ 2258556Sjkh ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 2268636Sjkh ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 2278208Sjkh ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 2288549Sjkh} 2299202Srgrimes 23020315Sjkhint 2319202Srgrimesat_pcballoc(struct socket *so) 2328556Sjkh{ 2339202Srgrimes struct ddpcb *ddp; 2348208Sjkh 2358208Sjkh MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK | M_ZERO); 2368307Sjkh ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 2378307Sjkh 2388307Sjkh ddp->ddp_next = ddpcb_list; 2398307Sjkh ddp->ddp_prev = NULL; 2408307Sjkh ddp->ddp_pprev = NULL; 2418549Sjkh ddp->ddp_pnext = NULL; 2428549Sjkh if (ddpcb_list != NULL) { 2438307Sjkh ddpcb_list->ddp_prev = ddp; 2448208Sjkh } 2458336Sjkh ddpcb_list = ddp; 2468336Sjkh 2478336Sjkh ddp->ddp_socket = so; 2488307Sjkh so->so_pcb = (caddr_t)ddp; 2498307Sjkh return (0); 2508307Sjkh} 2518336Sjkh 2528307Sjkhvoid 2538307Sjkhat_pcbdetach(struct socket *so, struct ddpcb *ddp) 25412661Speter{ 25512661Speter soisdisconnected(so); 25612661Speter so->so_pcb = NULL; 25712661Speter sotryfree(so); 25812661Speter 25912661Speter /* remove ddp from ddp_ports list */ 26012661Speter if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 26112661Speter ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL) { 26212661Speter if (ddp->ddp_pprev != NULL) { 26312661Speter ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 26412661Speter } else { 26512661Speter ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; 26612661Speter } 26712661Speter if (ddp->ddp_pnext != NULL) { 26812661Speter ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 26912661Speter } 27012661Speter } 27112661Speter 27212661Speter if (ddp->ddp_route.ro_rt) { 27312661Speter RTFREE(ddp->ddp_route.ro_rt); 27412661Speter } 27512661Speter 27612661Speter if (ddp->ddp_prev) { 27712661Speter ddp->ddp_prev->ddp_next = ddp->ddp_next; 27812661Speter } else { 27912661Speter ddpcb_list = ddp->ddp_next; 28012661Speter } 28112661Speter if (ddp->ddp_next) { 28212661Speter ddp->ddp_next->ddp_prev = ddp->ddp_prev; 28312661Speter } 28414670Sjkh FREE(ddp, M_PCB); 28512661Speter} 28612661Speter 28712661Speter/* 28812661Speter * For the moment, this just find the pcb with the correct local address. 2898549Sjkh * In the future, this will actually do some real searching, so we can use 2908307Sjkh * the sender's address to do de-multiplexing on a single port to many 29112661Speter * sockets (pcbs). 2928810Sjkh */ 29312661Speterstruct ddpcb * 2948549Sjkhddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 2958810Sjkh struct at_ifaddr *aa) 2968810Sjkh{ 2978810Sjkh struct ddpcb *ddp; 2988810Sjkh 2998810Sjkh /* 3008810Sjkh * Check for bad ports. 3018810Sjkh */ 3028810Sjkh if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) { 3038208Sjkh return (NULL); 3048576Sjkh } 30515439Sjkh 3068881Srgrimes /* 3078735Sjkh * Make sure the local address matches the sent address. What about 3088576Sjkh * the interface? 3098576Sjkh */ 3108576Sjkh for (ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext) { 3118576Sjkh /* XXX should we handle 0.YY? */ 3128636Sjkh 3138576Sjkh /* XXXX.YY to socket on destination interface */ 3149202Srgrimes if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 3158576Sjkh to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 3168576Sjkh break; 3178576Sjkh } 3188576Sjkh 3199202Srgrimes /* 0.255 to socket on receiving interface */ 32017375Sjkh if (to->sat_addr.s_node == ATADDR_BCAST && (to->sat_addr.s_net == 0 || 3218576Sjkh to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 32215242Sjkh ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) { 3238660Sjkh break; 3248715Sjkh } 3258576Sjkh 32610882Speter /* XXXX.0 to socket on destination interface */ 32716412Sjkh if (to->sat_addr.s_net == aa->aa_firstnet && 3288576Sjkh to->sat_addr.s_node == 0 && 3298576Sjkh ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 3308576Sjkh ntohs(aa->aa_firstnet) && 33112661Speter ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 3328576Sjkh ntohs(aa->aa_lastnet)) { 3338677Sjkh break; 3348576Sjkh } 3358576Sjkh } 3368677Sjkh return (ddp); 3378677Sjkh} 3388810Sjkh