1 /* $NetBSD: ddp_output.c,v 1.8 2004/04/25 21:14:21 matt Exp $ */ 2 3 /* 4 * Copyright (c) 1990,1991 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 20 * Research Systems Unix Group 21 * The University of Michigan 22 * c/o Wesley Craig 23 * 535 W. William Street 24 * Ann Arbor, Michigan 25 * +1-313-764-2278 26 * netatalk@umich.edu 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: ddp_output.c,v 1.8 2004/04/25 21:14:21 matt Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/mbuf.h> 35 #include <sys/socket.h> 36 #include <sys/errno.h> 37 #include <sys/syslog.h> 38 39 #include <net/if.h> 40 #include <net/route.h> 41 #include <net/if_ether.h> 42 43 #include <netinet/in.h> 44 #undef s_net 45 46 #include <netatalk/at.h> 47 #include <netatalk/at_var.h> 48 #include <netatalk/ddp.h> 49 #include <netatalk/ddp_var.h> 50 #include <netatalk/at_extern.h> 51 52 #include <machine/stdarg.h> 53 54 int ddp_cksum = 1; 55 56 int 57 ddp_output(struct mbuf *m,...) 58 { 59 struct ddpcb *ddp; 60 struct ddpehdr *deh; 61 va_list ap; 62 63 va_start(ap, m); 64 ddp = va_arg(ap, struct ddpcb *); 65 va_end(ap); 66 67 M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT); 68 if (!m) 69 return (ENOBUFS); 70 71 deh = mtod(m, struct ddpehdr *); 72 deh->deh_pad = 0; 73 deh->deh_hops = 0; 74 75 deh->deh_len = m->m_pkthdr.len; 76 77 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 78 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 79 deh->deh_dport = ddp->ddp_fsat.sat_port; 80 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 81 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 82 deh->deh_sport = ddp->ddp_lsat.sat_port; 83 84 /* 85 * The checksum calculation is done after all of the other bytes have 86 * been filled in. 87 */ 88 if (ddp_cksum) { 89 deh->deh_sum = at_cksum(m, sizeof(int)); 90 } else { 91 deh->deh_sum = 0; 92 } 93 deh->deh_bytes = htonl(deh->deh_bytes); 94 95 return (ddp_route(m, &ddp->ddp_route)); 96 } 97 98 u_short 99 at_cksum(m, skip) 100 struct mbuf *m; 101 int skip; 102 { 103 u_char *data, *end; 104 u_long cksum = 0; 105 106 for (; m; m = m->m_next) { 107 for (data = mtod(m, u_char *), end = data + m->m_len; 108 data < end; data++) { 109 if (skip) { 110 skip--; 111 continue; 112 } 113 cksum = (cksum + *data) << 1; 114 if (cksum & 0x00010000) { 115 cksum++; 116 } 117 cksum &= 0x0000ffff; 118 } 119 } 120 121 if (cksum == 0) { 122 cksum = 0x0000ffff; 123 } 124 return ((u_short) cksum); 125 } 126 127 int 128 ddp_route(m, ro) 129 struct mbuf *m; 130 struct route *ro; 131 { 132 struct sockaddr_at gate; 133 struct elaphdr *elh; 134 struct at_ifaddr *aa = NULL; 135 struct ifnet *ifp = NULL; 136 u_short net; 137 138 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 139 net = satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net; 140 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 141 if (aa->aa_ifp == ifp && 142 ntohs(net) >= ntohs(aa->aa_firstnet) && 143 ntohs(net) <= ntohs(aa->aa_lastnet)) { 144 break; 145 } 146 } 147 } 148 if (aa == NULL) { 149 printf("ddp_route: oops\n"); 150 m_freem(m); 151 return (EINVAL); 152 } 153 /* 154 * There are several places in the kernel where data is added to 155 * an mbuf without ensuring that the mbuf pointer is aligned. 156 * This is bad for transition routing, since phase 1 and phase 2 157 * packets end up poorly aligned due to the three byte elap header. 158 */ 159 if (!(aa->aa_flags & AFA_PHASE2)) { 160 M_PREPEND(m, SZ_ELAPHDR, M_DONTWAIT); 161 if (!m) 162 return (ENOBUFS); 163 164 elh = mtod(m, struct elaphdr *); 165 elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node; 166 elh->el_type = ELAP_DDPEXTEND; 167 if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= 168 ntohs(aa->aa_firstnet) && 169 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= 170 ntohs(aa->aa_lastnet)) { 171 elh->el_dnode = satosat(&ro->ro_dst)->sat_addr.s_node; 172 } else { 173 elh->el_dnode = 174 satosat(ro->ro_rt->rt_gateway)->sat_addr.s_node; 175 } 176 } 177 if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= 178 ntohs(aa->aa_firstnet) && 179 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= 180 ntohs(aa->aa_lastnet)) { 181 gate = *satosat(&ro->ro_dst); 182 } else { 183 gate = *satosat(ro->ro_rt->rt_gateway); 184 } 185 ro->ro_rt->rt_use++; 186 187 #if IFA_STATS 188 aa->aa_ifa.ifa_data.ifad_outbytes += m->m_pkthdr.len; 189 #endif 190 191 /* XXX */ 192 return ((*ifp->if_output) (ifp, m, (struct sockaddr *) &gate, NULL)); 193 } 194