1 #define IMPLOOP 2 /* ip_output.c 1.19 81/11/24 */ 3 4 #include "../h/param.h" 5 #include "../h/mbuf.h" 6 #include "../h/mtpr.h" 7 #include "../h/socket.h" 8 #include "../h/socketvar.h" 9 #include "../net/inet.h" 10 #include "../net/inet_systm.h" 11 #include "../net/imp.h" 12 #include "../net/ip.h" 13 #include "../net/ip_var.h" 14 15 ip_output(m) 16 struct mbuf *m; 17 { 18 register struct ip *ip = mtod(m, struct ip *); 19 int len, hlen = ip->ip_hl << 2, off; 20 21 COUNT(IP_OUTPUT); 22 /* 23 * Fill in IP header. 24 */ 25 ip->ip_v = IPVERSION; 26 ip->ip_hl = hlen >> 2; 27 ip->ip_off &= IP_DF; 28 ip->ip_id = ip_id++; 29 30 /* 31 * If small enough for interface, can just send directly. 32 */ 33 if (ip->ip_len <= MTU) { 34 ip_send(ip); 35 return; 36 } 37 38 /* 39 * Too large for interface; fragment if possible. 40 * Must be able to put at least 8 bytes per fragment. 41 */ 42 if (ip->ip_off & IP_DF) 43 goto bad; 44 len = (MTU-hlen) &~ 7; 45 if (len < 8) 46 goto bad; 47 48 /* 49 * Discard IP header from logical mbuf for m_copy's sake. 50 * Loop through length of segment, make a copy of each 51 * part and output. 52 */ 53 m->m_len -= sizeof (struct ip); 54 m->m_off += sizeof (struct ip); 55 for (off = 0; off < ip->ip_len; off += len) { 56 struct mbuf *mh = m_get(0); 57 struct ip *mhip; 58 59 if (mh == 0) 60 goto bad; 61 mh->m_off = MMAXOFF - hlen; 62 mhip = mtod(mh, struct ip *); 63 *mhip = *ip; 64 if (hlen > sizeof (struct ip)) { 65 int olen = ip_optcopy(ip, mhip, off); 66 mh->m_len = sizeof (struct ip) + olen; 67 } else 68 mh->m_len = sizeof (struct ip); 69 mhip->ip_off = off; 70 if (off + len >= ip->ip_len) 71 mhip->ip_len = ip->ip_len - off; 72 else { 73 mhip->ip_len = len; 74 mhip->ip_off |= IP_MF; 75 } 76 mhip->ip_len += sizeof (struct ip); 77 mh->m_next = m_copy(m, off, len); 78 if (mh->m_next == 0) { 79 (void) m_free(mh); 80 goto bad; 81 } 82 ip_send(mhip); 83 } 84 bad: 85 m_freem(m); 86 } 87 88 /* 89 * Copy options from ip to jp. 90 * If off is 0 all options are copied 91 * otherwise copy selectively. 92 */ 93 ip_optcopy(ip, jp, off) 94 struct ip *ip, *jp; 95 int off; 96 { 97 register u_char *cp, *dp; 98 int opt, optlen, cnt; 99 100 COUNT(IP_OPTCOPY); 101 cp = (u_char *)(ip + 1); 102 dp = (u_char *)(jp + 1); 103 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 104 for (; cnt > 0; cnt -= optlen, cp += optlen) { 105 opt = cp[0]; 106 if (opt == IPOPT_EOL) 107 break; 108 if (opt == IPOPT_NOP) 109 optlen = 1; 110 else 111 optlen = cp[1]; 112 if (optlen > cnt) /* XXX */ 113 optlen = cnt; /* XXX */ 114 if (off == 0 || IPOPT_COPIED(opt)) { 115 bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 116 dp += optlen; 117 } 118 } 119 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 120 *dp++ = IPOPT_EOL; 121 return (optlen); 122 } 123 124 /* REST OF CODE HERE IS GARBAGE */ 125 126 ip_send(ip) 127 register struct ip *ip; 128 { 129 register struct mbuf *m; 130 register struct imp *l; 131 int hlen = ip->ip_hl << 2; 132 int s; 133 COUNT(IP_SEND); 134 135 m = dtom(ip); 136 l = (struct imp *)(mtod(m, caddr_t) - L1822); 137 l->i_shost = ip->ip_src.s_host; 138 l->i_dhost = ip->ip_dst.s_host; 139 l->i_type = IPTYPE; 140 ip->ip_sum = 0; 141 ip->ip_len = htons((u_short)ip->ip_len); 142 ip->ip_id = htons(ip->ip_id); 143 ip->ip_off = htons((u_short)ip->ip_off); 144 ip->ip_sum = inet_cksum(m, hlen); 145 m->m_off -= L1822; 146 m->m_len += L1822; 147 m->m_act = NULL; 148 #ifndef IMPLOOP 149 s = splimp(); 150 if (imp_stat.outq_head != NULL) 151 imp_stat.outq_tail->m_act = m; 152 else 153 imp_stat.outq_head = m; 154 imp_stat.outq_tail = m; 155 splx(s); 156 if (!imp_stat.outactive) 157 enstart(0); 158 #else 159 if (imp_stat.inq_head != NULL) 160 imp_stat.inq_tail->m_act = m; 161 else 162 imp_stat.inq_head = m; 163 imp_stat.inq_tail = m; 164 setsoftnet(); 165 #endif IMPLOOP 166 } 167 168 /* END GARBAGE */ 169