1 /* $NetBSD: ddp_output.c,v 1.1 1997/04/02 21:31:10 christos 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/types.h> 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/mbuf.h> 33 #include <sys/socket.h> 34 #include <sys/errno.h> 35 #include <sys/syslog.h> 36 37 #include <net/if.h> 38 #include <net/route.h> 39 #include <net/if_ether.h> 40 41 #include <netinet/in.h> 42 #undef s_net 43 44 #include <netatalk/at.h> 45 #include <netatalk/at_var.h> 46 #include <netatalk/ddp.h> 47 #include <netatalk/ddp_var.h> 48 #include <netatalk/at_extern.h> 49 50 #include <machine/stdarg.h> 51 52 int ddp_cksum = 1; 53 54 int 55 #if __STDC__ 56 ddp_output(struct mbuf *m,...) 57 #else 58 ddp_output(va_alist) 59 va_dcl 60 #endif 61 { 62 struct ddpcb *ddp; 63 struct ddpehdr *deh; 64 va_list ap; 65 66 #if __STDC__ 67 va_start(ap, m); 68 #else 69 struct mbuf *m; 70 71 va_start(ap); 72 m = va_arg(ap, struct mbuf *); 73 #endif 74 ddp = va_arg(ap, struct ddpcb *); 75 va_end(ap); 76 77 M_PREPEND(m, sizeof(struct ddpehdr), M_WAIT); 78 79 deh = mtod(m, struct ddpehdr *); 80 deh->deh_pad = 0; 81 deh->deh_hops = 0; 82 83 deh->deh_len = m->m_pkthdr.len; 84 85 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 86 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 87 deh->deh_dport = ddp->ddp_fsat.sat_port; 88 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 89 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 90 deh->deh_sport = ddp->ddp_lsat.sat_port; 91 92 /* 93 * The checksum calculation is done after all of the other bytes have 94 * been filled in. 95 */ 96 if (ddp_cksum) { 97 deh->deh_sum = at_cksum(m, sizeof(int)); 98 } else { 99 deh->deh_sum = 0; 100 } 101 deh->deh_bytes = htonl(deh->deh_bytes); 102 103 return (ddp_route(m, &ddp->ddp_route)); 104 } 105 106 u_short 107 at_cksum(m, skip) 108 struct mbuf *m; 109 int skip; 110 { 111 u_char *data, *end; 112 u_long cksum = 0; 113 114 for (; m; m = m->m_next) { 115 for (data = mtod(m, u_char *), end = data + m->m_len; 116 data < end; data++) { 117 if (skip) { 118 skip--; 119 continue; 120 } 121 cksum = (cksum + *data) << 1; 122 if (cksum & 0x00010000) { 123 cksum++; 124 } 125 cksum &= 0x0000ffff; 126 } 127 } 128 129 if (cksum == 0) { 130 cksum = 0x0000ffff; 131 } 132 return ((u_short) cksum); 133 } 134 135 int 136 ddp_route(m, ro) 137 struct mbuf *m; 138 struct route *ro; 139 { 140 struct sockaddr_at gate; 141 struct elaphdr *elh; 142 struct mbuf *m0; 143 struct at_ifaddr *aa = NULL; 144 struct ifnet *ifp = NULL; 145 u_short net; 146 147 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 148 net = satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net; 149 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 150 if (aa->aa_ifp == ifp && 151 ntohs(net) >= ntohs(aa->aa_firstnet) && 152 ntohs(net) <= ntohs(aa->aa_lastnet)) { 153 break; 154 } 155 } 156 } 157 if (aa == NULL) { 158 printf("ddp_route: oops\n"); 159 m_freem(m); 160 return (EINVAL); 161 } 162 /* 163 * There are several places in the kernel where data is added to 164 * an mbuf without ensuring that the mbuf pointer is aligned. 165 * This is bad for transition routing, since phase 1 and phase 2 166 * packets end up poorly aligned due to the three byte elap header. 167 */ 168 if (!(aa->aa_flags & AFA_PHASE2)) { 169 MGET(m0, M_WAIT, MT_HEADER); 170 if (m0 == 0) { 171 m_freem(m); 172 printf("ddp_route: no buffers\n"); 173 return (ENOBUFS); 174 } 175 m0->m_next = m; 176 /* XXX perhaps we ought to align the header? */ 177 m0->m_len = SZ_ELAPHDR; 178 m = m0; 179 180 elh = mtod(m, struct elaphdr *); 181 elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node; 182 elh->el_type = ELAP_DDPEXTEND; 183 if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= 184 ntohs(aa->aa_firstnet) && 185 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= 186 ntohs(aa->aa_lastnet)) { 187 elh->el_dnode = satosat(&ro->ro_dst)->sat_addr.s_node; 188 } else { 189 elh->el_dnode = 190 satosat(ro->ro_rt->rt_gateway)->sat_addr.s_node; 191 } 192 } 193 if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= 194 ntohs(aa->aa_firstnet) && 195 ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= 196 ntohs(aa->aa_lastnet)) { 197 gate = *satosat(&ro->ro_dst); 198 } else { 199 gate = *satosat(ro->ro_rt->rt_gateway); 200 } 201 ro->ro_rt->rt_use++; 202 203 /* XXX */ 204 return ((*ifp->if_output) (ifp, m, (struct sockaddr *) &gate, NULL)); 205 } 206