ddp_output.c revision 165974
1/*- 2 * Copyright (c) 1990, 1991 Regents of The University of Michigan. 3 * All Rights Reserved. 4 * 5 * Permission to use, copy, modify, and distribute this software and 6 * its documentation for any purpose and without fee is hereby granted, 7 * provided that the above copyright notice appears in all copies and 8 * that both that copyright notice and this permission notice appear 9 * in supporting documentation, and that the name of The University 10 * of Michigan not be used in advertising or publicity pertaining to 11 * distribution of the software without specific, written prior 12 * permission. This software is supplied as is without expressed or 13 * implied warranties of any kind. 14 * 15 * Research Systems Unix Group 16 * The University of Michigan 17 * c/o Mike Clark 18 * 535 W. William Street 19 * Ann Arbor, Michigan 20 * +1-313-763-0525 21 * netatalk@itd.umich.edu 22 */ 23 24/* $FreeBSD: head/sys/netatalk/ddp_output.c 165974 2007-01-12 15:07:51Z rwatson $ */ 25 26#include "opt_mac.h" 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/mbuf.h> 31#include <sys/socket.h> 32#include <sys/socketvar.h> 33 34#include <net/if.h> 35#include <net/route.h> 36 37#undef s_net 38 39#include <netatalk/at.h> 40#include <netatalk/at_var.h> 41#include <netatalk/ddp.h> 42#include <netatalk/ddp_var.h> 43#include <netatalk/at_extern.h> 44 45#include <security/mac/mac_framework.h> 46 47int ddp_cksum = 1; 48 49int 50ddp_output(struct mbuf *m, struct socket *so) 51{ 52 struct ddpehdr *deh; 53 struct ddpcb *ddp = sotoddpcb(so); 54 55#ifdef MAC 56 SOCK_LOCK(so); 57 mac_create_mbuf_from_socket(so, m); 58 SOCK_UNLOCK(so); 59#endif 60 61 M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT); 62 if (m == NULL) 63 return (ENOBUFS); 64 65 deh = mtod(m, struct ddpehdr *); 66 deh->deh_pad = 0; 67 deh->deh_hops = 0; 68 69 deh->deh_len = m->m_pkthdr.len; 70 71 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 72 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 73 deh->deh_dport = ddp->ddp_fsat.sat_port; 74 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 75 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 76 deh->deh_sport = ddp->ddp_lsat.sat_port; 77 78 /* 79 * The checksum calculation is done after all of the other bytes have 80 * been filled in. 81 */ 82 if (ddp_cksum) 83 deh->deh_sum = at_cksum(m, sizeof(int)); 84 else 85 deh->deh_sum = 0; 86 deh->deh_bytes = htonl(deh->deh_bytes); 87 88#ifdef NETATALK_DEBUG 89 printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n", 90 ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport, 91 ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport); 92#endif 93 return (ddp_route(m, &ddp->ddp_route)); 94} 95 96u_short 97at_cksum(struct mbuf *m, int skip) 98{ 99 u_char *data, *end; 100 u_long cksum = 0; 101 102 for (; m; m = m->m_next) { 103 for (data = mtod(m, u_char *), end = data + m->m_len; 104 data < end; data++) { 105 if (skip) { 106 skip--; 107 continue; 108 } 109 cksum = (cksum + *data) << 1; 110 if (cksum & 0x00010000) 111 cksum++; 112 cksum &= 0x0000ffff; 113 } 114 } 115 116 if (cksum == 0) 117 cksum = 0x0000ffff; 118 return ((u_short)cksum); 119} 120 121int 122ddp_route(struct mbuf *m, struct route *ro) 123{ 124 struct sockaddr_at gate; 125 struct elaphdr *elh; 126 struct mbuf *m0; 127 struct at_ifaddr *aa = NULL; 128 struct ifnet *ifp = NULL; 129 u_short net; 130 131#if 0 132 /* Check for net zero, node zero ("myself") */ 133 if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET 134 && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) { 135 /* Find the loopback interface */ 136 } 137#endif 138 139 /* 140 * If we have a route, find the ifa that refers to this route. I.e 141 * the ifa used to get to the gateway. 142 */ 143 if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) || 144 ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL)) 145 rtalloc(ro); 146 if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) && 147 (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) { 148 net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); 149 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 150 if (((net == 0) || (aa->aa_ifp == ifp)) && 151 net >= ntohs(aa->aa_firstnet) && 152 net <= ntohs(aa->aa_lastnet)) 153 break; 154 } 155 } else { 156 m_freem(m); 157#ifdef NETATALK_DEBUG 158 if (ro->ro_rt == NULL) 159 printf ("ddp_route: no ro_rt.\n"); 160 else if (ro->ro_rt->rt_ifa == NULL) 161 printf ("ddp_route: no ro_rt->rt_ifa\n"); 162 else 163 printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n"); 164#endif 165 return (ENETUNREACH); 166 } 167 168 if (aa == NULL) { 169#ifdef NETATALK_DEBUG 170 printf("ddp_route: no atalk address found for %s\n", 171 ifp->if_xname); 172#endif 173 m_freem(m); 174 return (ENETUNREACH); 175 } 176 177 /* 178 * If the destination address is on a directly attached node use 179 * that, else use the official gateway. 180 */ 181 if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= 182 ntohs(aa->aa_firstnet) && 183 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= 184 ntohs(aa->aa_lastnet)) 185 gate = *satosat(&ro->ro_dst); 186 else 187 gate = *satosat(ro->ro_rt->rt_gateway); 188 189 /* 190 * There are several places in the kernel where data is added to an 191 * mbuf without ensuring that the mbuf pointer is aligned. This is 192 * bad for transition routing, since phase 1 and phase 2 packets end 193 * up poorly aligned due to the three byte elap header. 194 */ 195 if (!(aa->aa_flags & AFA_PHASE2)) { 196 MGET(m0, M_DONTWAIT, MT_DATA); 197 if (m0 == NULL) { 198 m_freem(m); 199 printf("ddp_route: no buffers\n"); 200 return (ENOBUFS); 201 } 202#ifdef MAC 203 mac_copy_mbuf(m, m0); 204#endif 205 m0->m_next = m; 206 /* XXX perhaps we ought to align the header? */ 207 m0->m_len = SZ_ELAPHDR; 208 m = m0; 209 210 elh = mtod(m, struct elaphdr *); 211 elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node; 212 elh->el_type = ELAP_DDPEXTEND; 213 elh->el_dnode = gate.sat_addr.s_node; 214 } 215 ro->ro_rt->rt_use++; 216 217#ifdef NETATALK_DEBUG 218 printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n", 219 ntohs(satosat(&aa->aa_addr)->sat_addr.s_net), 220 satosat(&aa->aa_addr)->sat_addr.s_node, 221 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net), 222 satosat(&ro->ro_dst)->sat_addr.s_node, 223 ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname); 224#endif 225 226 /* Short-circuit the output if we're sending this to ourself. */ 227 if ((satosat(&aa->aa_addr)->sat_addr.s_net == 228 satosat(&ro->ro_dst)->sat_addr.s_net) && 229 (satosat(&aa->aa_addr)->sat_addr.s_node == 230 satosat(&ro->ro_dst)->sat_addr.s_node)) 231 return (if_simloop(ifp, m, gate.sat_family, 0)); 232 233 /* XXX */ 234 return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL)); 235} 236