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: releng/10.3/sys/netatalk/ddp_output.c 263478 2014-03-21 15:15:30Z glebius $ */ 25 26#include <sys/param.h> 27#include <sys/systm.h> 28#include <sys/mbuf.h> 29#include <sys/socket.h> 30#include <sys/socketvar.h> 31 32#include <net/if.h> 33#include <net/route.h> 34 35#undef s_net 36 37#include <netatalk/at.h> 38#include <netatalk/at_var.h> 39#include <netatalk/ddp.h> 40#include <netatalk/ddp_var.h> 41#include <netatalk/at_extern.h> 42 43#include <security/mac/mac_framework.h> 44 45int ddp_cksum = 1; 46 47int 48ddp_output(struct mbuf *m, struct socket *so) 49{ 50 struct ddpehdr *deh; 51 struct ddpcb *ddp = sotoddpcb(so); 52 53#ifdef MAC 54 mac_socket_create_mbuf(so, m); 55#endif 56 57 M_PREPEND(m, sizeof(struct ddpehdr), M_NOWAIT); 58 if (m == NULL) 59 return (ENOBUFS); 60 61 deh = mtod(m, struct ddpehdr *); 62 deh->deh_pad = 0; 63 deh->deh_hops = 0; 64 65 deh->deh_len = m->m_pkthdr.len; 66 67 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 68 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 69 deh->deh_dport = ddp->ddp_fsat.sat_port; 70 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 71 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 72 deh->deh_sport = ddp->ddp_lsat.sat_port; 73 74 /* 75 * The checksum calculation is done after all of the other bytes have 76 * been filled in. 77 */ 78 if (ddp_cksum) 79 deh->deh_sum = at_cksum(m, sizeof(int)); 80 else 81 deh->deh_sum = 0; 82 deh->deh_bytes = htonl(deh->deh_bytes); 83 84#ifdef NETATALK_DEBUG 85 printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n", 86 ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport, 87 ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport); 88#endif 89 return (ddp_route(m, &ddp->ddp_route)); 90} 91 92u_short 93at_cksum(struct mbuf *m, int skip) 94{ 95 u_char *data, *end; 96 u_long cksum = 0; 97 98 for (; m; m = m->m_next) { 99 for (data = mtod(m, u_char *), end = data + m->m_len; 100 data < end; data++) { 101 if (skip) { 102 skip--; 103 continue; 104 } 105 cksum = (cksum + *data) << 1; 106 if (cksum & 0x00010000) 107 cksum++; 108 cksum &= 0x0000ffff; 109 } 110 } 111 112 if (cksum == 0) 113 cksum = 0x0000ffff; 114 return ((u_short)cksum); 115} 116 117int 118ddp_route(struct mbuf *m, struct route *ro) 119{ 120 struct sockaddr_at gate; 121 struct elaphdr *elh; 122 struct mbuf *m0; 123 struct at_ifaddr *aa = NULL; 124 struct ifnet *ifp = NULL; 125 u_short net; 126 127#if 0 128 /* Check for net zero, node zero ("myself") */ 129 if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET 130 && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) { 131 /* Find the loopback interface */ 132 } 133#endif 134 135 /* 136 * If we have a route, find the ifa that refers to this route. I.e 137 * the ifa used to get to the gateway. 138 */ 139 if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) || 140 ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL)) 141 rtalloc(ro); 142 if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) && 143 (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) { 144 net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); 145 AT_IFADDR_RLOCK(); 146 TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 147 if (((net == 0) || (aa->aa_ifp == ifp)) && 148 net >= ntohs(aa->aa_firstnet) && 149 net <= ntohs(aa->aa_lastnet)) 150 break; 151 } 152 if (aa != NULL) 153 ifa_ref(&aa->aa_ifa); 154 AT_IFADDR_RUNLOCK(); 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 * XXXRW: kern/4184 suggests that an m_pullup() of (m) should take 196 * place here to address possible alignment issues. 197 * 198 * XXXRW: This appears not to handle M_PKTHDR properly, as it doesn't 199 * move the existing header from the old packet to the new one. 200 * Posibly should call M_MOVE_PKTHDR()? This would also allow 201 * removing mac_mbuf_copy(). 202 */ 203 if (!(aa->aa_flags & AFA_PHASE2)) { 204 MGET(m0, M_NOWAIT, MT_DATA); 205 if (m0 == NULL) { 206 ifa_free(&aa->aa_ifa); 207 m_freem(m); 208 printf("ddp_route: no buffers\n"); 209 return (ENOBUFS); 210 } 211#ifdef MAC 212 mac_mbuf_copy(m, m0); 213#endif 214 m0->m_next = m; 215 /* XXX perhaps we ought to align the header? */ 216 m0->m_len = SZ_ELAPHDR; 217 m = m0; 218 219 elh = mtod(m, struct elaphdr *); 220 elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node; 221 elh->el_type = ELAP_DDPEXTEND; 222 elh->el_dnode = gate.sat_addr.s_node; 223 } 224 counter_u64_add(ro->ro_rt->rt_pksent, 1); 225 226#ifdef NETATALK_DEBUG 227 printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n", 228 ntohs(satosat(&aa->aa_addr)->sat_addr.s_net), 229 satosat(&aa->aa_addr)->sat_addr.s_node, 230 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net), 231 satosat(&ro->ro_dst)->sat_addr.s_node, 232 ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname); 233#endif 234 235 /* Short-circuit the output if we're sending this to ourself. */ 236 if ((satosat(&aa->aa_addr)->sat_addr.s_net == 237 satosat(&ro->ro_dst)->sat_addr.s_net) && 238 (satosat(&aa->aa_addr)->sat_addr.s_node == 239 satosat(&ro->ro_dst)->sat_addr.s_node)) { 240 ifa_free(&aa->aa_ifa); 241 return (if_simloop(ifp, m, gate.sat_family, 0)); 242 } 243 ifa_free(&aa->aa_ifa); 244 245 /* XXX */ 246 return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL)); 247} 248