Revision b63c7f6b slirp/bootp.c

b/slirp/bootp.c
66 66
    return bc;
67 67
}
68 68

  
69
static BOOTPClient *request_addr(const struct in_addr *paddr,
70
                                 const uint8_t *macaddr)
71
{
72
    uint32_t req_addr = ntohl(paddr->s_addr);
73
    uint32_t spec_addr = ntohl(special_addr.s_addr);
74
    BOOTPClient *bc;
75

  
76
    if (req_addr >= (spec_addr | START_ADDR) &&
77
        req_addr < (spec_addr | (NB_ADDR + START_ADDR))) {
78
        bc = &bootp_clients[(req_addr & 0xff) - START_ADDR];
79
        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
80
            bc->allocated = 1;
81
            return bc;
82
        }
83
    }
84
    return NULL;
85
}
86

  
69 87
static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
70 88
{
71 89
    BOOTPClient *bc;
......
83 101
    return bc;
84 102
}
85 103

  
86
static void dhcp_decode(const uint8_t *buf, int size,
87
                        int *pmsg_type)
104
static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
105
                        const struct in_addr **preq_addr)
88 106
{
89 107
    const uint8_t *p, *p_end;
90 108
    int len, tag;
91 109

  
92 110
    *pmsg_type = 0;
111
    *preq_addr = NULL;
93 112

  
94
    p = buf;
95
    p_end = buf + size;
96
    if (size < 5)
97
        return;
113
    p = bp->bp_vend;
114
    p_end = p + DHCP_OPT_LEN;
98 115
    if (memcmp(p, rfc1533_cookie, 4) != 0)
99 116
        return;
100 117
    p += 4;
......
109 126
            if (p >= p_end)
110 127
                break;
111 128
            len = *p++;
112
            dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);
129
            dprintf("dhcp: tag=%d len=%d\n", tag, len);
113 130

  
114 131
            switch(tag) {
115 132
            case RFC2132_MSG_TYPE:
116 133
                if (len >= 1)
117 134
                    *pmsg_type = p[0];
118 135
                break;
136
            case RFC2132_REQ_ADDR:
137
                if (len >= 4)
138
                    *preq_addr = (struct in_addr *)p;
139
                break;
119 140
            default:
120 141
                break;
121 142
            }
122 143
            p += len;
123 144
        }
124 145
    }
146
    if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
147
        *preq_addr = &bp->bp_ciaddr;
148
    }
125 149
}
126 150

  
127
static void bootp_reply(struct bootp_t *bp)
151
static void bootp_reply(const struct bootp_t *bp)
128 152
{
129
    BOOTPClient *bc;
153
    BOOTPClient *bc = NULL;
130 154
    struct mbuf *m;
131 155
    struct bootp_t *rbp;
132 156
    struct sockaddr_in saddr, daddr;
133 157
    struct in_addr dns_addr;
158
    const struct in_addr *preq_addr;
134 159
    int dhcp_msg_type, val;
135 160
    uint8_t *q;
136 161

  
137 162
    /* extract exact DHCP msg type */
138
    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
139
    dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
163
    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
164
    dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
165
    if (preq_addr)
166
        dprintf(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
167
    else
168
        dprintf("\n");
140 169

  
141 170
    if (dhcp_msg_type == 0)
142 171
        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
......
155 184
    memset(rbp, 0, sizeof(struct bootp_t));
156 185

  
157 186
    if (dhcp_msg_type == DHCPDISCOVER) {
158
    new_addr:
159
        bc = get_new_addr(&daddr.sin_addr);
187
        if (preq_addr) {
188
            bc = request_addr(preq_addr, client_ethaddr);
189
            if (bc) {
190
                daddr.sin_addr = *preq_addr;
191
            }
192
        }
160 193
        if (!bc) {
161
            dprintf("no address left\n");
162
            return;
194
         new_addr:
195
            bc = get_new_addr(&daddr.sin_addr);
196
            if (!bc) {
197
                dprintf("no address left\n");
198
                return;
199
            }
163 200
        }
164 201
        memcpy(bc->macaddr, client_ethaddr, 6);
202
    } else if (preq_addr) {
203
        bc = request_addr(preq_addr, client_ethaddr);
204
        if (bc) {
205
            daddr.sin_addr = *preq_addr;
206
            memcpy(bc->macaddr, client_ethaddr, 6);
207
        } else {
208
            daddr.sin_addr.s_addr = 0;
209
        }
165 210
    } else {
166 211
        bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
167 212
        if (!bc) {
......
171 216
        }
172 217
    }
173 218

  
174
    if (bootp_filename)
175
        snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
176
                 bootp_filename);
177

  
178
    dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
179

  
180 219
    saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
181 220
    saddr.sin_port = htons(BOOTP_SERVER);
182 221

  
......
191 230
    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
192 231
    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
193 232

  
194
    daddr.sin_addr.s_addr = 0xffffffffu;
195

  
196 233
    q = rbp->bp_vend;
197 234
    memcpy(q, rfc1533_cookie, 4);
198 235
    q += 4;
199 236

  
200
    if (dhcp_msg_type == DHCPDISCOVER) {
201
        *q++ = RFC2132_MSG_TYPE;
202
        *q++ = 1;
203
        *q++ = DHCPOFFER;
204
    } else if (dhcp_msg_type == DHCPREQUEST) {
205
        *q++ = RFC2132_MSG_TYPE;
206
        *q++ = 1;
207
        *q++ = DHCPACK;
208
    }
237
    if (bc) {
238
        dprintf("%s addr=%08x\n",
239
                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
240
                ntohl(daddr.sin_addr.s_addr));
241

  
242
        if (dhcp_msg_type == DHCPDISCOVER) {
243
            *q++ = RFC2132_MSG_TYPE;
244
            *q++ = 1;
245
            *q++ = DHCPOFFER;
246
        } else /* DHCPREQUEST */ {
247
            *q++ = RFC2132_MSG_TYPE;
248
            *q++ = 1;
249
            *q++ = DHCPACK;
250
        }
251

  
252
        if (bootp_filename)
253
            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
254
                     bootp_filename);
209 255

  
210
    if (dhcp_msg_type == DHCPDISCOVER ||
211
        dhcp_msg_type == DHCPREQUEST) {
212 256
        *q++ = RFC2132_SRV_ID;
213 257
        *q++ = 4;
214 258
        memcpy(q, &saddr.sin_addr, 4);
......
247 291
            memcpy(q, slirp_hostname, val);
248 292
            q += val;
249 293
        }
294
    } else {
295
        static const char nak_msg[] = "requested address not available";
296

  
297
        dprintf("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr));
298

  
299
        *q++ = RFC2132_MSG_TYPE;
300
        *q++ = 1;
301
        *q++ = DHCPNAK;
302

  
303
        *q++ = RFC2132_MESSAGE;
304
        *q++ = sizeof(nak_msg) - 1;
305
        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
306
        q += sizeof(nak_msg) - 1;
250 307
    }
251 308
    *q++ = RFC1533_END;
252 309

  
310
    daddr.sin_addr.s_addr = 0xffffffffu;
311

  
253 312
    m->m_len = sizeof(struct bootp_t) -
254 313
        sizeof(struct ip) - sizeof(struct udphdr);
255 314
    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);

Also available in: Unified diff